Saturday, October 03, 2015

Physical Controls for the Digital Dash , Part 2

Well, it took a bit longer than I expected (about six months longer) but I finally got my Flic Bluetooth buttons.  And I like them; see my full review here: 
http://mikesgeneralblog.blogspot.com/2015/09/flic-bluetooth-button-review.html

I'm not quite sure what I'm going to do with all of them (I have five), but I have added one on the right-hand side of the center console in the Z3 as a music control.

I also thought about mirroring its functions to another button on the back of the steering wheel, but I've found that the car's cabin is small enough that I can reach the button while driving without even shifting position, so I've dropped that idea for the moment.

Here are the functions the button performs.

When the main screen is showing:

Short Click - Next (random) track when PowerAmp is the music source.  When Pandora is playing instead, Skip the current track.

Double Click - Replay the Previous Track (PowerAmp only; no function for Pandora).

Long Click - Display the Favorite Songs menu with a cursor used to highlight selections.

Triple Click - Toggles pause for the currently playing track.

When the Favorite Songs Menu is showing:

Short Click - Cause the music cursor to step down the list to the next entry.  If the bottom of the list is reached, the cursor wraps around back to the top of the list.

Long Click - Select the song under the cursor and have PowerAmp begin playing the track. This causes PowerAmp to display the album art for the song.  After about 5 seconds, the system returns to the main Digital Dash screen automatically.

Double Click - Cancels the Favorite Song menu and removes it from the screen without selecting any track.


If you read the first part of the physical controls documentation, you might recognize those functions as also being performed by the Bluetooth Gamepad that I've re-purposed into a sidearm controller.

In fact, I just reused the same code I wrote for that.  In order to make the Flic perform those functions, all I had to do was create the profiles that caught the various activations.  Once I had done that, I just linked to the existing tasks.  I don't think that it took me 10 minutes to get everything working.

We've taken a few drives and tried out the Flic and it has worked beautifully.  It's much easier (and safer) to click the button than it is to try hit the on-screen controls.

Monday, September 28, 2015

Flic Bluetooth Button Review

