Sunday, August 12, 2018

"Spooky Old Tree" - The Mouse and The Spider

Despite their vastly different appearances, the Mouse and the Spider are basically the same prop.  They use exactly the same electronic components and the difference in their code is a single digit, so I'm going to cover them together.


Build (Mouse)

The mouse is my favorite of the three props.  The image was taken directly from the book and he has nice bounce when he comes up. His eyes and mouth are coated with glow-in-the-dark paint, so when you activate him with a ultraviolet flashlight, he has a neat look.

We started with a small tagboard box that originally held trash bags.  We painted the interior black and covered it with wood-grain contact paper.  The light sensor is in the middle of the knothole, but to make a more obvious aiming point, we glued on a plastic spider.

To make the mouse, I took a picture of the book page where he appears and loaded it up into a pico-projector.  We pointed that straight down and adjusted the height so that he was blown up to the proper size and my wife traced over him.  After coloring, we mounted him on a light piece of cardboard.

Originally, I thought I would mount him using an L-shaped bracket made from a couple of craft sticks, but we first needed to determine the exact angle and length.  So, for testing purposes I just hooked a piece of wire to a servo horn, figuring we could bend and adjust it until we got the right size and then build the final mount based on that.  However, when we started testing we both loved the way he popped up and wiggled from the wire's flexing, so we just ended up using that.  He's just stuck on with some pieces of Blue-Tack.

Here's a view from the rear.

As you can see, it's a bit of a hot mess.  These are temporary props designed for light duty cycles, so we didn't try to clean things up too much.  The servo is mounted on a block of wood glued to the side and bottom of the box.  I added some wire wrapped around the servo to make sure it didn't move, since the clearance to get the mouse up and out of the hole is a bit tight.  The servo horn is attached so that the zero position is actually pointed down toward the bottom of the box.  When activated, it jumps up to 60 degrees, taking the mouse with it.  Like the Owl, the controller is an Arduino Nano powered by a cellphone USB power bank. 

Build (Spider)

The Spider is the most complicated physical build since it has several different graphic elements.  We wanted something that would fit neatly into the hallway opening, but we didn't have a big enough piece of cardboard span the distance, so we also cut our a pair of cardboard "wings" and attached one to each side vertically  with hot glue to make a nice arch that filled the space.  It's hung using a pair of grommets that slip over some finishing nails I put on the back of the hallway support beam.  It can be hung or removed in a matter of seconds.  Like the Mouse, the cardboard is covered in wood-grain contact paper.

The spiderweb is black yarn that my wife wove through holes she punched in the cardboard and then glued down.  The light sensor is in the middle of the web and a plastic spider with a jeweled back was glued on to give a bit more visual interest. 

To help fill up the space, my wife drew and cut out three bats.  Their eyes are coated with luminous paint to give an eerie look under ultraviolet light.

Here's the rear view.
The controller (another Nano) and its power bank are mounted with Blue-Tack on a shelf made from a piece of molding hot-glued to the cardboard.  A smaller shelf holds the servo, which is wired in place.

The servo horn has been extended with a five-inch piece of craft stick and positioned so that zero is straight up.  When activated, the servo rotates 90 degrees (to the right in this picture) and ends up pointing at the large white circle.  The Spider is attached to a piece of black yarn fastened to the stick that goes over a push pin behind the white circle (six inches out from the servo center), and drops down a couple of inches below the cardboard arch.

Circuitry

Here's the schematic for both the Mouse and the Spider.
As before, it consists of an Input side and an Output side.

The input uses exactly the same components as described for the Owl; an LDR and a resistor that form a voltage divider.  Refer to the post about building the Owl if you want a more detailed explanation of how it works.

The output side is even simpler.  It's just a single servo tied to power and ground, with its control wire attached to an output pin of the Nano.  There's really not much else to say about it.

Here's the breadboard diagram in case you want to mock it up.

Code

The code for the Mouse and the Spider is even simpler than that for the Owl.  The only real changes are the simplification caused by the prop only being able to do one thing, and the code required to run the servo.  This program also includes the Calibrate() routine to make sure the system has an appropriate triggerpoint at all times.  See the Owl post for more details. 

#include<Servo.h>
Servo myServo;
float triggerpoint;
long unsigned caltime;

void Calibrate(){
  triggerpoint=analogRead(A1)+60;
  caltime=millis()+10000;
}

void setup(){
  myServo.attach(9);
  myServo.write(0);
  Calibrate();
}

void loop(){
  if(analogRead(A1)>triggerpoint){
    myServo.write(60); //use 90 for the Spider
    delay(1000);
    myServo.write(0);
  }
  if(millis()>caltime){
    Calibrate();
  }
}

The grandkids love these props and they were a lot of fun to make.  If you build something like them, please let me know.

Tuesday, August 07, 2018

"Spooky Old Tree" - The Owl

