Koenkk / Koenkk/zigbee2mqtt

Inverted logic for ZCL frame type handling in ZCL default response

Open
#32,571 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

problem stale
Dominant language
TypeScript
Stars
15.7k
Forks
2k
Avg merge
18h 55m
Merged PRs (30d)
35

Description

What happened?

I implement a custom Zigbee stack (it will be open-sourced soon once usable). I mostly test it with Z2M. During the testing I found this issue.

My sample device has a ZHA On/Off cluster input. For now I reply with a default response with "Unsupported Cluster Command" status. And here is the problem – when I accidentally set ZCL frame type to be "Cluster-specific", Z2M properly reacts to these responses, logging these messages:

[7/15/2026, 11:05:59 AM] frontend:api: Sending {"topic":"0xc001babedeadbeef/set","payload":{"state":"OFF"}}
[7/15/2026, 11:05:59 AM] z2m: Publish 'set' 'state' to '0xc001babedeadbeef' failed: 'Error: ZCL command 0xc001babedeadbeef/1 genOnOff.off({}, {"timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":false,"direction":0,"reservedBits":0,"writeUndiv":false}) failed (Status 'UNSUP_COMMAND' response genOnOff:11)'
[7/15/2026, 11:06:00 AM] frontend:api: Sending {"topic":"0xc001babedeadbeef/set","payload":{"state":"ON"}}
[7/15/2026, 11:06:00 AM] z2m: Publish 'set' 'state' to '0xc001babedeadbeef' failed: 'Error: ZCL command 0xc001babedeadbeef/1 genOnOff.on({}, {"timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":false,"direction":0,"reservedBits":0,"writeUndiv":false}) failed (Status 'UNSUP_COMMAND' response genOnOff:11)'
ZigBee Cluster Library Frame
    Frame Control Field: Cluster-specific (0x19)
        .... ..01 = Frame Type: Cluster-specific (0x1)
        .... .0.. = Manufacturer Specific: False
        .... 1... = Direction: Server to Client
        ...1 .... = Disable Default Response: True
    Sequence Number: 157

When I fix the default response frame to be properly set to "Profile wide" since "Default response" is not a cluster-specific command, Z2M no longer displays these errors:

[7/15/2026, 10:59:49 AM] z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/0xc001babedeadbeef', payload '{"linkquality":45,"state":"ON"}'
[7/15/2026, 10:59:54 AM] z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/0xc001babedeadbeef', payload '{"linkquality":60,"state":"OFF"}'

Howerver Wireshark now can properly decode the default responses:

ZigBee Cluster Library Frame, Command: Default Response, Seq: 1
    Frame Control Field: Profile-wide (0x18)
        .... ..00 = Frame Type: Profile-wide (0x0)
        .... .0.. = Manufacturer Specific: False
        .... 1... = Direction: Server to Client
        ...1 .... = Disable Default Response: True
    Sequence Number: 1
    Command: Default Response (0x0b)
    Response to Command: 0x00
    Status: Unsupported Cluster Command (0x81)

So it seems there is a problem in Z2M, it parses default responses when it should not and vice versa. I think it's worth checking it. It may cause other problems as well.

captures.zip

Z2M: 2.12.1 aa909a8a
zigbee-herdsman-converters version 26.76.0
zigbee-herdsman version 10.6.1
Coordinator ZStack3x0 0x00124b0022988ab4 Revision: 20210120

What did you expect to happen?

No response

How to reproduce it (minimal and precise)

No response

Zigbee2MQTT version

2.12.1

Adapter firmware version

20210120

Adapter

Electrolama

Setup

Plain

Device database.db entry

No response

Debug log

No response

Notes

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue does not name implementation files or tests. Start by locating the Zigbee ZCL default-response parsing path and compare handling of profile-wide versus cluster-specific frame types using the supplied captures; done means responses are accepted or ignored according to their frame type and regression coverage verifies both cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
embedded-iot, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.