Automated way to send Zigbee cluster command (Zigbee2MQTT)

Is it possible to programmatically send Zigbee commands in an automated way using the dashboard cards, scripts, automation, node red, or similar add-ons?

I’m using Z2M which can already do this manually through its dev console, but it’s manual and I’m not sure how to access it from anywhere other than inside Z2M.

My goal is to use HA in an automated way to reproduce Zigbee cluster commands that I can sniff on my network.

Example Message - Key Parameters
Note that I don’t know if Profile is needed and I don’t know the correct variable names for the rest.

{
  "DestinationEndpoint": "1",
  "Cluster": "0x0006",
  "Profile": "0x0104", //unsure if needed
  "Command": "0x02",
  "Attribute": "0x4003",
  "StartupOnOff": "0xff"
}

Example Message - Sniffed from Wireshark with nRF52840

ZigBee Application Support Layer Data, Dst Endpt: 1, Src Endpt: 64
    Frame Control Field: Data (0x00)
        .... ..00 = Frame Type: Data (0x0)
        .... 00.. = Delivery Mode: Unicast (0x0)
        ..0. .... = Security: False
        .0.. .... = Acknowledgement Request: False
        0... .... = Extended Header: False
    Destination Endpoint: 1
    Cluster: Level Control (0x0008)
    Profile: Home Automation (0x0104)
    Source Endpoint: 64
    Counter: 160
ZigBee Cluster Library Frame, Command: Write Attributes, Seq: 29
    Frame Control Field: Profile-wide (0x00)
        .... ..00 = Frame Type: Profile-wide (0x0)
        .... .0.. = Manufacturer Specific: False
        .... 0... = Direction: Client to Server
        ...0 .... = Disable Default Response: False
    Sequence Number: 29
    Command: Write Attributes (0x02)
    Attribute Field
        Attribute: Startup Level (0x4000)
        Data Type: 8-Bit Unsigned Integer (0x20)
        Startup Level: Set the CurrentLevel attribute to its previous value (0xff)

I’ve tried to send this command using the Node Red Pallete:node-red-contrib-zigbee2mqtt 2.6.4 but I can’t figure out how to add the cluster and command information.

I also found this example which uses ZHA, but I can’t build on it since I haven’t found a Z2M equivalent for the ZHA set_zigbee_cluster_attribute service call.

This zcl_cmd ZHA HACS extension is pretty much what I’m looking for, but for Z2M instead, and assuming zcl_cmd can be accessed from dashboard cards, scripts, automations, node red, etc.

Could you share what you did in the Dev Console? I’m trying to use it to execute some commands. I can’t even get a simple command to work.

There might be a way to publish a MQTT message that does what the Dev Console does. I’ve been exploring this for a couple of days but can’t even get Dev Console to do what I want.

I am able to use the top part of the Dev Console to read stuff. It’s the bottom bit where you can execute commands that I can’t get to work.

Sure I’d be happy to. Explaining what I’m trying to get HA/NR/other to replicate from the Z2M Dev Console probably helps add more context to my original question, but if you need extra extra details can you please PM me or link me to another post I can answer?

This is what I’m trying to make Home Assistant do at the press of a button, or from a command that can be used in automation. You have to know the cluster, command, and payload parameters that specific command needs.

Using the Fade to Off in 0.8s command as an example, you would set:

  • Endpoint = 1,
  • Cluster = 0x0006 (OnOff),
  • Command = 0x40 (Off with effect)
  • Payload =
{
"effectid":0,
"effectvariant":0
}

Just FYI, this command is what the Philips Hue Bridge uses to turn off lights instead of just 0x00 (Off).

The hard part is finding the correct variable names for the Payload. The cluster.ts file from Koenkk’s Zigbee-Herdsman project was a great help in that area. You’ll need to convert all your hex values to decimals in order to find them in this file. You probably need decimal for the payload syntax anyway.

You may also find this post helpful.

Using the HA MQTT service call, I believe this should work… Topic:

zigbee2mqtt/<your friendly name>/1/set

and the data is

{"command":{"cluster":6,"command":64,"payload":{"effectid":0,"effectvariant":0}}}

A tip. Instead of looking through cluster.ts what you can do is the following.