I had mentioned the flic Bluetooth buttons earlier when I was talking about adding physical controls to my Digital Dash Project (http://mikesgeneralblog.blogspot.com/2015/08/physical-controls-for-digital-dash.html).  I had been an early backer of the project on Indiegogo with the idea of using them specifically for that system.  I ended up ordering five of them, and four were delivered over the weekend. (Not sure what happened to the fifth one, but it was a late addition and may not come for a while.)

Although I won't be using them entirely as I planned, I've installed one in the car and will be experimenting with the others.  Since these are new, I thought I'd do a review.

What is a flic?

A flic is a self-contained Bluetooth button that can be connected to both Android and IOS devices to perform tasks when pressed.  The free flic software has direct integration with a number of apps and can be used with both IFTT and Tasker (Android only) to control nearly any action that you care to automate. Each flic can recognize three different activation types (Click, Double-Click, and Hold).  You can program these separately, so each button can essentially do three things.

Flics are the brainchild of a Swedish company, Shortcut Labs, who used Indiegogo to crowd fund the startup.  They reached their initial funding goal in only 30 hours and ended up with over $900,000 in pledges; 801% of their original goal.

Packaging

The flics arrived in an attractive box that has a thank you message to Indiegogo backers on the bottom.  The Flics themselves are nestled in custom foam cutouts inside the box.  There are two layers of these, and each one can hold three flics, so each box can contain six buttons.  The foam rests on a cardboard stand which has some space underneath where the optional clips are stored.  

There was also an insert directing you to the website (https://flic.io/), and a large round sticker that  you can use to show your support.

All in all, the packaging provides a nice presentation and holds the contents securely and safely.







Hardware

Each flic is slightly larger than a U.S. quarter and just over a quarter-inch thick.  The body is covered with a textured, velvety rubber embossed with the cursive version of the name from the logo.  

The back is hard plastic that comes covered with thin transparent shield.  Removing that exposes the reusable adhesive that you use to stick the flic to a non-porous surface. If the adhesive loses its stickiness, you can just clean it with water and it will regain its holding power.  I had originally intended to mount a couple of these to the back of the steering wheel in my car, but I don't think the adhesive would be up to that task; it holds the button just fine on the console, however.




The unit is entirely self-contained and powered by a button cell battery that the company claims will last up to five years.  They also claim that the battery is common item and can be easily replaced, although there are no instructions that tell you what to get or how to change it.

Flics come in black, white, green, yellow, turquoise, but I choose all black ones for my application.

The button is light, but it has very nice tactile experience and a satisfying physical "click" when pressed.

There's also a small clip that you can attach to your flic so that you can clip the button to clothing.  The company suggests you might want to do this for personal safety or to provide a way of faking a phone call to get out of a bad Tinder date.

Software

The free flic app is available in both the Apple and Google app stores and is required for operation.  It is used for pairing the button to your device, assigning actions, and changing settings.  You do need a free flic account to use the software.

The flic app is also where you start and stop the flic service.  This service must be running in order to use a flic on your device.  By default, it runs as a foreground service that starts when your device does and puts up a persistent notification.  You can use it as a background service as well, but then it is subject to be killed by memory management.  There doesn't seem to be any appreciable battery drain from this service when it isn't being used, so there's really no need to ever turn it off, but you can if you'd really like to.  

Once you've set up a flic (See Operation, below) you can access the individual functions.  There are 46 built-in app integrations and most of them give you several options to choose from.  You have free rein to set things up as you wish.  That is, one button can control up to three different apps: a single-click might turn on your Phillips Hue lights, while a double-click might send a text message, and a hold command could start a Skype call.

More sophisticated options such as IFTT and "Send Intent" allow for even greater control.  (And, of course, there's Tasker, integration, which means you can do anything you want.  Tasker is covered separately, below.)

I won't cover all the settings, but there is one that I particularly like.  By default, a flic will play pleasant sounding chimes through your device to indicate that it has been pressed.  Each action type has a different chime associated with it, so you know right away if your press has been registered.  For my Digital Dash project, this is ideal and I've left it enabled, but you can turn it off if you wish.

Finally, the app also has a help section that explains most functions, but it also has context sensitive help that walks you through most operations.

This is a nice, simple piece of software that gets the job done.  It has a clean and open look that make it easy to navigate and use.

Operation

Here are the basic steps to using a flic.

Pairing

Pairing is a simple operation.  Just open the flic app and press the button once.  The app generates a key and links the button to your device.  Once that is done, the process is automatic from then on.  Flic appears to use Bluetooth Near to detect the button and activate it.  You don't need to turn it on, wake it up, or do anything else; it's just there when you need it. Once it's in range, it's active.  Once the button is paired, you can go ahead and rename it and configure it.

Configuring

Open the app and touch the button entry on the screen.  It will then take you to another screen where you can add actions for each type of button press.  Just tap the plus sign to get a list of programs.  Click one of those and the system will guide you through the steps to get everything set up.  If you already have an action, there is a standard "three dot" menu that allows you to Remove, Edit, or Execute the action.






Use with Tasker

When I first opened the flic app and began scrolling through the list of possible integrations, I was a bit concerned because I didn't see Tasker anywhere on the list.  I was afraid it didn't make the initial release cut and that I'd need to wait before I could use it.

However, on a hunch, I went into Tasker itself, created an Event profile, and chose the Plugin category.  Sure enough, there was flic.  Installing the app also installed the Tasker plugin.

Using it is very simple.  Once you chosen flic as the Event handler, you just click the standard Tasker plugin configuration icon and you are taken to a screen where you choose the flic you are programming and which of the three activation types you are trying to capture.  Once you've done that, you link the profile to the task you want to execute.  In other words, it's just like every other Tasker plugin you've ever used.  Note that the plugin gives you a few more options, such as triggering on either the up or down portion of a press and executing a task based on the button connecting or disconnecting.




It only took me a few minutes to program the flic to act as a Next Track button for both Pandora and PowerAmp.  In the next day or two I'll be programming its other functions to provide additional music control and I'm confident that it will work as expected.


Notes and Observations

Here are a few random things about using the flic.

You can have up to eight (8) flics connected to a single device.

A flic can only be paired to one device at a time.  If you want to use it with a new mobile, you need to disconnect it from the old one first and move it to the new one by opening the flic app on the new device and pressing and holding the button for at least seven seconds.  The app will connect to the flic servers and download the button's key.  Since all this is stored in your flic account, it will also download the configuration for the button, so your programmed actions come over as well.

Response time is excellent.  When my Digital Dash project is in full swing, it really works the tablet; running turn-by-turn navigation, regularly querying web servers via Bluetooth tethering, running Torque (which is also writing it's own log file), sending and receiving AutoRemote messages, handling interactive screen overlays, playing music, and more.  Despite all that, there was never any lag between pressing the the flic and hearing the confirmation chime.  This is a very fast implementation.

There is a "Providers" screen under settings where you can disable apps or services that you don't use or configure the ones you do.

Conclusions

I like these little buttons a lot. There were some delays in getting them out, but I'm glad the company chose to delay and release a product that they were happy with rather than putting out something that wasn't quite finished.  I feel that they delivered exactly what they promised and I have no regrets about backing them.

As of the time of this review, flics are not yet shipping to the general public.  However you can pre-order them on their website (https://flic.io/) with an estimated time delivery of about eight weeks.

If you need or want a simple physical control for a project, flics are a good choice.



Wednesday, September 23, 2015

Navigation ETA Information Revisited

The display of ETA information that I talked about in my last entry about the Digital Dash project was (I thought) pretty neat, since it expanded on the philosophy of bringing as much useful information to one screen as possible.  It was also, unfortunately, very short-lived.

I got to use the feature on exactly one trip.  Then, after we returned home, I made the mistake of upgrading my tablet to Lollipop.  I figured it had been out awhile and had had a couple of point releases, so it was probably safe.  Wrong.

In the first place, it completely messed up my GPS.  After upgrading it took more than five minutes to get a lock, and even when it did, it had an error of up to 900 feet and would drop out every couple of minutes.  I was on the verge of flashing back to KitKat when I saw a post where someone mentioned the "GPS Status Test & Fix - No Ads" app as a possible solution.  Fortunately, installing it did the trick and my GPS is working normally again.  At the same time, the original "GPS Status" app that I was using wasn't working at all, so I've uninstalled that one.

The other thing that Lollipop broke was Google Maps notifications.  Well, maybe not broke, exactly, but it did change things to the point where AutoNotification can't return the ETA data any more.  The information is still there, and AN can actually respond to it, but it can't report it back to Tasker as a variable.  I've reached out to the AN developer and he's investigating, but I haven't heard anything back from him yet.

There's no guarantee, of course, that he'll be able to fix it or that it won't break again, so rather than waiting, I decided to see if there was any other way to get the information I wanted.

Turns out, there is.

I originally started out looking to see if there was an intent that I could call or monitor for this information.  I didn't find one, but I did find plenty of discussions from developers wanting to create different types of navigation apps, particularly for geocaching.  It seemed like they were always directed to check out something called the "Google Maps DistanceMatrix API".

A little more research turned up that this was a web-based service that can be called via a simple HTTP Get command.  You simply create a query string with a starting point, a destination point, and few settings and ship it off to the server.  You get back a data block (either xml or json) that contains, among other things, the distance to the target and the estimated travel time.  Just what I needed.

I played around with it a bit and came up with the code I needed.  I added a couple of lines to my V3_Compass routine to save the current latitude and longitude, added one line to the V3_StartNavigation task that saved my chosen destination to a new global variable, and added one more line to the V3_TimeAndTorque task to call my new routine so that it gets executed about every 30 seconds.

Here's that new task: 

APIQuery (113)
A1: Variable Set [ Name:%dayhalf To:AM Do Maths:Off Append:Off ] 

We start off by assuming that we will be arriving at our destination during the morning hours.  Later, we'll test this assumption and modify this variable if necessary.

A2: Variable Set [ Name:%uri To:/maps/api/distancematrix/xml?origins=%V3_Lat+%V3_Long&destinations=%V3_CurrentDestination&mode=driving&units=imperial&key=My Google Key Do Maths:Off Append:Off ] 
A3: HTTP Get [ Server:Port:https://maps.googleapis.com Path:%uri Attributes: Cookies: User Agent: Timeout:10 Mime Type: Output File: None Trust Any Certificate:Off Continue Task After Error:On ] 

This is the heart of the routine.  We use variables from other parts of the system to construct a properly-formatted query string and ship it off to the Google Maps DistanceMatrix API.  Although anyone can call the non-secure version of the API, I signed up for a free Google Developer Account and obtained a Key so that I could use a secure connection and be able to monitor performance.  This query will return a consistently formatted block of xml data containing the information I need and put it in Tasker's built-in %HTTPD variable.  Much of the rest of this task is devoted to extracting the relevant pieces.

A4: Variable Split [ Name:%HTTPD Splitter:text> Delete Base:Off ] 
A5: Variable Split [ Name:%HTTPD2 Splitter:< Delete Base:Off ] 
A6: Variable Set [ Name:%timeleft To:%HTTPD21 Do Maths:Off Append:Off ] 
A7: Variable Search Replace [ Variable:%timeleft Search:hours Ignore Case:Off Multi-Line:Off One Match Only:Off Store Matches In: Replace Matches:On Replace With:hr ] 
A8: Variable Search Replace [ Variable:%timeleft Search:mins Ignore Case:Off Multi-Line:Off One Match Only:Off Store Matches In: Replace Matches:On Replace With:min ] 

The first thing I obtain is the travel time remaining.  It's almost in the format I want, but to shorten it up a bit for display, I replace "hours" with "hr" and "mins" with "min".

A9: Variable Split [ Name:%HTTPD4 Splitter:< Delete Base:Off ] 
A10: Variable Set [ Name:%distance To:%HTTPD41 Do Maths:Off Append:Off ] 

The next piece is the distance to the destination.  This is already formatted as I want, so I just have to split it out.

A11: Variable Split [ Name:%HTTPD1 Splitter:value> Delete Base:Off ] 
A12: Variable Split [ Name:%HTTPD12 Splitter:< Delete Base:Off ] 
A13: Variable Set [ Name:%durationvalue To:%HTTPD121 Do Maths:Off Append:Off ] 

For the first two pieces of information above, I extracted the "text" versions.  That is, the information as presented in a human-readable format.  However, the xml contains "values" for this information as well: the distance is also sent as meters, and the travel time is also sent in seconds.  Because the API does not return an ETA, I need to calculate it myself, and it's easier to do by manipulating a single block of seconds rather than individual hours and minutes.  Accordingly, I grab the travel time value to use in that calculation.  

A14: Variable Split [ Name:%TIME Splitter:. Delete Base:Off ] 

This line grabs the system time from Tasker's built-in variable (which is in 24-hour format) and splits it into separate hours and minutes variables.

A15: Variable Set [ Name:%eta To:((%TIME1*3600)+(%TIME2*60))+%durationvalue Do Maths:On Append:Off ]

The line above converts the hours and minutes into a single variable that represents the seconds since midnight.  It then adds the number of seconds left to travel to that value.  The result is the ETA expressed in seconds.

A16: Variable Set [ Name:%hours To:floor(%eta/3600) Do Maths:On Append:Off ] 
A17: Variable Set [ Name:%minutes To:floor(((%eta/3600)-%hours)*60+.5) Do Maths:On Append:Off ] 

The above two lines simply convert the seconds back into hours and minutes.

A18: Variable Set [ Name:%dayhalf To:PM Do Maths:Off Append:Off ] If [ %hours > 11 & %hours < 24 ]

Now it's time to revisit that %dayhalf variable.  If %hours is greater than 11, then we will be arriving at our destination in the afternoon and need to set %dayhalf to "PM"; unless %hours is also greater than 23.  In that case, we will be arriving sometime after midnight of the next day, which is morning again so we leave %dayhalf alone.

A19: Variable Subtract [ Name:%hours Value:12 Wrap Around:0 ] If [ %hours > 12 ]
A20: Variable Subtract [ Name:%hours Value:12 Wrap Around:0 ] If [ %hours > 12 ]

I prefer the 12-hour time format, so these two lines take care of converting 24-hour time back to what I want.  The same action is used twice just in case our trip will take us past midnight.

A21: Variable Set [ Name:%V3_ETA To:%timeleft (%distance)ETA: %hours:%minutes %dayhalf Do Maths:Off Append:Off ] 

The final step is to take all the information we've derived and put it into a variable which is linked to a text box display on the main screen.

Once again, here's what that looks like:



To test this, we took the Z3 out for a little drive this weekend.  We drove over a neighboring town and when we got ready to come back, I called up my navigation panel and chose "Home" as the destination.  In about 15 seconds, the ETA display showed up on the main screen and began tracking the trip.  I watched it pretty closely and it seemed to work perfectly.  The ETA that it showed turned out to be exactly right and it counted down time and distance very accurately.

Later, I logged on to my Google Developer account and checked the stats for usage on the Distance Matrix API.  It showed 44 calls, which was exactly correct for the 22 minute trip, and every call was successful.  I also checked my cellular data usage and showed that my Bluetooth tethering app went through just under 8Mb for the day.  I have no way of knowing just how much of that was for Distance Matrix calls, but even it accounted for all of it, I'm no danger of running over my 10GB monthly allowance even if I use navigation heavily.

Update:  I tried this again today.(The weather here has been beautiful this weekend.)  Same idea, but this time it was a longer test.  On a 49-minute trip, I can see that the system handled 98 successful events and the info tracked perfectly.  My phone showed data usage of about 5MB, so it is using even less than I had previously thought.  It looks like I could run this system 24 hours per day all month and not even use half of my monthly data allowance.



Thursday, September 10, 2015

Ok, this is just weird.


I'm not sure if it's Moe's pageboy bob, Curly's barefoot tummy tickling, the bondage, or the general assault on fashion, but something about this image just gives me the creeps.

On second thought, it's the tummy tickling.  Ugh.

Tuesday, September 08, 2015

A New Digital Dash Feature

It's been a long time since I've really added a new feature to the system.  Most things I've done over the last year have been tweaks and enhancements.  But just in time for our unofficial-end-of-summer road trip last weekend I did add something new.

I had seen a tutorial showing how to use AutoInput and AutoVoice to create a system that could grab the ETA information from Google Maps and send it as a text message to someone to let them know when you would be arriving.  It looked pretty good, but, A) I really don't ever need to do that, and B) I know for a fact that voice commands are ...ineffective in a convertible with the top down cruising along at 70 with the stereo blasting.

If you're one of the 22 people who have read the first installment of this adventure "Adding Tech to a Z3 Using an Android Phone", you might remember that I ended that by saying that I really wanted a fully voice controlled interface.  Well, I actually did have that at one point.  I spent a good deal of time during the first few months of 2014 building it.  I used AutoVoice in continuous mode on my phone to create an always-listening system that could capture and interpret voice commands and send them off as AutoRemote messages to the tablet to be executed.  It was really pretty full-featured and could switch apps, start navigation, control music, search for and play specific songs, and so on.  All in all, it recognized about 30 different commands.  And it worked perfectly...in my home office, where I created it.

In the car, however, it was another matter.  The first warm spring day that I could get the car out, I backed into the driveway, fired up the system, and began testing.  Even with a good Bluetooth headset and the car not even moving, my commands were recognized about one out of every ten times when the stereo was on, even when I was speaking quite loudly.

There's a nice elderly lady in our neighborhood who still brings me cookies once in a while because she feels sorry for me.  She had seen me sitting in the car yelling "Torque!", "Maps!", "Torque!", "Damn it!", and became convinced that I have Tourette Syndrome.  Needless to say, I abandoned voice control in favor of what I'm using now.

Anyway, although I didn't take away anything directly from that tutorial, it got me wondering if there was some other way to catch and use the ETA information. Turns out, there is.

In addition to displaying that info on its own screen, Maps also creates a notification that contains essentially the same thing.  By using AutoNotification I'm able to capture it, massage it into a more compact format, and display it on the main screen.  Like this:



Even though this might not seem like that big of a deal, it's very useful for me since 90% of the time when I flip over to the Maps app, it's to see this information.

You see, I live in one of the fly-over states and most of my road trips include directions like: "...Continue straight for 87 miles, then turn right and continue straight for 64 miles...". I don't really need to check those directions very often.  About the only time I actually use the turn-by-turn information is when I'm skirting the edge of a city.  (Defined as any place with a population of more than 5000.)

So having this on-screen all the time keeps me from switching apps as often, which is safer and doesn't annoy my wife as much.

I'm not necessarily thrilled with how it looks at the moment.  It seems a bit crowded and messy, but I think if I were to have it switch places with the connection icons, it would look better.

Something to do this winter while I'm eating cookies.

Tuesday, August 18, 2015

Controlling Bluetooth Buttons

Since I mentioned in the last post that I was intercepting and modifying some of the buttons on the Bluetooth gamepad to respond to two different types of input, I thought I'd share the Tasker code that I'm using to do that.

Actually, most of the work is done by the AutoInput plugin, which is one of the AutoApps series that extends and simplifies Tasker itself.

Just as I did for the Digital Dash, I'll be using the gamepad as the input source.  Just to recap, here are the functions it sends by default:
 I'll just be capturing the "Media Fast Forward" button and giving it two functions: a normal click, and a long press.  Just for completeness though, I'm suppressing all the gamepad buttons.

The first thing to do is to run the AutoInput Key Suppress command:

KeySuppress (473)
A1: AutoInput Modes [ Configuration:Key Suppress: Enable
Keys: Enter
Back
Media Fast Forward
Volume Up
Volume Down
Media Next
Media Previous
Media Rewind Package:com.joaomgcd.autoinput Name:AutoInput Modes Timeout (Seconds):2 ] 

This function traps the specified key inputs and prevents them from being delivered to the OS.  If you don't do that, you can still make the keys do whatever you want, but they'll also be passed along and perform their original function as well.  That might be useful for some situations, like having Tasker's "Say" function confirm what key was pressed while still letting it through, but I want to completely change the key functions, so I'm going to suppress them.

In my Digital Dash project, the Key Suppress command is part of the Startup task, but you can just run it manually if you want to experiment, since it's persistent and will stay in force until explicitly cancelled. 

Now we need a couple of profiles and tasks.

Profile: FFLong (107)
Priority: 40
Event: AutoInput Key [ Configuration:Keys: Media Fast Forward
Key Action: Key Down ]
Enter: LongClick (106)
A1: Profile Status [ Name:FFShort Set:On ] 
A2: Wait [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ] 
A3: Profile Status [ Name:FFShort Set:Off ] 
A4: Flash [ Text:Long Click Long:On ] 

This is the profile that determines what happens when the key is pressed and held.

The first thing it does is enable the second profile (which we'll get to in a minute).  It then waits for one second and then deactivates the second profile.  After that, it simply performs the function you want.  Here's it's a simple Flash Alert, but it can be any set of Tasker actions.

The second profile determines what happens when you click and release the key before the one second Wait expires:

Profile: FFShort (108)
Priority: 45
Event: AutoInput Key [ Configuration:Keys: Media Fast Forward
Key Action: Key Up ]
Enter: ShortClick (103)
A1: Stop [ With Error:Off Task:LongClick ] 
A2: Flash [ Text:Short Click Long:On ] 

Note that this profile is activated when the key is RELEASED and the task it launches is at a higher priority than the one for "FFLong".

Because this task is at a higher priority, it can interrupt the FFLong task and stop it during the Wait period.   Beyond that time, the FFShort profile will become inactive and won't fire at all.

If it does activate it simply shuts down the FFLong task and executes its own action, again, in this case, a simple Flash Alert.

That's all there is to it.

A couple of things to note, however.  Firstly, you have to name a profile before you can set its status.  So, "FFShort" needed a name.  "FFLong" doesn't (technically) but it's always a good idea to name your profiles.  

Secondly, the actual status of "FFShort" doesn't matter after the key press has been handled.  If the "FFLong" task is the one that gets executed, the profile will be turned off.  However, if the "FFShort" task is called, the profile remains enabled.  But since it responds to a key up state and you can't have that without a corresponding key down event first, the profile can never trigger until "FFLong" is called first.

Of course, once you are done using the buttons, you need to stop capturing them.  This is done with the Key Suppress command again, but this time the configuration is set to disable:

KeyAllow (474)
A1: AutoInput Modes [ Configuration:Key Suppress: Disable Package:com.joaomgcd.autoinput Name:AutoInput Modes Timeout (Seconds):2 ]

Again, in this case, this is just a standalone task that you can run manually.  In my dash project that command is part of the Shutdown task.


Monday, August 17, 2015

More Tweaks and Tuning

Before and after our last roadtrip, I made a few changes to the Digital Dash system.  Nothing major, but I did address a few long-standing issues that have proven to be worth the effort to correct.

The first has to do with the Destinations panel.  If you've read some the previous entries, you know this is a pop-up panel that holds five preset destinations; all I have to do is pick one and the system starts navigating to it.

Normally it has an entry for Home, three places that we visit fairly often, and a slot for an ad hoc destination that's just called "Current".  Usually, I just edit the address for that last entry and don't bother changing the on-screen name.

However, for our last trip I needed to change everything except for the Home designation since we were going to be visiting several places in an unfamiliar area.  Changing the addresses was easy; all I needed to do was change the entry list in the "%V3_Destinations" variable.  However, to get the right names on the screen, I was going to have to manually edit the pop-up scene.  I wasn't too wild about doing that because I was just going to have to change it back after the trip and there's always the chance that I'd end up slightly moving the position of one of the elements.  And since the process that chooses the navigation destination relies on precise screen positioning, a small change would stop it from working.

So instead, I made a new variable in the Startup task: "%V3_DestinationNames" and turned it into an array.  It, of course, holds the onscreen names that I want to have displayed.  I also added a small loop in the Startup task that reads that array and uses Tasker's "Element Text" to change the names in the scene.  That way there's no risk of accidentally moving something and it makes future changes much easier to do.

I actually have two copies of both "%V3_Destinations" and "%V3_DestinationNames" in the Startup Task.  One holds my normal, default values and the other can be used for future trips.  I just disable the pair that I'm not using.

The second thing I did was go through and re-balance all the task priorities.  I admit I hadn't paid much attention to this before, even though I should have.  Before I did this, I would get occasions where the interface would be slow to respond; I'd hit the Next Track button and nothing would happen, so I'd hit it again and all of sudden it would jump two tracks.  Or it would take several seconds to pause the music.

To fix that, I went into every profile that dealt with user interaction and bumped the launched task priority up to around 40.  I also tweaked other tasks while I was at it, and the result is that the system is now very responsive to user input and there's never any confusion about whether the screen (or Bluetooth controller) tap has registered.

The last thing I did on the tablet was to fix an annoyance that has been around for quite some  time.  Every once in awhile the overlay scenes on Torque would "blink"; disappearing for a second before they would pop back on.  When this first started happening, long ago, I did a little investigation, but somehow came to the conclusion that it was something inherent in either Tasker or the Android OS.  After all, I was displaying four overlays, each with many elements and possible interactions and I figured I was just pushing the limits of the systems and it was something that I would have to live with.  And since was an annoyance rather than an actual problem, I just let it go.

But when I began to look at it a little deeper, I realized that it was actually my profile and task that was removing the displays.  I still don't really know why this is happening; the profile is triggered by Torque being in the foreground and none of my code is changing that condition when the problem manifests itself.  For some reason, Torque just loses focus for a fraction of a second from time to time, which was triggering the profile's exit task and removing the display, only to put it right back on again.

Fortunately, the fix was pretty simple.  I modified the exit task for the profile to start with a one-second Wait.  After that, it checks Tasker's built-in %PACTIVE variable to see if the profile is active.  If it is, the exit task is stopped.  This de-bouncing code is enough to stop the problem.  Since I put it in, the display has been rock-solid.

The final change I made was on the phone, rather than the tablet.  Again, if you read some of the earlier posts, you'll know that every couple of minutes the phone is supposed to read the temperature from its sensor and send it to the tablet via an AutoRemote message for display on the main screen.

The problem is that this has never worked quite right.  Messages wouldn't get sent consistently, or they'd get sent but never arrive, or a bunch of them would show up at once.  I ran lots of tests and tried lots of things, but I could never quite figure out the problem.

As it turns out, there were two issues:  One was that AutoRemote normally sends its messages through the web via Google.  That service seems to be a bit buggy and unreliable, causing lost and delayed messages.  The fix was to switch to using AutoRemote's Direct Messaging option.  Now, messages go from the phone to the tablet...uh, directly...using the Bluetooth tether between the two devices.

 That took care of messages the were sent but not received, but the system on the phone still wasn't sending messages consistently.  This time, the problem was of my own making.

When I decided to mount the phone in the car as well as the tablet, I did so because I wanted to have Waze constantly running and visible because I like its road hazard reporting.  However, I don't like its on-screen speedometer; it just too small to be useful.  So, I reused some code that I had originally developed to put a speedometer on Google Maps, without really paying much attention.

I had used a simple task that grabbed Tasker's %LOCSPD variable, converted it from meters-per-second to miles-per-hour and fed that to an onscreen variable.  The task would then wait before looping back and repeating.  The problem was that it was "waiting" exactly one millisecond.  My speed was being reported with great granularity, but that loop was blocking the low-level task I had set up to send the temperature messages.

Rather than rewrite this routine to use AutoLocation, I simply modified it by adding the temperature sending code to the loop.  Now, it has a loop counter that is incremented every time the speed is updated and after so many times, will send the temperature and reset the counter so it can start incrementing again.  I also changed the wait to 250 milliseconds, which is much more reasonable.  The result is that I now get consistent temperature updates about once per minute on the tablet.  It finally works the way I wanted.

None of these changes were very big, but they have made the system more stable, responsive, and user-friendly.

Thursday, August 06, 2015

Physical Controls for the Digital Dash



I know, of course, that it's somewhat dangerous (not to mention illegal in many places) to operate a touch screen device while driving.  That's why I've wanted to add physical controls to my system for quite a while.  In fact, the latest version of the system was built with that in mind, with a structure that was prepped for it.

I had initially become pretty excited about the Flic Bluetooth button when I heard about it last year on the Tasker Google Group.  I backed their project on Indiegogo and ended up ordering five of them.  I've become a bit disillusioned, though.  They were supposed to deliver in March, and it's now August and I still don't have them.

I had intended, originally, to mount four in the car: two on the center console for the passenger, and two on the back of the steering wheel (that mirrored the console buttons) for the driver.  I figured that with two buttons, I could control just about everything in my system.  I may still mount one on the console for passenger music control, but I've found something better for complete driver control.


This is a "Compact Bluetooth Gamepad" that I bought from GearBest.  It only costs about $7, has a rechargeable  battery, and incorporates nine buttons (including a four-way joystick) that send standard Android keycodes to your device.  And with Tasker and the AutoInput plugin, I can intercept those codes and make them do anything I want.  And what I want is to control the digital dash system...completely.

Here are the keycodes it sends in it's default mode.  There are at least two other modes that change the mapping, but I haven't messed with those.


I've remapped all the buttons except for the Play/Pause control; that one I use as is.  In addition, each of the joystick buttons uses two linked Tasker profiles to allow it to recognize two different types of activation: a short click, or a longer, held one. (I could do that with the buttons as well, but haven't needed to...yet.)



This picture shows how I've got it mounted in the car.  An inverted "U-shaped" piece of plastic with a couple of self-adhesive rubber feet to hold it in place and a couple of Velcro dots to hold the controller to it.  It gives me a very nice little sidearm controller that's easy to reach and use.  In the descriptions that follow, "up" is toward the front of the car.

Here's a list of functions that each button can perform, broken down by screen:

On the Main Screen

Joystick Up Click - Launch Google Maps
Joystick Up Held - Show the list of pre-programmed destinations
Joystick Down Click - Launch the MyRadar weather app
Joystick Down Held - Launch the Weather Channel app
Joystick Left Click - Replay previous song
Joystick Left Held - Show the list of favorite songs
Joystick Right Click - Skip to the next (random) song
Joystick Right Held - Launch PowerAmp if the music source variable is currently set to "Local".  If it's set to "Net", launch Pandora, instead
Volume Down Click - Launch Pandora and start playing my pre-existing 60's music station
Volume Up Click - Launch Pandora and start playing a mix of my pre-existing stations.
Back Key Click - Launch Pandora and start playing my pre-existing 70's Rock station
Enter Key Click - Launch GasBuddy

On Google Maps

Joystick Up Click - Return to Main Screen
Joystick Up Held - Toggle Voice Navigation on and off (uses AutoInput to press on-screen controls)
Joystick Down Click - Download A-GPS data using the GPSStatus app. (uses AutoInput to press on-screen controls.  Automatically returns to the main screen.)

On Radar or Weather Apps

Joystick Click Down - Return to Main Screen

On GasBuddy

Enter Key Click - Return to Main Screen

When the Destinations List is Showing

Joystick Down Click - Step the cursor down to highlight the next destination in the list.  If you try to step below the last one, it wraps around back to the top of the list.

Joystick Up Click - Step the cursor up to highlight the previous destination in the list.  If you try to step above the first one, it wraps around back to the bottom of the list.

Joystick Left Click - Cancel destination selection and remove the on-screen list

Joystick Right Click - Select a destination and send it to Google Maps.  Navigation starts automatically.

When the Favorite Songs List is Showing

Joystick Down Click - Step the cursor down to highlight the next song in the list.  If you try to step below the last one, it wraps around back to the top of the list.

Joystick Up Click - Step the cursor up to highlight the previous song in the list.  If you try to step above the first one, it wraps around back to the bottom of the list.

Joystick Left Click - Cancel song selection and remove the on-screen list

Joystick Right Click - Select a song and send it as a search to PowerAmp.  The song will start playing and then the system returns automatically to the main screen.

The Play/Pause key executes the Play/Pause function regardless of what screen is showing.

It seems a bit complicated when you're just reading through the list, but the operation is really pretty intuitive (at least to me.)  That's the beauty of designing your own system; you can have something that makes perfect sense to you, even if others don't see it the same way.

If you've read some of my previous entries, you might notice that there are a few functions that aren't accounted for.  They're used so rarely that I didn't feel it was necessary to add those in, but if I get bored, or ambitious I might do it anyway.  The missing functions are: launch ScannerRadio, set the PowerAmp EQ, toggle Auto-Brightness, and launch the fireplace app.

 I just got back from a long weekend mini-vacation where we put about 700 miles on the car and the system worked very well.  So far, I'm very pleased with how this part of the project has turned out.

Friday, June 19, 2015

Digital Dash Documentation, Part 9: Reading Time and Torque Data

This is a bit of a "rogue" task.  Where the other tasks in the system are triggered by some sort of external stimuli (e.g. a button is tapped, a new song comes on, app focus changes) this one is kicked off by the startup sequence, goes off into its own little world, and is killed when the system shuts down.  It spends most of its time sleeping, only to wake up every 25 seconds or so to see what's going on.  Its purpose is to update the time display on the main screen and let me know when it's time to start thinking about getting gas.


V3_TimeAndTorque (336)
A1: Variable Set [ Name:%mytime To:%TIME Do Maths:Off Append:Off ] 
A2: Variable Split [ Name:%mytime Splitter:. Delete Base:Off ] 
A3: Variable Set [ Name:%mytime1 To:%mytime1-12 Do Maths:On Append:Off ] If [ %mytime1 > 12 ]
A4: Variable Set [ Name:%mytime To:%mytime1:%mytime2 Do Maths:Off Append:Off ] 
A5: Variable Set [ Name:%V3_DispTime To:%mytime Do Maths:Off Append:Off ] 

It would have been much easier to just link Tasker's built in %TIME variable to an on-screen display but, unfortunately, it only reports out in 24-hour time; and I wanted a 12-hour display, so I need to manipulate the data a bit.  

It's pretty straight forward: The %TIME variable is copied into a local variable (%mytime) and split into variables holding the hour (%mytime1) and the minutes (%mytime2).  We then subtract 12 from the hour, but only if it's greater than 12.  So, for example, 10 is left alone but 15 has 12 subtracted from it to yield 3.

We then concatenate the hours, a ":", and the minutes back into the %mytime variable and set the global variable %DispTime equal to it.  %DispTime, of course, is the source for a text element on the main display.

The Z3's analog gas gauge has the disturbing habit of going along saying, "Yup, Everything's fine; plenty of gas.  No problem here, Chief.  We can go a long way yet".  Until it gets down to about a third of a tank.  Then it starts sucking it down like a thirsty drunk on Dollar Pitcher Night.  That's one reason there are three displays dealing with gas mileage on the main screen.  The following part of the task is designed to wake me up if I'm not paying attention and let me know that it's time to start looking for some 91-octane go-juice.

A6: Run Shell [ Command:/data/data/burrows.apps.busybox/app_busybox/tail -1 /storage/emulated/0/torqueLogs/trackLog.csv Timeout (Seconds):0 Use Root:Off Store Output In:%obd_log Store Errors In: Store Result In: Continue Task After Error:On ] 

Every five seconds Torque adds a new line to its log file with several pieces of information, including the "Estimated Distance To Empty" (EDE) that it calculates using the current MPG and the vehicle profile I set up.  Since I only want to know the latest information, I use the "tail" command, which simply reads in the last line of the file (tracklog.csv) and stores it in a local variable (%obd_log).

A7: Variable Split [ Name:%obd_log Splitter:, Delete Base:Off ] 

I then split the base variable so that I can access the one piece of data that I really want.

A8: Test Element [ Scene Name:V3_LH Element:LowFuel Test:Element Visibility Store Result In:%lowdistanceindicator Continue Task After Error:On ] 

The line above tests the LowFuel element on the V3_LH scene to see if it is visible or not and stores the result in %lowdistanceindicator.

A9: If [ %obd_log6 < 60 & %lowdistanceindicator ~ false ]

The next thing we do is test to see if the indicator is still invisible and the EDE (stored in the 6th position of the data array) has fallen below my set point; in this case, 60 miles.

A10: Element Visibility [ Scene Name:V3_LH Element Match:LowFuel Set:True Animation Time (MS):0 ] 

If both of those conditions are true, we make the LowFuel element (a translucent red square) be visible over the Distance To Empty element on the screen.

A11: Say [ Text:Warning. Range limit is under sixty miles. Engine:Voice:default:default Stream:3 Pitch:5 Speed:4 Respect Audio Focus:On Network:Off Continue Task Immediately:Off Continue Task After Error:On ] 
A12: End If 

We also give a verbal warning before ending the test started back in line 9.  The reason for doing it this way is that I want a verbal warning when low range point is first reached, but after that I only want the indicator to stay lit.  Once the conditions in the test have been met for the first time, the second part of the test will fail since the indicator is already on; so no repeated verbal warnings.  If I just tested the EDE, the system would be yelling at me about every 30 seconds.

A13: If [ %obd_log6 > 60 & %lowdistanceindicator ~ true ]
A14: Element Visibility [ Scene Name:V3_LH Element Match:LowFuel Set:False Animation Time (MS):0 ] 
A15: End If 

This routine clears the visual indicator when the EDE rises above 60 again.  That is, when I fill up and tell Torque that I have plenty of gas again.

A16: Wait [ MS:0 Seconds:25 Minutes:0 Hours:0 Days:0 ] 
A17: Goto [ Type:Action Number Number:1 Label: ] 

The task finishes by going back to sleep again.  When it wakes up, it starts all over at line one.  Doing it this way means that the clock isn't accurate to the second, but it's close enough for what I want.

Digital Dash Documentation, Part 8: Torque Overlay Handling

This is the last profile (at least on the tablet) that I need to describe.  This one simply handles showing the four main overlay scenes when Torque is in the foreground, and removing them when it loses focus.

Profile: V3_TorqueOverlay (342)
Application: Torque
State: Variable Value [ %V3_DrivingMode Set ]
Enter: V3_ShowMainOverlay (340)

A very simple profile.  Whenever we are in the system (i.e. %V3_DrivingMode is SET) and Torque comes to the foreground, we show the four overlay screens.  When Torque loses focus (i.e. we switch to another app) the scenes are hidden. 

A1: Show Scene [ Name:V3_TopMain Display As:Overlay, Blocking Horizontal Position:100 Vertical Position:0 Animation:System Show Exit Button:Off Continue Task Immediately:On ]
A2: Show Scene [ Name:V3_LH Display As:Overlay, Blocking Horizontal Position:4 Vertical Position:196 Animation:System Show Exit Button:Off Continue Task Immediately:On ]
A3: Show Scene [ Name:V3_Bottom Display As:Overlay, Blocking Horizontal Position:100 Vertical Position:200 Animation:System Show Exit Button:Off Continue Task Immediately:On ]
A4: Show Scene [ Name:V3_RH Display As:Overlay, Blocking Horizontal Position:200 Vertical Position:200 Animation:System Show Exit Button:Off Continue Task Immediately:On ]

The entry task just shows the previously created scenes.  All of them are blocking overlays because they all contain elements that the user can interact with.

Exit: V3_HideMainOverlay (341)
A1: Hide Scene [ Name:V3_TopMain Animation:None Continue Task After Error:On ]
A2: Hide Scene [ Name:V3_TopSources Animation:None Continue Task After Error:On ]
A3: Hide Scene [ Name:V3_TopEQ Animation:None Continue Task After Error:On ]
A4: Hide Scene [ Name:V3_CancelOverlays Animation:None Continue Task After Error:On ]
A5: Hide Scene [ Name:V3_LH Animation:None Continue Task After Error:On ]
A6: Hide Scene [ Name:V3_Bottom Animation:None Continue Task After Error:On ]
A7: Hide Scene [ Name:V3_FavoriteSongs Animation:None Continue Task After Error:On ]
A8: Hide Scene [ Name:V3_Destinations Animation:None Continue Task After Error:On ]
A9: Hide Scene [ Name:V3_RH Animation:None Continue Task After Error:On ] 

For the exit task, I took what my father would call the "brute force and awkwardness" approach.  That is, I don't check to see what scenes might be showing and selectively hide them; instead, I just hide any scene that could possibly be showing.  The "Continue Task After Error" lets that happen.

Digital Dash Documentation, Part 7: Incoming Phone Commands

When the digital dash system starts up, it makes a Bluetooth tethering connection to my phone.  There is a Tasker profile on the phone that listens for this connection to be made, and when it sees it, it runs a startup task of its own.  The details of that will be covered in a later part of the documentation, but the only thing we're interested in now is the fact that part of that sequence launches a low-priority looping task that repeats about every three minutes.

What that task does is to read the current ambient temperature from the phone's sensor (via Tasker's built-in %TEMP variable) convert it to Fahrenheit, append the degree symbol, and send it off to the tablet via an AutoRemote message.


Profile: V3_IncomingCommands (368)
State: AutoRemote [ Configuration:All Messages ]
State: Variable Value [ %V3_DrivingMode Set ]
Enter: V3_HandlePhoneCommands (369)

This profile, running on the tablet, simply listens for any incoming AutoRemote message.  When it sees one, it fires off it's entry task.  Since I'm really only sending one message, I'm not making use of any of AutoRemote's filtering capabilities; I just look for any message and let the entry task figure out what to do with it.

A1: Variable Set [ Name:%V3_CurrentTemp To:%arpar() Do Maths:Off Append:Off ] If [ %arcomm ~ Temp ]

When it comes in, the AutoRemote message looks like this: "the temperature"=:=Temp (Where "the temperature" is the current ambient temperature, including the degree symbol.)  In AutoRemote terms, anything to the left of the =:=  is called the parameter(s) and is contained in the %arpar() local variable.  LIkewise, anything to the right of the symbol string is called the command and is found in the %arcomm local variable.  All this task does is check to make sure that this is a "TEMP" command and, if it is, sets the %V3_CurrentTemp global variable equal to the parameter payload.  %V3_CurrentTemp is used as the source for the temperature text element on the V3_RH scene shown on the main display. 

Although I'm only sending one type of message at this time, the system is easily expandable if I want to add additional types.