Of the three props we created, the Owl, having no moving parts, was the simplest build.

Build

I used my printer's copy function to make a 1:1 scale reproduction of one of our Halloween decorations, which we then spray-glued down to a piece of cardboard.  My wife cut out around it and went over the edges with a black marker.  Once that was done, we used a pushpin to make a couple of holes in each eye for the LED leads, and another set between the feet for the photo-resistor "target".

That completed the graphics work, so all we had to do was wire it up.
The breadboards I'm using come with double-sided tape, so i just peeled of the protective coating and stuck it directly to the cardboard.  Power for the system comes from a USB battery pack.  The system draws very little power, so the pack will run it for hours.  It's just held in place with a couple of pieces of Blue-Tack.

As you can see, we didn't really make any effort at a neat, professional build.  All these projects are relatively temporary and everything is held together with tape, Blue-Tack and hot glue. All connections were simply twisted together and covered with electricians tape.

Circuitry

Here's the schematic for the Owl's circuitry.
There are two basic parts:  the output (the LED eyes) and the input (the photo-resistor).  We'll take a look at the input first, and since it's used for all the props, I'll cover it in some detail.

Input
The input is comprised of an  LDR (Light-Dependent Resistor) wired in series with a fixed 1K resistor to form a voltage divider.  One end of the LDR is connected to a 5V power pin on an Arduino Nano, and the other end is connected to the fixed resistor.  The other end of the fixed resistor goes to ground.  The center tap of the voltage divider is connected to one of the analog input pins on the Nano. (Refer to the schematic.)

Here's the way it works.  

In a simple divider like this, the voltage at the center tap will be the same as the ratio between each resistor and the total resistance in the circuit.  In other words, if we shine enough light on the LDR to lower its resistance to 1K, the total resistance in the circuit would be 2K, and the voltage at the tap would be 2.5V, since the LDR would be dropping half of the 5V source and fixed resistor will be dropping the other half.  If there is less light on the LDR (say, making it 2K) the total resistance would be 3K and the voltage at the tap would be about 1.67V, since the LDR will be dropping 2/3 of the voltage.

The analog input on the Nano converts the voltage to a proportionate value in the range of 0-1023.  So, when the voltage is 2.5V, the value would be about 512.  A 1.67 voltage would be converted to  341, and so on.

So, to make the LDR act as a trigger, we simply need to read the ambient light value and then add some value to create a triggerpoint that is a bit higher.  That way, when the LDR later receives a hit from the flashlight, it's resistance will go down, causing the input at the center tap to rise above the triggerpoint and set off the effect.  For my circuits I've been adding 60 to the ambient light value (i.e. an ambient light value of 40 would have triggerpoint of 100).

Output
The output side of things is even simpler.  Two digital output pins are used, each one connected to the anode of a standard red LED.  The cathode of the LED is connected to a 150 Ohm resistor, which is then connected to ground.  When the pins go high, current flows to the LED and lights it up.  When the pin goes low, the LEDs turn off.  There's not much else to say.


Finally, here's a breadboard diagram in case you want to build a prototype.

Code

Despite being the simplest physical build, the Owl has the most complex code of any of the props, since it can react to a light hit in one of three different ways.  Fortunately, however, the code is still pretty simple and straightforward.

Here it is:

float triggerpoint;
long unsigned caltime;

void Steady(){
  analogWrite(4,255);
  analogWrite(5,255);
  delay(1000);
  analogWrite(4,0);
  analogWrite(5,0);
} 

void Flash(){
  for(int x=0;x<5;x++){
    analogWrite(4,255);
    analogWrite(5,255);
    delay(205);
    analogWrite(4,0);
    analogWrite(5,0);
    delay(250);
  }
}

void Blink(){
  for(int x=0;x<5;x++){
    analogWrite(4,255);
    delay(250);
    analogWrite(4,0);
    analogWrite(5,255);
    delay(250);
    analogWrite(5,0);
  }
}

void Calibrate(){
  triggerpoint=analogRead(A1)+60;
  caltime=millis()+10000;
   
}
void setup(){
  Calibrate();
}

void loop(){
  if(analogRead(A1)>triggerpoint){
    int x=random(3);
    switch(x){
    case 0:
      Steady();
      break;
    case 1:
      Flash();
      break;
    case 2:
      Blink();
      break;
    }
  }

  if(millis()>caltime){
    Calibrate();
  }
}

There's nothing unusual or even very interesting about this code. It defines a couple variables, followed by four function definitions that the main program can call.  Then there's the standard setup function and the main loop, which reads the current light value and, if it is above the triggerpoint, gets a random number and uses the switch structure to determine which effect function to call..  The only thing that might require a bit of explanation is the Calibrate() function.