In the dev console, enter the cluster and command as you already do. For the payload enter 0 (no braces). Press execute. This should generate an error. Read what is missing in the error. It would be something such as missing key effectid. Change your payload to be {"effectid":0} and press execute. The error will then say something such as effectvariant is missing`. Add it to the payload. Etc. Etc, until you get a working command. It’s all very unintuitive! I figured this out from hours of reading and trail and error.

Thanks Gwww,

I’m hoping to test that soon, hopefully in the next few days. I can probably also get a dashboard card to use that MQTT command, or even node red. This will make testing my lights so much easier. I’ll let you know how it goes.

Using the dev console like that is a great idea! Especially if you’ve already seen what values to use when looking at the network traffic. e.g I knew both Effect ID and Effect Variant needed to be 0, but didn’t know the correct variable names.

Thanks Gwww. That worked really well from the Developer Tools where I can manually call services.
Since it works there, I put it in a standard button card. See below.
For some reason, in the the topic both /1/set and /set work. Maybe that will change if I add more than 1 light to my dev network.

Button Card:

show_name: true
show_icon: false
type: button
tap_action:
  action: call-service
  service: mqtt.publish
  data:
    topic: zigbee2mqtt/Z2M Test Light/set
    payload: |-
      { "command":{
        "cluster":6,
        "command":64,
        "payload":{
          "effectid":0,
          "effectvariant":0
          }
        }
      }
  target: {}
entity: light.z2m_test_light
hold_action:
  action: none
name: 'Fade to Off { 0x40: ( 0x00,0x00 ) }'
icon: ''
show_state: false

I also got this working in Node Red which I posted in the Github discussion link listed in one of my previous comments.

Hi @gwww
Would you happen to know how to send the Write Attributes command? My attempts send other commands for some reason.

I looked at my network traffic and found the parameters I’d like to copy.

  • Cluster: On/Off (0x0006)
  • Command: Write Attributes (0x02)
  • Attributes:
    • Attribute: StartUpOnOff (0x4003)
    • Data Type: 8-Bit Enumeration (0x30)
    • Startup On Off: Set the OnOff attribute to its previous value (0xff)

But this was the command that actually got sent.

  • Cluster: On/Off (0x0006)
  • Command: Toggle (0x02)

This is what I saw in my network traffic and tried to copy.

Frame 3: 50 bytes on wire (400 bits), 50 bytes captured (400 bits) on interface COM7, id 0
IEEE 802.15.4 Data, Dst: 0x1b6d, Src: 0x0000
ZigBee Network Layer Data, Dst: 0x1b6d, Src: 0x0000
ZigBee Application Support Layer Data, Dst Endpt: 1, Src Endpt: 1
    Frame Control Field: Data (0x00)
    Destination Endpoint: 1
    Cluster: On/Off (0x0006)
    Profile: Home Automation (0x0104)
    Source Endpoint: 1
    Counter: 90
ZigBee Cluster Library Frame, Command: Write Attributes, Seq: 58
    Frame Control Field: Profile-wide (0x10)
        .... ..00 = Frame Type: Profile-wide (0x0)
        .... .0.. = Manufacturer Specific: False
        .... 0... = Direction: Client to Server
        ...1 .... = Disable Default Response: True
    Sequence Number: 58
    Command: Write Attributes (0x02)
    Attribute Field
        Attribute: StartUpOnOff (0x4003)
        Data Type: 8-Bit Enumeration (0x30)
        Startup On Off: Set the OnOff attribute to its previous value (0xff)

This is what I tried to send. I hadn’t figured out how to send the attributes but I still excepted to send the correct command, which didn’t happen.

"topic":"zigbee2mqtt/Z2M Test Light/set"
{
    "command": {
        "cluster": 6,
        "command": 2,
        "payload": {
            "startUpCurrentLevel": 255
        }
    }
}

This is what I saw on the network after sending my own command.

Frame 6123: 46 bytes on wire (368 bits), 46 bytes captured (368 bits) on interface COM7, id 0
IEEE 802.15.4 Data, Dst: 0x1b6d, Src: 0x0000
ZigBee Network Layer Data, Dst: 0x1b6d, Src: 0x0000
ZigBee Application Support Layer Data, Dst Endpt: 1, Src Endpt: 1
    Frame Control Field: Data (0x00)
    Destination Endpoint: 1
    Cluster: On/Off (0x0006)
    Profile: Home Automation (0x0104)
    Source Endpoint: 1
    Counter: 91
ZigBee Cluster Library Frame
    Frame Control Field: Cluster-specific (0x01)
        .... ..01 = Frame Type: Cluster-specific (0x1)
        .... .0.. = Manufacturer Specific: False
        .... 0... = Direction: Client to Server
        ...0 .... = Disable Default Response: False
    Sequence Number: 59
    Command: Toggle (0x02)

No, I haven’t managed to figure out how to send commands. I asked on the discord forum and was told not the right place, find a Zigbee forum.

I’ll ponder the two messages you included above and see if that sparks some thoughts.

On the Zigbee2Mqtt GitHub site there’s a discussions tab. Maybe try there? If you tag me then I’ll be notified and can pitch in my experience.

Thanks @gwww ,

I couldn’t find you on GitHub to tag you, but here is a link to my post.
Can you please add to it? Any weight you can add to this would be very much appreciated, even if it’s just to show that more people would like an answer. I posted in the Z2M Discord but was told by Rene (who was very nice about it) that I wasn’t likely to get an answer on Discord.

Hi,

I need help with this. I have a device where I have to send a “wake up” via dev console to have updated values. In the Z2M dev console I can do this while sending this command:

Can anyone help to translate in the corresponding MQTT command? I have tried zigbee2mqtt/Poolmeter/1/set with this command “{“command”:{“cluster”:0xEF00,“command”:0x03,“payload”:{}}}” without success.

Edit: With the Z2M Logs I found the suitable command and it is working now.

@Flitzpiepe I have the same PoolMonitor and use the following topic to trigger a new sensor read:

{
  "command": {
    "cluster": 61184,
    "command": 3,
    "payload": 1
  }
}

how to execute your example ?

action: mqtt.publish
data:
  qos: 0
  retain: false
  topic: homeassistant/water quality/1/set
  payload: |-
    {
      "command": {
        "cluster": 61184,
        "command": 3,
        "payload": 1
      }
    }

I answer myself, here’s how to call the device to refresh its values…

the correct way to send message for my water quality sensor is :slight_smile:

action: mqtt.publish
data:
  topic: zigbee2mqtt/water quality/1/set
  payload: |-
    {
      "command": {
        "cluster": 61184,
        "command": 3,
        "payload": {}
      }
    }

the name in zigbee2mqtt is : water quality
the device is : https://www.zigbee2mqtt.io/devices/BLE-YL01.html#tuya-ble-yl01

hope this helps other sensor users