Migrating Zwave & ZigBee stuff to MQTT - guidance needed.
-
Release development v22.12.6 separating switch and controller devices, and fixing nil function pointer.
-
@akbooer said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
Release development v22.12.6 separating switch and controller devices, and fixing nil function pointer
Thanks for that - looks OK now.
Have now got all my Hue stuff running with no Hue hub - that's good. A few complications here and there.
Main complication:
Conditions:
z2m is running and openLuup is running.
Then pair new device: in this case this Philips light bulb with z2m.
z2m logs this to the terminal. I've prettied the json section so you can read it:Zigbee2MQTT:info 2022-12-10 10:40:28: Device '0x001788010363fcbf' joined Zigbee2MQTT:info 2022-12-10 10:40:28: MQTT publish: topic 'zigbee2mqtt/bridge/event', payload '{"data":{"friendly_name":"0x001788010363fcbf","ieee_address":"0x001788010363fcbf"},"type":"device_joined"}' Zigbee2MQTT:info 2022-12-10 10:40:28: Starting interview of '0x001788010363fcbf' Zigbee2MQTT:info 2022-12-10 10:40:28: MQTT publish: topic 'zigbee2mqtt/bridge/event', payload '{"data":{"friendly_name":"0x001788010363fcbf","ieee_address":"0x001788010363fcbf","status":"started"},"type":"device_interview"}' Zigbee2MQTT:info 2022-12-10 10:40:29: Successfully interviewed '0x001788010363fcbf', device has successfully been paired Zigbee2MQTT:info 2022-12-10 10:40:29: Device '0x001788010363fcbf' is supported, identified as: Philips Hue White A60 Single bulb E27/B22 (8718696449691) Zigbee2MQTT:info 2022-12-10 10:40:29: MQTT publish: topic 'zigbee2mqtt/bridge/event', payload ' { "data": { "definition": { "description": "Hue White A60 Single bulb E27/B22", "exposes": [{ "features": [{ "access": 7, "description": "On/off state of this light", "name": "state", "property": "state", "type": "binary", "value_off": "OFF", "value_on": "ON", "value_toggle": "TOGGLE" }, { "access": 7, "description": "Brightness of this light", "name": "brightness", "property": "brightness", "type": "numeric", "value_max": 254, "value_min": 0 }], "type": "light" }, { "access": 2, "description": "Triggers an effect on the light (e.g. make light blink for a few seconds)", "name": "effect", "property": "effect", "type": "enum", "values": ["blink", "breathe", "okay", "channel_change", "finish_effect", "stop_effect"] }, { "access": 1, "description": "Link quality (signal strength)", "name": "linkquality", "property": "linkquality", "type": "numeric", "unit": "lqi", "value_max": 255, "value_min": 0 }], "model": "8718696449691", "options": [{ "access": 2, "description": "Controls the transition time (in seconds) of on/off, brightness, color temperature (if applicable) and color (if applicable) changes. Defaults to `0` (no transition).", "name": "transition", "property": "transition", "type": "numeric", "value_min": 0 }], "supports_ota": true, "vendor": "Philips" }, "friendly_name": "0x001788010363fcbf", "ieee_address": "0x001788010363fcbf", "status": "successful", "supported": true }, "type": "device_interview" } ' Zigbee2MQTT:info 2022-12-10 10:40:29: Configuring '0x001788010363fcbf' Zigbee2MQTT:info 2022-12-10 10:40:29: Successfully configured '0x001788010363fcbf'
Looks like openLuup then responds to the topic zigbee2mqtt/bridge/event ?? and creates a Generic device. The openLuup log doesn't make it clear what topic it's responding to when it creates a device but you can see in the log that it has found a new device:
2022-12-10 10:40:28.568 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:28.571 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/logging 2022-12-10 10:40:28.574 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:28.591 luup.zigbee2mqtt:0: New Zigbee detected: 0x001788010363fcbf 2022-12-10 10:40:28.594 luup.create_device:: [20010] D_GenericZigbeeDevice.xml / / D_GenericZigbeeDevice.json (GenericZigbeeDevice) 2022-12-10 10:40:28.602 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:28.603 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/logging 2022-12-10 10:40:28.605 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:28.605 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/event 2022-12-10 10:40:28.607 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:28.607 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/logging 2022-12-10 10:40:28.609 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:28.626 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:28.626 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/logging 2022-12-10 10:40:28.628 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:28.628 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/event 2022-12-10 10:40:28.754 openLuup.server:: request completed (11333 bytes, 1 chunks, 2261 ms) tcp{client}: 0x43d0070 2022-12-10 10:40:28.766 openLuup.server:: GET /data_request?id=user_data&output_format=json&DataVersion=564556066&_=1670559272961 HTTP/1.1 tcp{client}: 0x43d0070 2022-12-10 10:40:29.987 openLuup.server:: request completed (1723523 bytes, 108 chunks, 1220 ms) tcp{client}: 0x43d0070 2022-12-10 10:40:30.017 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:30.017 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/logging 2022-12-10 10:40:30.018 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:30.018 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/logging 2022-12-10 10:40:30.020 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:30.032 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:30.033 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/logging 2022-12-10 10:40:30.034 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:30.035 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/event 2022-12-10 10:40:30.036 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:30.036 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/logging 2022-12-10 10:40:30.037 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:30.037 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/logging 2022-12-10 10:40:30.039 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:30.048 openLuup.mqtt:: PUBLISH tcp{client}: 0x3a7b670 2022-12-10 10:40:30.052 luup.zigbee2mqtt:0: Topic ignored : zigbee2mqtt : / : bridge/info
So it looks as the event returns the same data as "zigbee2mqtt/bridge/devices" does, as each new device is paired but it's parent json is a little different. The device definition is below "data" in the json:
"data":
With type set as follows:
type="device_interview",
and this must indicate success:
data.status ="successful"
Hope that's clear - bit hard to explain.
Suffice to say I added a pile of stuff and ended up with a whole pile of generic devices, which I had to remove one by one with a openLuup restart for each. Got a bit ambitious!
However; it looks like the ability to handle the addition of new devices on the fly without having to restart thez2m server each time to get the device definitions, would certainly be possible and a welcome addition.
Looks like you just look for the event topic with {"type":"device_interview" and {"data": status":"successful".
The json contains definition.expose.type = light so the function infer_device_type() should still do its work OK as it currently does.
I can't test any new code on this as I have now added all my devices. Although I could unpair just a light bulb and repair it and see what happens.
-
a-lurkerreplied to a-lurker on Dec 11, 2022, 8:06 AM last edited by a-lurker Dec 11, 2022, 3:11 AM
A slight in convenience:
Conditions:
Having just added a scene controller to z2m and restarted the z2m server and openLuup has dutifully added it in and here it is:Great; so first thing to do next, is to link the scene controller to a scene: So create a new scene, dial up the scene controller and put a watch on to create a trigger:
LastSceneTime (new~=old)
Problem is LastSceneTime is nowhere to be found - bit disconcerting at this point. In order to proceed, you have to push a button on the scene controller to get the variable to be created. Suggest the variable is created when the scene controller is first added to openLuup and set its time to Unix year zero.
-
A slight in convenience: no way to set color on the light bulbs. X,Y color space seems better than RGB as it allows you to specify white color temperature.
-
This vibration detection device and other similar devices should be "inferred" as a motion sensor. They expose "contact".
Perhaps infer_device_type() could use some look up table or look at json string that could perhaps be later saved to a file that the user could fiddle with? eg some vague pesudo code. Whatever you figure would work.
local deviceType = nil if (lookup.exposes.contact) then deviceType = lookup.exposes.contact end
-
akbooerreplied to a-lurker on Dec 11, 2022, 10:41 AM last edited by akbooer Dec 11, 2022, 5:58 AM
@a-lurker said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
Looks like openLuup then responds to the topic zigbee2mqtt/bridge/event ?? and creates a Generic device.
Can't see how that would happen. The bridge code is clear that anything other than bridge/devices is ignored:
local function handle_bridge_topics (topic, message) local subtopic = topic: match "^bridge/(.+)" if subtopic: match "^devices" then create_devices (message) else ignore_topic (topic) end end
and it should write Topic ignored... in the log. If it creates a device, it must be receiving the actual /devices topics. I take it that your "info" log messages are your own additions to the code. I could certainly make it respond to a /event topic. The Shelly and Tasmota bridges already create new devices on the fly, because they send their own configurations when they connect to MQTT.
-
@a-lurker said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
Problem is LastSceneTime is nowhere to be found - bit disconcerting at this point. In order to proceed, you have to push a button on the scene controller to get the variable to be created.
Yes, that's true. The root cause is actually that the service file for a scene controller S_SceneController1.xml does not contain a definition of that variable, or a default vaule for it. I could force this at device creation, but you have found a work-around alreay.
-
@a-lurker said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
A slight in convenience: no way to set color on the light bulbs. X,Y color space seems better than RGB as it allows you to specify white color temperature.
Some investigation required here. The existing Color service definition defines three actions of interest:
- setColor
- setColorRGB
- setColorTemperature
It's not clear from the service file definition what the possible value/syntax is for any of these commands, so that would mean delving into the UPnP documentation, which, previously, I've found to be an absolute nightmare (as are most international standard definitions.) Perhaps csomeone here can aleady tell us the answer?
-
@a-lurker said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
This vibration detection device and other similar devices should be "inferred" as a motion sensor. They expose "contact".
Do you have the bridge/devices JSON for that device?
-
@akbooer said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
The root cause is actually that the service file for a scene controller S_SceneController1.xml does not contain a definition of that variable, or a default vaule for it. I could force this at device creation
...and I have just done so in development v22.12.11.
-
@akbooer said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
Do you have the bridge/devices JSON for that device?
No but I would see it as no different to checking "occupancy" in the motion sensor device.
-
@akbooer said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
I take it that your "info" log messages are your own additions to the code.
The two logs are directly as they were spat out, except for uncollapsing of the json as mentioned above. I made no changes.
Yes - this is very odd - I can't see how the code would respond to anything else but the bridges/devices topic either. But certainly it appears to have done same; but unsuccessfully as all devices ended up being considered Generic. I may have to try repairing a bulb with more debug code.
Moving forward - responding to an /event topic would be good.
-
These messages:
Zigbee2MQTT:info 2022-12-10 10:40:28: MQTT publish: topic 'zigbee2mqtt/bridge/event', payload '{"data":{"friendly_name":"0x001788010363fcbf","ieee_address":"0x001788010363fcbf"},"type":"device_joined"}' Zigbee2MQTT:info 2022-12-10 10:40:28: Starting interview of '0x001788010363fcbf' Zigbee2MQTT:info 2022-12-10 10:40:28: MQTT publish: topic 'zigbee2mqtt/bridge/event', payload '{"data":{"friendly_name":"0x001788010363fcbf","ieee_address":"0x001788010363fcbf","status":"started"},"type":"device_interview"}' Zigbee2MQTT:info 2022-12-10 10:40:29: Successfully interviewed '0x001788010363fcbf', device has successfully been paired Zigbee2MQTT:info 2022-12-10 10:40:29: Device '0x001788010363fcbf' is supported, identified as: Philips Hue White A60 Single bulb E27/B22 (8718696449691)
…don’t come from my code. You mentioned that this was printed out to the console… something else must be doing this too.
-
@akbooer said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
Some investigation required here. The existing Color service definition defines three actions of interest:
setColor
setColorRGB
setColorTemperatureIt's not clear from the service file definition what the possible value/syntax is for any of these commands, so that would mean delving into the UPnP documentation, which, previously, I've found to be an absolute nightmare (as are most international standard definitions.) Perhaps csomeone here can aleady tell us the answer?
I've done a lot of work on the color side of thing in the Vera, and my code used to work on openluup as well. Feel free to take inspiration from https://github.com/dbochicchio/vera-VirtualDevices/blob/master/L_VirtualRGBW1.lua
From line 134 you'll find all the formats that luup is supporting, at least on Vera's side. There's also W/D, for warn and cool white.
-
a-lurkerreplied to akbooer on Dec 11, 2022, 12:36 PM last edited by a-lurker Dec 11, 2022, 7:38 AM
@akbooer said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
don’t come from my code. You mentioned that this was printed out to the console… something else must be doing this too.
Yes - this is the output from z2m to its terminal, which I am monitoring. ie from the z2m server. Not from openLuup.
So the z2m server is interviewing the newly detected device and recognises it; next it ends up being created in openLuup!
-
akbooerreplied to a-lurker on Dec 11, 2022, 2:59 PM last edited by akbooer Dec 11, 2022, 1:23 PM
@a-lurker said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
So the z2m server is interviewing the newly detected device and recognises it; next it ends up being created in openLuup!
Mystery solved (partially.) From the docs:
zigbee2mqtt/bridge/devices
”Contains the devices connected to the bridge, this message is published as retained. Whenever a device joins or leaves this is republished.”
…but this doesn’t explain why the devices are not identified correctly.
-
a-lurkerreplied to akbooer on Dec 16, 2022, 7:51 AM last edited by a-lurker Dec 16, 2022, 4:52 PM
zigbee2mqtt/bridge/devices
”Contains the devices connected to the bridge, this message is published as retained. Whenever a device joins or leaves this is republished.”Well this turns out to be the case. Neither openLuup or z2m logged this, as you can see in the logs provided above. However I added logging some code to openLuup and yes and as expected the zigbee2mqtt/bridge/devices topic is published each time you add & remove a zigbee device, which is great. Would be good to see openLuup log the json info when any topic is RX'ed and when MQTT is in debug mode. mqttExplorer would have picked this up but it wasn't running at the time.
Here is the definition json for the dual general purpose outlet (GPO):
{ "date_code": "", "definition": { "description": "Ikuü double power point with USB", "exposes": [{ "endpoint": "left", "features": [{ "access": 7, "description": "On/off state of the switch", "endpoint": "left", "name": "state", "property": "state_left", "type": "binary", "value_off": "OFF", "value_on": "ON", "value_toggle": "TOGGLE" }], "type": "switch" }, { "endpoint": "right", "features": [{ "access": 7, "description": "On/off state of the switch", "endpoint": "right", "name": "state", "property": "state_right", "type": "binary", "value_off": "OFF", "value_on": "ON", "value_toggle": "TOGGLE" }], "type": "switch" }, { "access": 1, "description": "Instantaneous measured power", "endpoint": "left", "name": "power", "property": "power_left", "type": "numeric", "unit": "W" }, { "access": 1, "description": "Instantaneous measured electrical current", "endpoint": "left", "name": "current", "property": "current_left", "type": "numeric", "unit": "A" }, { "access": 1, "description": "Measured electrical potential value", "endpoint": "left", "name": "voltage", "property": "voltage_left", "type": "numeric", "unit": "V" }, { "access": 1, "description": "Sum of consumed energy", "name": "energy", "property": "energy", "type": "numeric", "unit": "kWh" }, { "access": 1, "description": "Link quality (signal strength)", "name": "linkquality", "property": "linkquality", "type": "numeric", "unit": "lqi", "value_max": 255, "value_min": 0 }], "model": "SPPUSB02", "options": [{ "access": 2, "description": "Calibrates the power value (percentual offset), takes into effect on next report of device.", "name": "power_calibration", "property": "power_calibration", "type": "numeric" }, { "access": 2, "description": "Calibrates the current value (percentual offset), takes into effect on next report of device.", "name": "current_calibration", "property": "current_calibration", "type": "numeric" }, { "access": 2, "description": "Calibrates the voltage value (percentual offset), takes into effect on next report of device.", "name": "voltage_calibration", "property": "voltage_calibration", "type": "numeric" }], "supports_ota": false, "vendor": "Mercator" }, "endpoints": { "1": { "bindings": [{ "cluster": "genBasic", "target": { "endpoint": 1, "ieee_address": "0x84b4dbfffecc0c6f", "type": "endpoint" } }, { "cluster": "genOnOff", "target": { "endpoint": 1, "ieee_address": "0x84b4dbfffecc0c6f", "type": "endpoint" } }, { "cluster": "haElectricalMeasurement", "target": { "endpoint": 1, "ieee_address": "0x84b4dbfffecc0c6f", "type": "endpoint" } }, { "cluster": "seMetering", "target": { "endpoint": 1, "ieee_address": "0x84b4dbfffecc0c6f", "type": "endpoint" } }], "clusters": { "input": ["genBasic", "genGroups", "genScenes", "genOnOff", "seMetering", "haElectricalMeasurement", "manuSpecificTuya", "genIdentify"], "output": ["genOta", "genTime"] }, "configured_reportings": [{ "attribute": "rmsVoltage", "cluster": "haElectricalMeasurement", "maximum_report_interval": 3600, "minimum_report_interval": 5, "reportable_change": 5 }, { "attribute": "rmsCurrent", "cluster": "haElectricalMeasurement", "maximum_report_interval": 3600, "minimum_report_interval": 5, "reportable_change": 50 }, { "attribute": "activePower", "cluster": "haElectricalMeasurement", "maximum_report_interval": 3600, "minimum_report_interval": 5, "reportable_change": 1 }, { "attribute": "onOff", "cluster": "genOnOff", "maximum_report_interval": 3600, "minimum_report_interval": 0, "reportable_change": 0 }], "scenes": [] }, "2": { "bindings": [{ "cluster": "genOnOff", "target": { "endpoint": 1, "ieee_address": "0x84b4dbfffecc0c6f", "type": "endpoint" } }], "clusters": { "input": ["genGroups", "genScenes", "genOnOff", "manuSpecificTuya", "genIdentify"], "output": [] }, "configured_reportings": [{ "attribute": "onOff", "cluster": "genOnOff", "maximum_report_interval": 3600, "minimum_report_interval": 0, "reportable_change": 0 }], "scenes": [] }, "242": { "bindings": [], "clusters": { "input": [], "output": ["greenPower"] }, "configured_reportings": [], "scenes": [] } }, "friendly_name": "0x842e14fffe13d0d5", "ieee_address": "0x842e14fffe13d0d5", "interview_completed": true, "interviewing": false, "manufacturer": "_TZ3210_pfbzs1an", "model_id": "TS011F", "network_address": 64390, "power_source": "Mains (single phase)", "supported": true, "type": "Router" }
To recognise this GPO, the function infer_device_type() needs to have a minor change:
--elseif exp.switch then elseif exp.type == "switch" then
That's not going to help very much as the device has two outlets and hence two independently controllable relays. It also has Voltage, current & power measurement but to make everything more difficult the power measurement is the addition of the power consumed by both outlets. This implies the device needs to be represented as a single parent with two children. Gets a bit messy.
The json defines two "Endpoint"s: "Endpoint: left" & "Endpoint: right". I note that ZWave JS UI takes the same sort of approach of making use of endpoints for compound devices.
Looking through the zigbee devices database you see identifiers such as follows - for compound devices:
state state_left, state_right state_left, state_center, state_right state_top, state_center, state_bottom state_l1, state_l2, state_l3, state_l4 --> state_lX state_top_left, state_center_left, state_bottom_left, state_top_right, state_center_right, state_bottom_right,
The dual GPO under discussion returns this payload regularly:
{ "current_left": 0, "energy": 0, "linkquality": 252, "power_left": 0, "state_left": "OFF", "state_right": "OFF", "voltage_left": 245 }
In fact, straight after purchase, it was returning this about every two seconds but fortunately in the z2m web page, you can change the reporting interval.
-
@a-lurker said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
Neither openLuup or z2m logged this, as you can see in the logs provided above.
Don't know how it missed this, given that the very first action in the MQTT module on receiving a message is...
if message then pname = message.packet_name _debug (pname, ' ', tostring(client)) ...
...but there you go.
@a-lurker said in Migrating Zwave & ZigBee stuff to MQTT - guidance needed.:
This implies the device needs to be represented as a single parent with two children. Gets a bit messy.
Not a fundamental issue – the Shelly, Tasmota, and ZWay bridges do this regularly. The up / down / sideways / ... states may be more of a challenge, in general.
The payload example you show is curiously asymmetric? (ie. some obvious values missing from the other switch.)
-
@akbooer said
curiously asymmetric
Yes - current/power/energy is as consumed by the addition of both outlets. Should be something like this but isn't:
{ "current_total": 0, "energy_total": 0, "linkquality": 252, "power_total": 0, "state_left": "OFF", "state_right": "OFF", "voltage": 245 }
-
Don't know how it missed this, given that the very first action in the MQTT module on receiving a message is...
I thought the MQTT messages would show up by setting this flag in the startup - which I have:
local attr = luup.attr_set attr("openLuup.MQTT.DEBUG", true)
but the console ABOUT page shows:
DEBUG false
Assume there are more than two flags in use? Checked the documentation but the only mention of a debug flag was for smttp.ABOUT.DEBUG How do set the other one?
62/73