Zigbee devices monitoring using OpenHab

Hi all,

This topic is about how-to monitor Zigbee devices connected via Zigbee2mqtt using only Openhab power.

I have around 30 Zigbee devices in network, many of them are battery-powered, and:

  • Some of Zigbee devices do not report battery level properly.
  • Some of Zigbee devices report wrong battery level.
  • We have important devices (like Water-leak sensors) which should be monitored.

It may cause that sometimes i missing the moment when device goes offline. So, let’s setup some device monitoring on it. Zigbee2mqtt has built-in device checker, but i don’t like it - i want to check only some of devices and i don’t want to push them to prolong battery life.

First of all, will declare device with special channels on it. Classic link/battery and new - activity.

// Xiaomi MiJia temperature & humidity sensor (WSDCGQ01LM)
Thing mqtt:topic:openhab:mi-sensor-cc22 (mqtt:broker:openhab) {
		Type number : temperature [ stateTopic="zigbee2mqtt/0x00158d0001c2cc22", transformationPattern="JSONPATH:$.temperature" ]
		Type number : humidity [ stateTopic="zigbee2mqtt/0x00158d0001c2cc22", transformationPattern="JSONPATH:$.humidity" ]
		Type number : battery [ stateTopic="zigbee2mqtt/0x00158d0001c2cc22", transformationPattern="JSONPATH:$.battery" ]
		Type switch : battery_low [ stateTopic="zigbee2mqtt/0x00158d0001c2cc22", transformationPattern="JS:z2m-lowbatt.js" ]
		Type number : link [ stateTopic="zigbee2mqtt/0x00158d0001c2cc22", transformationPattern="JSONPATH:$.linkquality" ]
		Type datetime : activity [ stateTopic="zigbee2mqtt/0x00158d0001c2cc22", transformationPattern="JS:z2m-activity.js" ]

I have added special transformation to record last activity update, by return current date:

// z2m-activity.js
(function (dataString) {
    var now = new Date();
    return now.toISOString();

This will save latest received packet to activity channel. Will add item on it:

DateTime mi_sens_weather_activity "MI Sens Weather [JS(display-activity.js):%s]" <time> (g_zigbee_activity) { channel="mqtt:topic:openhab:mi-sensor-cc22:activity" }

I have added special display-formatter to show last activity time in human-friendly way, without date-time parsing:

// display-activity.js
(function (dataString) {
    // Make a fuzzy time
    // https://stackoverflow.com/a/7641812
    var delta = Math.round((+new Date - new Date(dataString)) / 1000);
    if (isNaN(delta)) {
        return "?"
    var minute = 60,
        hour = minute * 60,
        day = hour * 24,
        week = day * 7;
    var fuzzy;
    if (delta < 30) {
        fuzzy = 'Now';
    } else if (delta < minute) {
        fuzzy = delta + ' s';
    } else if (delta < hour) {
        fuzzy = Math.floor(delta / minute) + ' m';
    } else if (delta < day) {
        fuzzy = Math.floor(delta / hour) + ' h';
    } else {
        fuzzy = Math.floor(delta / day) + ' d';
    return fuzzy;

Now we have item, which either stores correct value format (DateTime) and has nice printout in the same time. Now we can group this items to have some aggregation (will print WORST value, earliest item in group):

Group:DateTime:EARLIEST g_zigbee_activity "Zigbee Activity [JS(display-activity.js):%s]" <time>

And we can add it to sitemap:

And, for sure, we can now monitor - to find out stale devices (or just check the Group value instead of loop. I have it, as i want to have exact names to be sent):

// This rule send notifications if item was not updated within 24 hrs
rule "Test devices responce time"
    Time cron "0 00 12 ? * *"
	or Item test_sw_check_activity received command
	g_zigbee_activity.members.forEach [s |
        if (s.state != NULL) {
            val date_item = new DateTime(( s.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)
            val date_now = new DateTime()

            var double diff_hours = (date_now.millis - date_item.millis) / 1000 / 60 / 60

            logInfo("activity", "Item " + s.label + " last update: " + diff_hours)

            if (diff_hours > 24) {
                sendBroadcastNotification("Item " + s.label + " no activity for " + diff_hours + " h")
        } else {
            logInfo("activity", "Item " + s.label + " never updated")

That’s all, folks! Now we have some monitoring and report statement on sitemap.

Full source code is available in my github repository petrows/smarthome-openhab.

1 Like

This is interesting - thanks for posting and sharing! A few thoughts:

  1. Is there any reason that you’re not using the availability topic which zigbee2mqtt sends for each device? This is a topic which is available to me when using the attribute output of zigbee2mqtt, rather than the json output. As soon as the device disappears, the message offline is sent on the availability topic, which I subscribe to with openHAB and can then act upon.
  2. Did you know that this is possible? If you used this profile feature, you could get rid of your transformationPattern JS transformation altogether.
  3. Did you know that you can use friendly-name in your zigbee2mqtt configuration.yaml? It would make your openHAB configurations, and MQTT topics, a bit more human-readable, as it would remove 0x00158d0001c2cc22 and use whatever you specified as friendly-name!

Obviously, it’s working for you, so no need to change anything really!

Oooh, and one more thing: you can also monitor (and control) the status of your bridge (CC2531 USB stick, for example)!

I remember that the zigbee2mqtt availability will only work for non-battery devices.
@Petrows, thanks for sharing.

Interesting. I have a couple of battery powered devices (buttons), but haven’t really checked what happens if they lose power (hasn’t happened yet!).

Just because of personal interest: Why are you all using zigbee2mqtt in combination with OH instead of the official Zigbee binding?

Hey, thanks for your feedback!

Yes, i wrote that in Post, maybe not enough detailed. Availability works not exact as i want, and not for all devices. So i’d prefer to have fine control over devices how and when decide that they are not okay.

No, i was not aware! Thanks, probably will convert to it.

Yes, i know, but i am using device-id’s for a while because i think device “sensor-c1a1” will remain “sensor-c1a1” forever, and his role is defined only in Openhab items stage. If you move it from one room to another, you don’t need to rename it in many places. Also, i marked all devices with their ids, so match is easy. Main disadvantage that it’s hard to read logs, but i had no real cases yet, usually when you want to check something in log, you already know device you are going to check.

Yes, i am using Allow Join button in my config, pretty usefull!

1 Like

For me:

  1. I was already using MQTT, and the MQTT binding. The fewer bindings I use, the more stable openHAB runs for me.
  2. If openHAB goes down, I can still control all my devices through a generic MQTT App. Sort-of redundancy, if you will, and I’m not reliant on openHAB in the (extremely unlikely) event this project goes away.
  3. Zigbee2mqtt provides a great, huge list of compatible devices - very useful to know what has and has not been tested before spending money.


So, Zigbee binding is a bit easier to use, but i’d prefer fine control of devices description and behavior. Also, i had bad experience with some bindings in the past (like Yellight - i am using CLI commands and parsing instead for now), so, i am prefer to avoid them if possible, just to have explicit control.

1 Like

Thank you very much for these insights. I understand that as I a am also using MQTT for my Shelly devices instead of the official binding for similar reasons.
As I am also experiencing some problems with the official Zigbee binding I think zigbee2mqtt sounds interesting to me.
May I ask you which coordinator you are using?

A CC2531 - very first recommended one on this page.

I am using CC2530 based device with “Core Router” FW (normal FW stopped working after ~15 devices). At that moment i have 29 Zigbee devices in network, works pretty good. Only one problem was with accurate monitoring =)

1 Like

I moved from the CC2531 to a ZZH Stick from Tindie. I drive currently 49 devices with the ZZH and 4 router devices. No problems so far.

For monitoring I use the lastseen property with an associated datetime. Then by a change it triggers a proxy switch with expire. If the expire fires, I know that there is probably something going wrong. Pretty easy implementation and works for me

1 Like

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.