Saturday 17 September 2022

Dispatchables Part 2; Computer, enhance!

As usual with software, Dispatchables v1.0.0 wasn't ideal. In fact, it didn't really capture the "Dispatchable" idea at all. What if I don't have any batteries that need charging? Wouldn't it be better to only enable the charger if there was actually charging work to be done? And for how long? We need a way to specify intent.

Here's what I'd like to be able to tell the charging system:

  • I have flat batteries in the charger
  • I want them to be charged for a total of {x} hours

To me, that looks like a perfect job for a voice-powered Google Assistant integration. Let's go!

Googlification phase 1

First, let's equip our Broadlink smart power socket item with the required ga attribute so we can control it via the openHAB Google Assistant Action.

$OPENHAB_CONF/items/powerpoints.items:
Switch SP2_Power "Battery Charger Power" { 
  channel="broadlink:sp2:34-ea-34-84-86-d1:powerOn", 
  ga="Switch" 
}

If I go through the setup steps in the Google Assistant app on my phone, I can now see "Battery Charger Power" as a controllable device. And sure enough, I can say "Hey Google, turn on the battery charger" and it all works. Great!

Now, we need to add something to record the intent to perform battery-charging when solar conditions allow, and something else that will track the number of minutes the charger has been on for, since the request was made. Note that this may well be over multiple distinct periods, for example if I ask for 6 hours of charging but there's only one hour of quality daylight left in the day, I would expect the "dispatch" to be resumed the next day once conditions were favourable again. Once we've hit the desired amount of charging, the charger should be shut off and the "intent" marker reset to OFF. Hmmm... 🤔

Less state === Better state

Well, my first optimisation on the way to solving this is to streamline the state. I absolutely do not need to hold multiple distinct but highly-related bits of information:

  • Intent to charge
  • Desired charge duration
  • Amount of time remaining in this dispatch
... that just looks like an OOP beginner's first try at a domain object. Huh. Remember Java Beans? Ugh.

We can actually do it all with one variable, the Dead Timer "pattern" (if you can call it such a thing) I learnt from an embedded developer (in C) almost 20 years ago:


  unsigned int warning_led_timer = 0;

  /* Inside main loop, being executed once per second */
  
  while (warning_led_timer > 0) {
    warning_led_timer--;
    
    /* Enable the LED, or turn it off if no longer needed */
    enable_led(WARNING_LED, warning_led_timer > 0);
  }
  
  /* ...
  * Somewhere else in the code that needs to show
  * the warning LED for 3 seconds
  */
  warning_led_timer = 3;
It encapsulates:
  • intent - anyone setting the timer to a non-zero value
  • desired duration - the initial non-zero value
  • duration remaining - whatever value the variable is currently holding; and
  • termination - when the variable hits zero
Funny that a single well-utilised variable in C (of all things) can actually achieve one of the stated goals of OO (encapsulation) isn't it? All depends on your point of view I guess. Okay. Let's step back a little bit and see what we can do here.

Objectives

What I'd like to be able to do is have this conversation with the Google Assistant:

Hey Google, charge the batteries for five hours
"Okay, I'll charge the batteries for five hours"

... with all the underlying "dispatchable" stuff I've talked about being done transparently. And for bonus points:

Hey Google, how much charge time remaining?
"There are three hours and 14 minutes remaining"

So as it turns out, the Google Assistant has an Energy Storage trait which should allow the above voice commands (or similar) to work, as it can be mapped into the openHAB Charger Device Type. It's all starting to come together - I don't have a "smart charger" (i.e. for an electric vehicle) but I think I can simulate having one using my "dead timer"!