Friday, March 11, 2016

The Zenwatch and the Digital Dash

In my last post about my Slide Wear project, I mentioned that I was having trouble coming up with any kind or practical application for my Zenwatch 2 in conjunction with the Digital Dash project.  Well, I still haven't found anything practical, but I did come up with something kind of fun.

The other day when I was browsing G+ communities related to my watch, I came across a custom face that some guy had created based on his fondness for BMW motorcycles.  The logo caught my eye and got me thinking that I could probably make my own themed watchface as well.  He mentioned that he had made his in an app called "Watchmaker".  I started doing a bit of research into that app and found some truly amazing faces that people had created.  The app not only has incredible flexibility in design, but also includes a focused version of the Lua programming language; it's pretty much like Tasker for your watch.

I went to the Google Play Store and saw the app was currently 50% off.  That pretty much clinched the deal right there, but when i saw this in the feature list:

• Tasker - Full tasker integration to set watchface, change variables, run tasks

I was hooked. I had the app on my phone within minutes.

The watchfaces in this picture (shown in both their bright and dimmed states) are the first things I did with Watchmaker.
Can you guess where I'm going with this?

If you're one of the 26 people who read my post entitled "A Few More Changes" you know that I added a feature to the Digital Dash that allows it to know which vehicle it's connected to and display the appropriate logo on the tablet's main interface.  Given that I already had that code in place, it wasn't hard to add a single line that sent an AutoRemote direct message to the phone with the formal XXX=:=Face (where XXX is either BMW or JAG).

A Tasker profile on the phone recognizes this command and uses the parameter to call an appropriate task that sets my watch to full brightness and activates the proper face so that my watch is themed appropriately to the vehicle I'm driving.

I thought about adding an exit routine that would automatically revert back to my regular watchface when the Digital Dash shut down, but decided against it.  I'd rather have the watch stay themed if I stop for lunch or something during a roadtrip and shut the system down.

Instead, I used Watchmaker's "Tap" function to set up a manual reversion.  If I touch the vehicle logo on the watchface, it sends a command to run a Tasker task.  That task uses AutoWear to create a simple confirmation screen:
If I truly do want to revert to my normal watchface, I have five seconds to touch the AutoWear icon.  In that case, it runs another task that sets my display brightness back to normal and loads my regular watchface.

If, however, I don't touch the icon, the screen will dismiss itself automatically after five seconds without making any changes.  I did it this way to avoid accidentally changing face with an inadvertent touch.

The one other thing I did was extend the system's brightness control to include the watch.  Now if I dim the tablet screen for night driving, it also dims the watch as well as the phone.  Setting the tablet back to full brightness restores that setting to the other devices as well.

I realize that this is a pretty pointless enhancement, but it's also kind of fun and I'm glad I did it.

Monday, February 15, 2016

My First AutoWear Project

A few weeks ago, I picked up an Asus Zenwatch 2.  I'd been wanting to experiment with wearables, and it seemed like the best choice.  I do like having lots of information pushed to my wrist, but I really wanted to see what I could do with it that wasn't a just an off-the-shelf function.

I had bought the AutoWear Tasker plugin even before I had the watch and knew that it could do some pretty cool things, but I had trouble coming up with any kind of practical use that I could develop.  I've tried to think of some way to tie the watch into my Digital Dash project, but nothing really seemed appropriate.  So I went in a different direction.

I work in educational technology at a university and am occasionally asked to give presentations to other members of the technology community about what's happening in my area.  I decided it would be neat to be able to give those presentations directly from my phone and control them with my watch, so that became my first AutoWear project.

The port on my Galaxy S4 can put out HDMI video using a special cable that I picked up awhile back and all the presentation rooms are equipped with HDMI-capable projectors, meaning that I don't need to haul a laptop (or even a tablet) around.  My phone, my watch, and the cable are all I need.

The project, which I call "Slide Wear", is pretty simple and straight-forward, but has all the functions I need to give a normal presentation.

To start, I hook up my phone to the projector.  Then I shake my wrist to bring up AutoWear's voice control screen on the watch and say "Start Slideshow".  (Kind of geeky, I admit, but I'm usually talking to technologists who don't mind that type of thing.)

Once I say the command phrase, the phone turns on, gets forced into landscape mode, and displays the first slide in my presentation.  At the same time, it pushes a simple interface card to the watch that shows the current time, the number of the slide being displayed, and the number of slides remaining in the presentation.  The time is shown using AutoWear's built-in <time> command, so it isn't just a static display; it's an actual clock that you can use to keep your presentation on track.  The watch also gets put into a screen-always-on mode so that it doesn't go to sleep and remove the card.


The card has several functions associated with it:

Tap - A single tap anywhere on the screen advances in the presentation and displays the next slide.

Double-Tap - Double-tapping backs up and displays the previous slide, if there is one.

Long-Tap - A Long-tap brings up a new interface card that shows a scrolling list of all the slides in the presentation, complete with miniature thumbnails.  Tapping on any entry in the list causes that slide to be displayed on the screen, essentially giving you random access to any part of the presentation.

