Infinite energy – How to add a battery level warning to all your sensors

Published by Oliver on

Battery powered smart home devices are great. Usually small and unobtrusive and usable everywhere without the need for wires. Unfortunately batteries run out of power at one point and quietly loosing an important sensor is not so great. Here is how to build a battery level warning system to avoid such a scenario.

The setup

If you are using a similar setup as I do then you have quite some battery powered sensors in your smart home. I have a bunch of Aqara sensors, including a very important water leak sensor, as well as some battery powered IKEA Tradfri devices up and running. Both are cheap and work together well as they are both using Zigbee. I connected them to my OpenHab instance via the awesome Zigbee2MQTT project.

To be able to react to battery levels of course we need those values available in OpenHab. The battery powered Aqara sensors for example provide a battery level if connection via Zigbee2MQTT that looks like this

Number TempBath_battery        "Battery level [%d%%]"                                (grBattery)     { channel="mqtt:topic:mosquitto:TempBath:battery" }

Displaying the battery status

Once we have these battery percentage values of course it is easy to display them in OpenHab. Just add some like this to your sitemap to show it:

Text item=TempBath_battery

I quickly discovered that simply displaying these values does not really provide me with too much information. What I am missing here is the development over time. Otherwise a 50% battery might either mean you need to charge tomorrow or in another year, we just don’t know.

Although saving sensor values of time is not that difficult to do in OpenHab, I will also create a more in-depth tutorial later. Here is the quick overview though: remember the “grBattery” group that the item is part of? I have InfluxDB set up as a database with this configuration:

Strategies {
    everyMinute : "0 * * * * ?"
    everyHour   : "0 0 * * * ?"
    everyDay    : "0 0 0 * * ?"

Items {
    grHistory* : strategy = everyChange, everyHour

This means OpenHab will save each value in the “grHistory” group once every hour and every time it changes. It could easily be changed to every minute by switching strategies but as every change is already recorded I don’t think this is needed. Now we have a database with a history of all our battery states.

Diagrams of this kind of data could be displayed directly in OpenHab, but there is a much more powerful tool for this: Grafana.

visual battery level warnings in my grafana dashboard
My Grafana battery dashboard

Grafana is a tool made to easily build dashboard for data visualization. If you installed OpenHab on a Rasperry Pi via OpenHabian you simply install InfluxDB and Grafana via the setup assistant.

Once you have Grafana installed connect it to your InfluxDB database and create a new “singlestat” on the dashboard. Pick the battery item from the database to load it into this visualization.

Pick your battery item

Afterwards head over to the Options tab to customize the look & feel of this item. I decided to increase the font sizes for better readability and show this Gauge indicator. I also set thresholds for color changes. If the value of the battery falls under 80% it will change from green to orange. If it even falls under 50% it will change to red. That way I can see on the first glance if I need to pay attention to the battery levels at all.

Options to adjust how the Singlestat will look like

Of course you can use the battery values from the database for any visualization. You could for example also create a line graph showing the battery levels over time or activate the “Spark lines” setting in our existing Singlestat to also show historic values.

The battery level warning

Now we are able to see all our battery states in OpenHab as well as nicely presented in Grafana. My last step was to add an actual battery level warning once a battery falls under a critical level. This can be done by using an OpenHab rule like this.

rule "Send battery alerts"
	Member of grBattery changed
	logDebug("Rule", "Updated battery levels {}", grBattery)
	grBattery.members.filter[ i | i.state < 25].forEach[i | sendPushoverMessage(pushoverBuilder("Batterie is low. Remaining level: " + i))]

This rule gets triggered every time a battery level in the “grBattery” group changes. The will filter all levels and only act on those that are under a certain threshold (25% in this case). For those an alarm is sent to my phone via Pushover. That is the same service I also used for my water leak alarm.

This way I will always be reminded when a sensors battery reaches a critical state. Most batteries are not drained linearly but fall of really fast in the first few and last few percent. That means if the level gets low changing the battery soon would be a good move.

Luckily the sensors I am using have a great battery lifetime and after using them for about a year they are still show values >90%. However if they drop I will be notified.