Saturday, 30 March 2024
Tesla Model 3 (2022) standard range RWD review
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
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
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"!
Sunday, 28 August 2022
"Dispatchables" with OpenHAB and PowerPal
I read a while back about the concept of "dispatchable" energy sources - namely, ones that can be brought on- or off-stream at virtually no notice, at a desired output level. As an enthusiastic solar-power owner/operator, the idea of tuning my energy consumption to also be dispatchable, suited to the output of my rooftop solar cells, makes a lot of sense.
My first tiny exploration into this field will use OpenHAB to automate "dispatch" of a non-time-critical task: recharging some batteries, to a time that makes best use of the "free" solar energy coming from my roof.
Just to be clear, I'm referring to charging domestic AA and AAA batteries here; I'm not trying to run a PowerWall!
OMG PPRO REST API FTW
To get the necessary insight into whether my house is running "in surplus" power, I'm using my PowerPal PRO which offers a simple RESTful API. If you send off a GET with suitable credentials to
https://readings.powerpal.net/api/v1/device/{{SERIAL_NUMBER}}you get something like:
{ "serial_number": "000abcde", "total_meter_reading_count": 443693, "pruned_meter_reading_count": 0, "total_watt_hours": 4246285, "total_cost": 1380.9539, "first_reading_timestamp": 1627948800, "last_reading_timestamp": 1659495300, "last_reading_watt_hours": 0, "last_reading_cost": 0.00062791666, "available_days": 364, "first_archived_date": "2021-04-13", "last_archived_date": "2022-08-02" }
It's pretty straightforward to translate that into an openHAB Thing definition using the HTTP Binding that will get us the current watt-hours reading every 60 seconds (which is how often the device phones home)
$OPENHAB_CONF/things/powerpal.thing:
Thing http:url:powerpal "PowerPal" [ baseURL="https://readings.powerpal.net", headers="Authorization=MyPowerPalAPIKey", "Accept=application/json", timeout=2000, bufferSize=1024, refresh=60] { Channels: Type number : powerUsage "Newest Power Usage" [ stateExtension="/api/v1/device/000abcde", stateTransformation="JSONPATH:$.last_reading_watt_hours", mode="READONLY" ] }You can get MyPowerPalAPIKey as used above, by opening the PowerPal mobile app and going to Guidance -> Generate an API Key.
That's it for the "physical" (Thing) layer. Lets move up the stack and define an Item that we can work with in a Rule.
$OPENHAB_CONF/items/powerpal.items:
Number:Power currentPowerUsage "Current Power Usage [%d W]" {channel="http:url:powerpal:powerUsage"}
... and if you're me, nothing will happen, and you will curse openHAB and its constant changes. Make sure you've actually got the HTTP Binding installed or it'll all just silently fail. I wasn't able to see the list of Official Bindings because of some weird internal issue. So I had to do a full sudo apt-get update && sudo apt-get upgrade openhab before I could get it.
Then, fun times ensued because the PowerPal API uses a slightly-strange way of providing authentication, which didn't fit very well with how the HTTP binding wants to do it. I had to go spelunking through the binding's source code to figure out how to specify the Authorization header myself.
Now we can finally get to the "home automation bus" bit of openHAB ... we define a rule that's watching for power usage changes, and triggers my Broadlink SP2 smart power switch on or off depending on whether we're net-zero.
$OPENHAB_CONF/rules/dispatchable.rules:
rule "Charge batteries if in power surplus" when Item housePowerUsage changed then logInfo("dispatchable", "Power: " + housePowerUsage.state); if (SP2_Power.state === ON && housePowerUsage.state > 0|W) { logInfo("dispatchable", "Charger -> OFF"); SP2_Power.sendCommand(OFF); } if (SP2_Power.state === OFF && housePowerUsage.state == 0|W) { logInfo("dispatchable", "Charger -> ON"); SP2_Power.sendCommand(ON); } end
And we're all done!
What's that weird |W stuff? that's an inline conversion to a Number:Power object, so that comparisons can be performed - a necessary, if slightly awkward aspect of openHAB's relatively-new "Units Of Measurement" feature.
What does it look like? Here's the logs from just after 9am:
09:06:37 [dispatchable] - Power: 3 W 09:07:37 [dispatchable] - Power: 2 W 09:08:37 [dispatchable] - Power: 3 W 09:09:37 [dispatchable] - Power: 2 W 09:12:37 [dispatchable] - Power: 3 W 09:13:37 [dispatchable] - Power: 2 W 09:16:37 [dispatchable] - Power: 1 W 09:18:37 [dispatchable] - Power: 0 W 09:18:37 [dispatchable] - Charger -> ON
So the query to PowerPal is obviously running on the 37th second of each minute. There are "missing" entries because we're only logging anything when the power figure has changed. You can see the panels gradually creating more power as the sun's incident angle/power improves, until finally at 9:18, we hit power neutrality and the charger is turned on. Not bad.
Saturday, 26 February 2022
New Toy
I just received this from the good folk at PowerPal:
This is a cool device that basically should give me real-time API-based access to the power usage of my house. The next logical step for me is to then bundle it up into my openHAB setup. I'll probably begin with just using the HTTP binding to get what I need, and maybe (and it's a BIG maybe) turn it into a genuine binding at some point in the future. My experience trying to get the Broadlink binding merged into the openHAB addons codebase has turned me off that process a little...
Thursday, 6 December 2018
Green Millhouse: OK Google, turn on the living room air conditioner
The RM3 sits in a little niche that has line-of-sight to both these devices (a Daikin in the living room, and a Panasonic in the dining area). Using the RM-Bridge Android app, the fun2code website and the method I've documented over on the OpenHAB forums), I've learnt the ON and OFF codes for each device, and put them into transforms/broadlink.map:
PANASONIC_AIRCON_ON=D3ADB33F... PANASONIC_AIRCON_OFF=13371337... DAIKIN_AIRCON_ON=F00F00FAAFAA... DAIKIN_AIRCON_OFF=F00D00FAAFAA...
The "basic" way of invoking the commands is by using a String Item for your IR-blaster device, and a Switch in your sitemap, like this:
items/remotecontrollable.items:
String RM3_MINI {channel="broadlink:rm3:34-ea-34-58-9d-5b:command"}
sitemaps/default.sitemap:
sitemap default label="My house" { Frame label="Aircon" { Switch item=RM3_MINI label="Dining Area" mappings=[PANASONIC_AIRCON_ON="On", PANASONIC_AIRCON_OFF="Off"] } ... }
Which gives you this:
... which is completely fine for basic UI control. But if you want the Google Home Assistant (aka "OK Google") to be able to operate it, it won't work. The reason for this is that the Switchable trait that you have to give the item can only take the simple values ON and OFF, not a string like PANASONIC_AIRCON_ON. So while it *might* work if you named your remote control commands ON and OFF, you're hosed if you want to add a second switchable device.
The best solution I could find was to set up a second Item, which is literally the most basic Switch you can have. You can also give it a label that makes it easier to remember and say when commanding your Google Home device. You then use a rule to issue the "command" to match the desired item's state. I'll demonstrate the difference by configuring the Living Room aircon in this Google-friendly way:
items/remotecontrollable.items:
String RM3_MINI {channel="broadlink:rm3:34-ea-34-58-9d-5b:command"} Switch AC_LIVING_ONOFF "Living Room Air Conditioner" [ "Switchable" ]
Notice the "label" in the Switch is the one that will be used for Google voice commands.
rules/remotecontrollable.rules:
rule "Translate Living Room ON/OFF to aircon state" when Item AC_LIVING_ONOFF changed then val isOn = (AC_LIVING_ONOFF.state.toString() == "ON") val daikinState = if(isOn) "DAIKIN_AIRCON_ON" else "DAIKIN_AIRCON_OFF" RM3_MINI.sendCommand(daikinState) end
This rule keeps the controlling channel (RM3_MINI) in line with the human-input channel (the OpenHAB UI or the Google Home Assistant input). Finally the sitemap:
sitemaps/default.sitemap:
sitemap default label="My house" { Frame label="Aircon" { Switch item=AC_LIVING_ONOFF label="Living Room On/Off" } ... }
I quite like the fact that the gory detail of which command to send (the DAIKIN_AIRCON_ON stuff) is not exposed in the sitemap by doing it this way. You also get a nicer toggle switch as a result:
The final step is to ensure the AC_LIVING_ONOFF item is being exposed via the MyOpenHAB connector service, which in turn links to the Google Assistant integration. And now I can say "Hey Google, turn on the living room air conditioner" and within 5 seconds it's spinning up.
Friday, 4 May 2018
Raspberry Pi 3 Model B+
But that was before I knew about the Raspberry Pi 3, Model B+. This little rocket boots up its Raspbian (tweaked Debian) OS in a few seconds, has 1Gb of RAM and a quad-core 1.4GHz ARM processor that does a great job with the Java workloads I'm throwing at it. And look at the thing - it's about the size of a pack of cards:
With wired and wireless Ethernet, scads of USB 3.0 ports and interesting GPIO pin possibilities, this thing is ideal for my home automation projects. And priced so affordably that (should it become necessary) running a fleet of these little guys is quite plausible. If like me, you had thought the Raspberry Pi was a bit of a toy, take another look!
Sunday, 25 February 2018
Green Millhouse - Temp Monitoring 2 - Return of the BroadLink A1 Sensor!
Here's the relevant OpenHAB forum post - it includes a link to a Beta-quality OpenHAB binding, which I duly installed to my Synology's OpenHAB 2 setup, and it showed itself to be pretty darn good. Both my A1 and my new BroadLink RM3 Mini (wifi-controlled remote blaster) were discovered immediately and worked great "out of the box".
However, I discovered that after an OpenHAB reboot (my Synology turns itself off each night and restarts each morning to save power) the BroadLink devices didn't come back online properly; it was also unreliable at polling multiple devices, and there were other niggly little issues identified by other forum members in the above thread. Worst of all, the original developer of the binding (one Cato Sognen) has since gone missing from the discussion, with no source code published anywhere!
Long story short, I've decided to take over the development of this binding - 90% of the work has been done, and thanks to the amazing JAD Decompiler, I was able to recover the vast majority of the source as if I'd written it myself. At the time of writing I am able to compile the binding and believe I have fixed the multiple-device problems (the code was using one shared static Socket instance and a shared mutable Boolean to try and control access to it...) and am looking at the bootup problems. And best of all, I'm doing the whole thing "in the open" over on Github - everyone is welcome to scrutinise and hopefully improve this binding, with a view to getting it included in the next official OpenHAB release.
Tuesday, 29 November 2016
Green Millhouse - Temp Monitoring 1 - Hacking the BroadLink A1 Sensor
These devices, like those before them, have dubious reputations for "phoning home" to random Chinese clouds and being difficult and unreliable to set up. I can confirm!
The first problem is easily nipped in the bud with some judicious network configuration, as I outlined last time. The device works just as well when isolated from the outside world, so there is nothing to fear there.
The second problem is real. Luckily, it's as if they know the default device-finding process will fail (which it did for me the half-dozen times I tried), and they actually support and document an alternative scheme ("AP Mode") which works just fine. Just one thing though - this device seems to have NO persisted storage of its network settings (!) which probably means you'll be going through the setup process a few times - you lose power, you lose the device. Oy.
So once I had the sensor working with its (actually quite decent) Android app, it was time to start protocol-sniffing, as there is no existing binding for this device in OpenHAB. It quickly became apparent that this would be a tough job. The app appeared to use multicast IP to address its devices, and a binary protocol over UDP for data exchange.
Luckily, after a bit more probing with WireShark and PacketSender, the multicast element proved to be a non-event - seems like the app broadcasts (i.e. to 255.255.255.255) and multicasts the same discovery packet in either case. My tests showed no response to the multicast request on my network, so I ignored it.
Someone did some hacks around the Android C library (linked from an online discussion about BroadLink devices) but all my packet captures showed that encryption is being employed (for reasons unknown) and inspection confirms encryption is performed in a closed-source C library that I have no desire to drill into any further.
A shame. The BroadLink A1 sensor is a dead-end for me, because of their closed philosophy. I would have happily purchased a number of these devices if they used an open protocol, and would have published libraries and/or bindings for OpenHAB etc, which in turn encourages others to purchase this sort of device.
UPDATE - FEB 2018: The Broadlink proprietary encrypted communication protocol has been cracked! OpenHAB + Broadlink = viable!
Monday, 2 November 2015
Green Millhouse - Hacking WiFi Power Points
An area in particular is running an efficient home. My first toe-dip in this area is shutting down (not putting-into-standby, shutting down) as many things as possible for as much of the day as possible. Being a geek, controlling some power-points via WiFi seemed like a great way to get started. Hence: These $20 devices can be found on eBay and are controlled by an app that is only ever named in the user manual. This smells of "security by obscurity" and after further investigation I can see why...
My particular one (which was identical to the photo) was called a "Small-K" but you'll probably get the most Google-joy by searching for "Kankun" devices. There are a whole pile of different iOS and Android apps, with various brandings and/or success at translation into English.
There is an extremely troubling suggestion that the various Android apps do some "calling home" via some Chinese servers - this, combined with the fact that you have to tell your device your SSID and WiFi password, made me sufficiently uneasy that even though I have uninstalled the Android app (it was junk anyway), I'll be putting my smart plugs into a dedicated subnet that is unable to "get out of" my network. How?
Putting network devices in jail
I use DNSmasq on my NAS which gives me much more control over my DHCP than the usual on/off switch in consumer routers. The setup to make sure a particular device doesn't go wandering off out onto the interwebs just needs two lines of configuration in dnsmasq.conf, namely:# Always give the host with ethernet address 11:22:33:44:55:66 # the name smartplug1, # IP address 10.200.240.1, # lease time 45 minutes, and # assign it to the "jailed" group dhcp-host=11:22:33:44:55:66,smartplug1,10.200.240.1,45m,net:jailedWhy 10.200.240.1? Well:
- 10 because I like to have space ;-)
- 200d is 11001000 which in my bitwise-masking permissions scheme means:
- Firewalled FROM internet
- Trusted WITHIN home network; and
- Prevented from going TO internet (I've added that last bit flag since writing that old post)
- 240d because it's 240-Volt mains power (geddit?); and
- 1 because it's my first device of this type
# Members of the "jailed" group don't get # told about the default gateway #("router" in DHCP-speak) #- this sends a zero-length value: dhcp-option = net:jailed, option:routerAnd we can check this after rebooting the plug; in the DNSmasq logs:
dnsmasq-dhcp: DHCPDISCOVER(eth0) 11:22:33:44:55:66 dnsmasq-dhcp: DHCPOFFER(eth0) 10.200.240.1 11:22:33:44:55:66 dnsmasq-dhcp: DHCPREQUEST(eth0) 10.200.240.1 11:22:33:44:55:66 dnsmasq-dhcp: DHCPACK(eth0) 10.200.240.1 11:22:33:44:55:66 smartplug1.. and after logging in to root@smartplug1:
root@koven:~# ping www.google.com PING www.google.com (220.244.136.54): 56 data bytes ping: sendto: Network is unreachable