The hallway where these props are set up has a partially-curtained, west-facing window.  During the morning and late evening, it's rather dim, but during the afternoon, more light can come in.  Since the kids play this game at all hours of the day, there is no single triggerpoint that will work at all times.  To get around that, I created the Calibrate() function.

First, it reads the current ambient light level, adds 60 units to it, and sets that as the triggerpoint.  Then it read the Arduino's built-in millis() function.  This function returns the number of milliseconds since the board was powered on.  Once it has this, Calibrate() adds 10000 to it and saves it as the variable "caltime"  Essentially, caltime is set to 10 seconds into the future. 

Calibrate() is called in the setup() function to set an initial value.  Then, on each pass through the main loop the system checks to see if the real time returned by millis() has caught up with caltime.  If it has, Calibrate() is run again, re-evaluating and setting the triggerpoint and kicking the next update time another 10 seconds into the future.

This means that regardless of changing light conditions, the system will set an appropriate triggerpoint within 10 seconds.  Even if we turn on one of the hallway lights and trigger the effects, 10 seconds later they will go off and be reset to an appropriate working state.

There is an inherent minor flaw in this system, however.  Since the Calibrate() function runs independently of anything else, it will, inevitably, occasionally run when the target is being illuminated by the flashlight, giving a false ambient reading and setting the triggerpoint too high.  I thought of a few ways around this, but after watching the kids play the game, I decided it wasn't necessary.  They don't linger too long on any one effect and any error is corrected within 10 seconds, so they never even notice.

Wednesday, July 18, 2018

The "Spooky Old Tree Game" - Background

When my kids were little, we read to them every night; and one of their favorite books was "The Spooky Old Tree", by Stan and Jan Berenstain.

It tells the story of three little bears (one with a light, one with a stick, and one with a rope) who go out at night to explore the interior of a twisted and menacing-looking tree.  They encounter all kinds of frightening situations, including a twisty old stair, a spooky hall, and Great Sleeping Bear, who is less than thrilled about being awakened.  Naturally, they come through all this unscathed, but they do lose their tools and acquire a case of the shivers. But after a thrilling chase "up a ladder, through the floor, down a slide and out a door", they arrive "home again, safe at last".  It's a great book, with terrific illustrations.

Not surprisingly, when my older daughter had kids of her own, "The  Spooky Old Tree" became a regular feature in their nightly readings, as well.  However, her children soon discovered something interesting: Grandma and Grandpa's house (which we moved into after our kids were beyond the nightly reading stage) is perfectly set up to play a live-action version of the book.

We have a spiral staircase that leads from the kitchen to the back of an upstairs hallway which also has a straight set of steps leading down to the front door, mimicking the final slide to safety.  They would go round and round the house, with a flashlight, a foam "stick" and a length of yarn, up the twisty old stair, through the spooky hall and down the front steps to safety.  It was one of their favorite things to do when they came to visit.

The part of Great Sleeping Bear was played (somewhat reluctantly) by our white Siberian Husky, Sebastian.  He was supposed to lie at the foot of the front steps as a final obstacle but having three young kids jumping over him mad him a bit nervous, so he would just follow them around to be petted.

(Side note: Sebastian absolutely refused to go up the spiral staircase; it terrified him.  Once in a while he would go up one step, but he would start shaking and immediately turn around.  No matter.  He'd follow them to staircase and then go around to the front of the house to meet them when they came back down.  Our cat, Pumpkin, however, loved that staircase.  He'd lie for hours on one of the top steps about 12 feet in the air, looking out over the sunken family room, and survey his domain.  Of course, when the game started, he'd take off for a quieter spot and lay on the lap of one of the adults.  Sadly, both pets are gone now, but the part of Great Sleeping Bear has been taken over by a very large stuffed tiger, named Punjab, who doesn't seem to mind being climbed on.)

Those children are now a bit too old to play that game, but my younger daughter now has two children of her own, ages two and three.  They, too, read the book regularly and the older grandkids recently introduced them to the live-action game.  But there's one difference now: I'm recently retired.  And I have a new hobby.

A few months ago, I decided that I was going to need something to do with all my free time after retirement, so I began to experiment with Arduino microcontrollers and Raspberry Pi computers.  And that has led to a few "enhancements" of the Spooky Old Tree game.

Specifically I (along with my wife, who is a talented graphic artist and crafter) created three new interactive elements for the game.  A falling spider, a jumping mouse, and an owl with light-up eyes.  Each of these creatures is controlled by an Arduino Nano and their responses are triggered by shining a light on a sensor attached to them.

So, now when the kids go up into the spooky old hall, they can make things happen with their light.  You can see some video of the elements in place and in action in this video on my YouTube channel.

These "stunts" turned out to be a great hit with the kids, and in my next couple of posts I'll be providing more detail on their construction, including Fritzing diagrams, schematics, and Arduino  code in case you might like to build something like them.

They're great beginner projects because they are simple to build, easy to code, and very inexpensive.



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.