Mini-tutorial: Control a Zigbee2Mqtt device in Gladys via Node-red when it's not yet recognized by Gladys

This mini-tutorial proposes connecting a device recognized in zigbee2mqtt but whose integration might not yet exist in Gladys by using node-red as an intermediary! No more excuses :slight_smile: for not using Gladys!

For this, we will create a virtual device (or virtual device) in the MQTT integration of Gladys and a Node-red flow that you just need to import and you will only need to configure according to the device to be controlled and your parameters (IP of your Gladys instance, Mqtt password, Zigbee2Mqtt password)

Let’s get started:

Go to the « Integrations » menu

Click on the « MQTT » integration icon

In device, click on the « New + » button

image

create a virtual device as follows

you will then have a device that should be this one

The device creation part is finished, it will only remain to display this device with these 2 features in the Gladys dashboard

There are 3 parameters that we will reuse later, these are the topics of « MQTT Topic to Publish » and « MQTT Topic to Listen »

Go to node-red and click on « Import »

Copy the following flow below and paste it then click on « Import »

Flow code
[
    {
        "id": "064a844a10f278d0",
        "type": "tab",
        "label": "Gladys <=> Z2M",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "2bee4d2d30957c22",
        "type": "group",
        "z": "064a844a10f278d0",
        "style": {
            "stroke": "#999999",
            "stroke-opacity": "1",
            "fill": "none",
            "fill-opacity": "1",
            "label": true,
            "label-position": "nw",
            "color": "#a4a4a4"
        },
        "nodes": [
            "55b5362bb2f1081f",
            "e5974b74c4f0523d",
            "896b379f92909116",
            "267f8ce1755e49ee",
            "79f42f08d633eba1",
            "86df5045936db7d1",
            "350d4cab9b6ddfc6",
            "eba51d83ac887a1c",
            "3ad8cd81b2da503b",
            "1908d429c1d0cf06",
            "9b850e5047f189e9",
            "5faacded48aa4cc7"
        ],
        "x": 74,
        "y": 99,
        "w": 1112,
        "h": 222
    },
    {
        "id": "0cf88844315f110d",
        "type": "group",
        "z": "064a844a10f278d0",
        "style": {
            "stroke": "#999999",
            "stroke-opacity": "1",
            "fill": "none",
            "fill-opacity": "1",
            "label": true,
            "label-position": "nw",
            "color": "#a4a4a4"
        },
        "nodes": [
            "07dec9a2ad2f07cd",
            "780c7da37c4cc4bf",
            "7e369026c5674540",
            "f17aadce56f60a2f",
            "73cdf2a53b73da8f",
            "79365e2791c55807",
            "a7ad027dd87ce30b",
            "32c7a028d4dba351",
            "b0717d9927c1b6d8",
            "fceca8e194e04524"
        ],
        "x": 74,
        "y": 399,
        "w": 1062,
        "h": 182
    },
    {
        "id": "e5974b74c4f0523d",
        "type": "mqtt in",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "IP Gladys:1883",
        "topic": "#",
        "qos": "2",
        "datatype": "auto",
        "broker": "f4ab211ed11dc81c",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 180,
        "y": 180,
        "wires": [
            [
                "896b379f92909116",
                "55b5362bb2f1081f"
            ]
        ]
    },
    {
        "id": "896b379f92909116",
        "type": "debug",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 370,
        "y": 220,
        "wires": []
    },
    {
        "id": "267f8ce1755e49ee",
        "type": "debug",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1050,
        "y": 280,
        "wires": []
    },
    {
        "id": "79f42f08d633eba1",
        "type": "change",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "Test OFF",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "zigbee2mqtt/NOUS-5/set/state",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "OFF",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 800,
        "y": 240,
        "wires": [
            [
                "267f8ce1755e49ee",
                "350d4cab9b6ddfc6"
            ]
        ]
    },
    {
        "id": "86df5045936db7d1",
        "type": "inject",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "OFF",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "OFF",
        "payload": "gladys/device/mqtt:Z2M-NOUS-5/feature/mqtt:Z2M-NOUS-5-state/state",
        "payloadType": "str",
        "x": 550,
        "y": 240,
        "wires": [
            [
                "79f42f08d633eba1"
            ]
        ]
    },
    {
        "id": "07dec9a2ad2f07cd",
        "type": "mqtt in",
        "z": "064a844a10f278d0",
        "g": "0cf88844315f110d",
        "name": "IP Zigbee2Mqtt:1884",
        "topic": "zigbee2mqtt/NOUS-5",
        "qos": "2",
        "datatype": "auto",
        "broker": "16ae73273064273e",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 190,
        "y": 480,
        "wires": [
            [
                "780c7da37c4cc4bf",
                "b0717d9927c1b6d8"
            ]
        ]
    },
    {
        "id": "780c7da37c4cc4bf",
        "type": "debug",
        "z": "064a844a10f278d0",
        "g": "0cf88844315f110d",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 370,
        "y": 540,
        "wires": []
    },
    {
        "id": "350d4cab9b6ddfc6",
        "type": "mqtt out",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "IP Zigbee2Mqtt:1884",
        "topic": "",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "16ae73273064273e",
        "x": 1060,
        "y": 180,
        "wires": []
    },
    {
        "id": "eba51d83ac887a1c",
        "type": "inject",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "ON",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "ON",
        "payload": "gladys/device/mqtt:Z2M-NOUS-5/feature/mqtt:Z2M-NOUS-5-state/state",
        "payloadType": "str",
        "x": 550,
        "y": 280,
        "wires": [
            [
                "3ad8cd81b2da503b"
            ]
        ]
    },
    {
        "id": "3ad8cd81b2da503b",
        "type": "change",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "Test ON",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "zigbee2mqtt/NOUS-5/set/state",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "ON",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 800,
        "y": 280,
        "wires": [
            [
                "350d4cab9b6ddfc6",
                "267f8ce1755e49ee"
            ]
        ]
    },
    {
        "id": "1908d429c1d0cf06",
        "type": "debug",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 790,
        "y": 140,
        "wires": []
    },
    {
        "id": "7e369026c5674540",
        "type": "mqtt out",
        "z": "064a844a10f278d0",
        "g": "0cf88844315f110d",
        "name": "IP Gladys:1883",
        "topic": "",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "f4ab211ed11dc81c",
        "x": 1030,
        "y": 480,
        "wires": []
    },
    {
        "id": "f17aadce56f60a2f",
        "type": "inject",
        "z": "064a844a10f278d0",
        "g": "0cf88844315f110d",
        "name": "ON",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "ON",
        "payload": "gladys/master/device/mqtt:Heiman-On/feature/mqtt:Heiman-On/state",
        "payloadType": "str",
        "x": 540,
        "y": 540,
        "wires": [
            [
                "73cdf2a53b73da8f"
            ]
        ]
    },
    {
        "id": "73cdf2a53b73da8f",
        "type": "change",
        "z": "064a844a10f278d0",
        "g": "0cf88844315f110d",
        "name": "Test value 66",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "gladys/master/device/mqtt:Z2M-NOUS-5/feature/mqtt:Z2M-NOUS-5-power/text",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "66",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 810,
        "y": 540,
        "wires": [
            [
                "7e369026c5674540",
                "79365e2791c55807"
            ]
        ]
    },
    {
        "id": "79365e2791c55807",
        "type": "debug",
        "z": "064a844a10f278d0",
        "g": "0cf88844315f110d",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1000,
        "y": 540,
        "wires": []
    },
    {
        "id": "a7ad027dd87ce30b",
        "type": "comment",
        "z": "064a844a10f278d0",
        "g": "0cf88844315f110d",
        "name": "Reception de Zigbee2Mqtt",
        "info": "",
        "x": 210,
        "y": 440,
        "wires": []
    },
    {
        "id": "32c7a028d4dba351",
        "type": "comment",
        "z": "064a844a10f278d0",
        "g": "0cf88844315f110d",
        "name": "Send to Gladys",
        "info": "",
        "x": 1030,
        "y": 440,
        "wires": []
    },
    {
        "id": "9b850e5047f189e9",
        "type": "comment",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "Reception de Gladys",
        "info": "",
        "x": 200,
        "y": 140,
        "wires": []
    },
    {
        "id": "5faacded48aa4cc7",
        "type": "comment",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "Send to Zigbee2Mqtt",
        "info": "",
        "x": 1050,
        "y": 140,
        "wires": []
    },
    {
        "id": "55b5362bb2f1081f",
        "type": "function",
        "z": "064a844a10f278d0",
        "g": "2bee4d2d30957c22",
        "name": "Gladys => zigbee2mqtt",
        "func": "var inputTopic = msg.topic;\nvar inputPayload = msg.payload;\n\n// Logic to change the topic and payload based on both the input topic and payload\n\nif (inputTopic === \"gladys/device/mqtt:Z2M-NOUS-5/feature/mqtt:Z2M-NOUS-5-state/state\" && inputPayload === \"0\") {\n  // Adapt the topic and payload from Gladys to zigbee2mqtt \n  msg.topic = \"zigbee2mqtt/NOUS-5/set/state\"; msg.payload = \"OFF\";\n} \n\nif (inputTopic === \"gladys/device/mqtt:Z2M-NOUS-5/feature/mqtt:Z2M-NOUS-5-state/state\" && inputPayload === \"1\") {\n  // Adapt the topic and payload from Gladys to zigbee2mqtt \n  msg.topic = \"zigbee2mqtt/NOUS-5/set/state\"; msg.payload = \"ON\";\n}\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 590,
        "y": 180,
        "wires": [
            [
                "1908d429c1d0cf06",
                "350d4cab9b6ddfc6"
            ]
        ]
    },
    {
        "id": "b0717d9927c1b6d8",
        "type": "function",
        "z": "064a844a10f278d0",
        "g": "0cf88844315f110d",
        "name": " zigbee2mqtt => Gladys",
        "func": "var inputTopic = msg.topic;\nvar inputPayload = JSON.parse(msg.payload);\n\n// Logic to change the topic and payload based on both the input topic and payload\nif (msg.topic === \"zigbee2mqtt/NOUS-5\") {\n    \n    \n    // If there is the value \"state\" in the json sent in the payload of zigbee2mqtt\n    if (inputPayload.hasOwnProperty('state')) {\n        // Adapt the topic from Gladys to zigbee2mqtt \n        msg.topic = \"gladys/device/mqtt:Z2M-NOUS-5/feature/mqtt:Z2M-NOUS-5-state/state\";\n        // Adapt the payload from zigbee2mqtt to Gladys \n        var payloadValue = inputPayload.state;\n        msg.payload = payloadValue;\n    } else {\n        // If the key 'power' is not present, set the output to \"default\"\n        msg.payload = \"default\";\n    }\n    \n    // If there is the value \"power\" in the json sent in the payload of zigbee2mqtt\n    if (inputPayload.hasOwnProperty('power')) {\n        // Adapt the topic from Gladys to zigbee2mqtt \n        msg.topic = \"gladys/master/device/mqtt:Z2M-NOUS-5/feature/mqtt:Z2M-NOUS-5-power/text\";\n        // Adapt the payload from zigbee2mqtt to Gladys \n        var payloadValue = inputPayload.power;\n        msg.payload = payloadValue;\n    } else {\n        // If the key 'power' is not present, set the output to \"default\"\n        msg.payload = \"default\";\n    }\n}\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 580,
        "y": 480,
        "wires": [
            [
                "7e369026c5674540",
                "fceca8e194e04524"
            ]
        ]
    },
    {
        "id": "fceca8e194e04524",
        "type": "debug",
        "z": "064a844a10f278d0",
        "g": "0cf88844315f110d",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 780,
        "y": 440,
        "wires": []
    },
    {
        "id": "f4ab211ed11dc81c",
        "type": "mqtt-broker",
        "name": "192.168.0.125:1883",
        "broker": "192.168.0.125",
        "port": "1883",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "autoUnsubscribe": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    },
    {
        "id": "16ae73273064273e",
        "type": "mqtt-broker",
        "name": "",
        "broker": "192.168.0.125",
        "port": "1884",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "autoUnsubscribe": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthRetain": "false",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closeRetain": "false",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willRetain": "false",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    }
]

PS: Code updated 07/11/2023

You will get a flow like this

Log in to the zigbee2mqtt docker page URL

You will arrive on the Zigbee2Mqtt broker page

Select the zigbee2mqtt device to control, in this example it’s a NOUS A1Z outlet (device already controlled by Gladys but it’s just for the example :wink:) it’s named « NOUS-5 »

When you are on the settings page, go to the status tab, it shows the json exchanged between zigbee2mqtt and the outside, here we will use 2 values for the example

  • one (in-out) used to control the outlet on/off: state
  • another (out) that sends the outlet’s power consumption: power

    This is the json you will need to copy into the flow code if you need to adapt it for other hardware

Now let’s go back to node-red, you will find 2 code areas

The first one concerns the translation between the topic and payload from Gladys to the topic and payload expected by Zigbee2Mqtt

image

The second one concerns the translation between the topic and payload from Zigbee2Mqtt to the topic and payload expected by Gladys

image

In both cases, the values to change depending on the virtual mqtt device and the Zigbee2Mqtt hardware to control are in red

The configuration of the « mqqt » nodes (port 1883 for Mqtt, 1884 for Zigbee2Mqtt), you must have the IP address of your Gladys in the mqtt nodes so that the frames go out of the containers!

For port 1883, the username and password can be found in Gladys

For port 1884 (Zigbee2Mqtt), the username and password can be found in the « configuration.yaml » file located in the « var/lib/gladysassistant/zigbee2mqtt/z2m » directory in the « mqtt: » section
(It would be nice to be able to view it in the Zigbee2Mqtt integration :woozy_face: as we can see for Mqtt and Node-red :blush:)

If the values are correct, the « mqtt » nodes will appear « connected » in green

That’s it, in the Gladys dashboard you can switch the « Nous-5 » outlet using the virtual outlet « Z2M-NOUS-5 »

and see its consumption

That’s it, if you have any suggestions, improvements or errors, don’t hesitate… :wink:

PS: It’s thanks to information found on the forum, especially for the zigbee2mqtt password (@vonox in a discussion) (@Will_71 for the virtual device in his Somfy tutorial) that I was able to make this mini-tutorial

7 Likes