Vertical Swipe - a vertical swipe on the main interface screen causes the currently displayed slide to fade out, leaving a bank display.  This can be useful if you want to have a discussion in the middle of a presentation and don't want people to be distracted by what's on the screen.  Swiping again will cause the slide to fade back in.  Even though the screen might be blanked, the interface on the watch is still active.  That means you can do something like blank the screen and while you're talking, tap to advance to the next slide.  Then, when you swipe again, the new slide is shown, giving you a way to do a dramatic reveal.

Horizontal Swipe - Swiping the main interface screen to the left will reveal a large, circled "X".  Tapping that ends the show.  The phone is shutdown automatically and the watch is returned to normal operation.

Whenever you Tap, Double-Tap, or choose a thumbnail from the scrolling list, a new main interface card is pushed to the watch with updated information on the currently displayed slide number and the number of slides left to go.

This project was fun to put together and (I think) serves as an interesting way to show a different side of what wearables can do.


Monday, January 11, 2016

Using Android's BATTERY_CHANGED Intent in Tasker

Monitoring the status of my tablet's battery has always been part of the Digital Dash project (http://mikesgeneralblog.blogspot.com/2015/06/digital-dash-documentation-part-4.html).  And later the function was expanded to bring in the phone's battery information as well.  That part of the project has always worked pretty well and I haven't changed the code in a long time.

Now, however, I've discovered a more efficient way to gather this information and have rewritten that part of the system to take advantage of it.  It allows me to replace what had been two profiles and three tasks, with a single profile with one task attached to it.

The key is another Android Broadcast Intent, similar to the TIME_TICK intent I wrote about in my last post. (http://mikesgeneralblog.blogspot.com/2016/01/using-androids-timetick-intent-in-tasker.html)  The main difference is that where the TIME_TICK intent didn't provide any real information (it was just a synchronizing pulse), the BATTERY_CHANGED intent that we'll be using has a payload that contains a lot of info about the device's battery.

Setup to monitor this intent is nearly identical to the TIME_TICK: Create a new Event profile and choose "Intent Received" from the "System" category.  In the "Action" field enter "android.intent.action.BATTERY_CHANGED" (without quotes).  Then link to the task you want to run from this profile.

Here's what mine looks like:

Profile: V3_ BatteryTracker (472)
        Cooldown: 10
        Event: Intent Received [ Action:android.intent.action.BATTERY_CHANGED Cat:None Cat:None Scheme:* Mime Type:* ]
        State: Variable Value [ %V3_DrivingMode Set ]
Enter: V3_BattMon (483)
        A1: Variable Set [ Name:%V3_BatteryDisplay To:%level% Do Maths:Off Append:Off ] If [ %plugged = 0 ]
        A2: Variable Set [ Name:%V3_BatteryDisplay To:<u>%level%</u> Do Maths:Off Append:Off ] If [ %plugged > 0 ]


(Note that, as usual, my profile has a second context, %V3_DrivingMode Set, to keep it from firing unless my Digital Dash system is running.  You don't need that context just to monitor the battery.)

Although this is pretty simple arrangement, there are a couple of points to keep in mind if you're thinking of using this intent.  First of all, notice that I've put a 10-second cooldown on the profile to limit it's maximum firing rate.  That's because this intent will change any time one of several battery conditions changes.  It's not quite like Tasker's built-in "Battery Changed" event that only fires when the battery level changes.  The BATTERY_CHANGED intent (which Tasker is undoubtedly monitoring behind the scenes) puts out new information not only when the battery level changes, but also when the powered status changes, when the battery health changes, and when the the battery temperature changes, along with several other triggers.  

The upshot is that this intent can be updated very frequently and since I don't need or want to have that kind of granularity, I've restricted the profile to firing only once every 10 seconds, at a maximum.

The second things to take note of are the names of the Tasker variables that I'm using: %plugged and %level.  They're obviously local variables, but I didn't make up the names; they are the ones created by Tasker and based on the names provided by the intent itself.  Since there are a lot of other variables associated with this intent (and no real documentation about how they translate to Tasker) it's probably worth a few minutes to lay it out. (You can't just choose these variables from Tasker's drop-down list because they are generated dynamically at runtime.) 

The Android system documentation contains a section on the "Battery Manager" class, which provides the details of this intent.  You can find it here: http://developer.android.com/reference/android/os/BatteryManager.html

There you'll find a list of all the constants used by this class and the information they can contain.  This document is the key to sorting out the Tasker names and knowing what values to look for.

For example, let's take the %plugged variable.  As you can see in the code above, if this variable is not 0, I wrap the battery level in HTML underline tags before displaying it.  This gives me a visual indicator of the power state on the main screen.

If you look at the Battery Manager documentation, you'll see this entry:

public static final String EXTRA_PLUGGED

Added in API level 5
Extra for ACTION_BATTERY_CHANGED: integer indicating whether the device is plugged in to a power source; 0 means it is on battery, other constants are different types of power sources.
Constant Value: "plugged"
The "Constant Value" gives you the name of the Tasker variable (once you add the leading %).  It also give you a hint about what the variable might contain, but there's more information available.
If you scroll up a bit, you'll find these entries, all with the word "plugged" in their names:

public static final int BATTERY_PLUGGED_AC

Added in API level 1
Power source is an AC charger.
Constant Value: 1 (0x00000001)

public static final int BATTERY_PLUGGED_USB

Added in API level 1
Power source is a USB port.
Constant Value: 2 (0x00000002)

public static final int BATTERY_PLUGGED_WIRELESS

Added in API level 17
Power source is wireless.
Constant Value: 4 (0x00000004)
These are the other values that might be present in the %plugged variable.  Knowing that you can test for any state and act accordingly.
Likewise, you can find the names for other variables, such as the ones for health, voltage, status, and so on.  By linking the names back to the constants, you can determine what type of information can be retrieved.
Some variables, like temperature, require a little more digging, however.  If you set up the profile and flash the %temperature value, you might see something like: 223  Don't worry; it doesn't mean your battery is at the boiling point.  The intent reports the battery temperature in tenths of a degree Celsius.  So, a value of 223 means 23.3 degrees Celsius or about 72.14 degrees Fahrenheit.  So, basically room temperature.
The fact that this intent contains the battery temperature is the main reason I put the cooldown period on the profile.  When my Digital Dash project begins ramping up, the battery temperature changes rapidly and I didn't want to have the profile firing every time the temperature changed a tenth of a degree.
This single intent could be a starting point for a pretty comprehensive Tasker-based battery monitoring system.  Take a look at the documentation and see just how much information you can gather with just one profile.





Friday, January 08, 2016

Using Android's TIME_TICK intent in Tasker

I keep coming back to the TimeAndTorque task.  Not because it's all that important, but because I keep finding better ways to execute it.

It started off as a looping task (http://mikesgeneralblog.blogspot.com/2015/06/digital-dash-documentation-part-9.html) and then moved to being triggered by a Schrödinger's Profile, (http://mikesgeneralblog.blogspot.com/2015/12/schrodingers-profile.html) and now it's being driven by Android's TIME_TICK Broadcast Intent.

If you don't know what a Broadcast Intent is, you can think of it as an olde tyme town crier.  The town crier would wander the streets calling out the time and any relevant news.  The Broadcast Intent is basically the same thing; it's just a message that the Android system sends out.  Like the town crier, the system doesn't really know or care it anyone is listening; it's job is just to send out the message.

There are a lot of Broadcast Intents that the system sends out, but the one we are interested in here is called the TIME_TICK.  This message is broadcast at the top of every minute and can be used for triggering events or synchronizing information.

Other apps can broadcast intents as well.  I use one generated by PowerAmp to grab and display music track and artist information (http://mikesgeneralblog.blogspot.com/2015/06/digital-dash-documentation-part-5-music.html).

Fortunately, Tasker makes it easy to listen for these intents and harness them for our own uses. To begin listening for the TIME_TICK, create a new Event profile and choose "Intent Received" from the System category. In the Action field enter "android.intent.action.TIME_TICK" (without the quotes).  You can leave all the other fields blank.  Then, just exit the event configuration and choose the task that you want to run when this intent is received.

Here's what the code looks like for my TimeAndTorque profile and task:

Profile: V3_TimeTick (484)
        Event: Intent Received [ Action:android.intent.action.TIME_TICK Cat:None Cat:None Scheme:* Mime Type:* ]
        State: Variable Value [ %V3_DrivingMode Set ]
Enter: V3_TimeAndTorque (336)
        A1: Variable Split [ Name:%TIME Splitter:. Delete Base:Off ]
        A2: Variable Subtract [ Name:%TIME1 Value:12 Wrap Around:0 ] If [ %TIME1 > 12 ]
        A3: Variable Set [ Name:%V3_DispTime To:%TIME1:%TIME2 Do Maths:Off Append:Off ]
        A4: 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 ]
        A5: Variable Split [ Name:%obd_log Splitter:, Delete Base:Off ]
        A6: Test Element [ Scene Name:V3_LH Element:LowFuel Test:Element Visibility Store Result In:%lowdistanceindicator Continue Task After Error:On ]
        A7: If [ %obd_log6 < 60 & %lowdistanceindicator ~ false ]
        A8: Element Visibility [ Scene Name:V3_LH Element Match:LowFuel Set:True Animation Time (MS):0 ]
        A9: Say [ Text:Warning.  Range limit 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 ]
        A10: End If
        A11: If [ %obd_log6 > 60 & %lowdistanceindicator ~ true ]
        A12: Element Visibility [ Scene Name:V3_LH Element Match:LowFuel Set:False Animation Time (MS):0 ]
        A13: End If

Once every minute, the profile will become active and run the TimeAndTorque task, grabbing the time (and synchronizing my on-screen display) and running the low-fuel check (If you want more detail about the task itself, check the documentation in the first link, above.)

This method is simple, clean, and reliable.  I doubt that I'll find a better way to run this task, but who knows; I learn something new about Tasker amost every day.