Zigbee - How to: Efficiently reading / writing Multiple Attributes

I'm working on optimizing some zigbee drivers and have a few questions.

As I understand it, it should be possible to send a command to a Zigbee device to read mutliple attributes in a cluster at once. However, the example code I've seen all reads a single attribute at a time. For example, for reading color attributes, code like the following is common:

            "he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0300 0x0000 {}", //hue
            "he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0300 0x0001 {}", //sat
            "he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0300 0x0007 {}",	//color temp
            "he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0300 0x0008 {}"  		//color mode

I've tried specifying multiple attributes in a single command like:

            "he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0300 0x0000 0x0001 0x0007 0x0008 {}", 

and

            "he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0300 0x0000000100070008 {}", 

But that doesn't seem to work. Anybody know how this should be done?

Also, does anybody know what the brackets "{}" at the end of the he rattr string are for? Maybe there are options that go in there, but I can't find any documention of the he command.

Similarly, according to section 2.5.16 of the Zigbee cluster specification, I understand that it should be possible to write multiple attributes at once.

So, as a common example, if I wanted to set Hue, Saturation, Color Temp, and Color Mode attributes of the color cluster (0x0300), rather than 4 separate commands, I should be able to do that more efficiently with a single write to all the attributes. Anybody know how?

Would there be a way to set the "raw" format of the command and just have Hubitat send that. I.e., for some common commands like color, it might be simple enough to format it myself if the hubitat methods can't support this.

This is a sample code for reading multiple attributes in one command

cmds += zigbee.readAttribute(0x0000, [0x0004, 0x000, 0x0001, 0x0005, 0x0007, 0xfffe], [:], delay=200) // Cluster: Basic, attributes: Man.name, ZLC ver, App ver, Model Id, Power Source, attributeReportingStatus
Writing requires separate commands for each attribute, as the data may be of a different type.

2 Likes

Thank you. That's what I was looking for. Seems to work perfectly!

Another question: what's the "[:]" for? are there options that can be put in there or something?

Also, for the status 0xfffe, on a color bulb report, I get:

['status':'86', 'attrId':'FFFE', 'attrInt':65534]

I found an attributeReportingStatus attribute in 2.3.5.1.2 of the zigbee cluster specification, but it doesn't seem to match these values. Am I looking in the wrong place for the meaning of this?

And finally, the reading of attributes generally follows setting them - for example, after setting color or level to confirm what was set (at least that's how it is in public drivers on the Hubitat github). I also notice in the zigbee spec. section 2.5, you can configure reporting for attributes. Is it possible to simply configure a device to report anew attribute for things like on, setting levels, color, etc. immediately after it gets set, or is the manual polling necessary? If a device can be configured to automatically generate a report, it seems this would be much more efficient than querying it after each set.

Again, thanks for your help.

This map can contain additional parameters, the only one that I am aware of and using in some of my drivers is the manufacturer code, where required:

    if (isT1()) {             // RTCGQ12LM Aqara T1 human body movement and illuminance sensor
        cmds += zigbee.readAttribute(0x0001, 0x0020, [:], delay=200)     
        cmds += zigbee.readAttribute(0xFCC0, 0x0102, [mfgCode: 0x115F], delay=200)
    }

Note, that the Aqara manufacturer code is required only for the Aqara custom cluster FCC0.

On the basic cluster 0xFFFE attribute - it's usage is specific for Tuya devices. Reading it is a part of the 'Tuya Magic' spell that unlocks some Tuya devices and they start to use the standard ZCL clusters, instead of the Tuya proprietary EF00 cluster and 'data points'. In your case, the status code returned 0x86 means 'not supported', and this is expected for non-Tuya devices.

Whether a specific attribute can be configured to be reported automatically by the devices depends solely on the device firmware. Typically, automatic reporting can be configured for attributes that are measured by the device itself - like battery percentage remaining, temperature, humidity, power, voltage, etc.... Attributes that are configured by the Zigbee coordinator (like level, color, etc..) are usually not reported back.

1 Like

Thanks again. This has been very helpful.

1 Like

As @kkossev mentioned its completely up to the device how reporting is offered. Some devices don't even support timers to do the reporting on a frequency. Generally to test I try and configure reporting on a bunch of cluster/attributes and see what the response is. Often its UNSUPPORTED or another similar error.

I've had one device that only supports report configurations on non useful attributes. The SAGE doorbell sensor won't accept reporting on anything except the Basic/Manufacturer name (0x0004) attribute (returns "Echostar"). I ended up using it as a device-health checkin as all the other what-you'd-think-would-make-sense attributes rejected any requests for reporting.

Two follow-ups if you can help. . . .

  1. If I wanted to read multiple attributes from a specific endpoint, how would that be done? I don't see where in the zigbee.readAttribute you specify an endpoint (I assume it might be an option in the [:] options list, but I can't find documentation.

  2. I noticed there is also a "he raw" command which I assume I can use to do #1 in raw form, but I can't find any documentation on how it is formatted. Is there documentation for this anywhere? I tried looking in the forums and through old SmartThings documentation sites, but I didn't find anything clear on this.

By way of example on #2, I found:

zigbee.readAttribute(0x0006, [0x0000, 0x4000, 0x4001, 0x4002, 0x4003, 0x4004], [:], 0)

corresponds to a he raw of

he raw 0x5580 1 0x01 0x0006 {10 00 00 00 00 00 40 01 40 02 40 03 40 04 40}

Breaking this down, it seems to be . . .
0x5580 is the device.networkId

I'm assuming the "1 0x01" that follows may be a command specifier and endpoint (if that's correct, then which is which?),

0x0006 is the cluster

10 00 00 (I don't know what this is -- again, this is where I need help)

and the remaining 00 00 00 40 01 40 02 40 03 40 04 40 is the list of attributes in byte-swapped form.

Hi @jvm33 ,

I suppose that the zigbee.readAttribute command uses the default endpoint ( ${device.endpointId} )

There is a good example for using the "he raw" command here :

Here is an example from my FP1 driver :

cmds += ["he raw 0x${device.deviceNetworkId} 0 0 0x8002 {40 00 00 00 00 40 8f 5f 11 52 52 00 41 2c 52 00 00} {0x0000}", "delay 50",]

where it simulates the node descriptor response from Aqara E1 zigbee hub:

Frame 189: 62 bytes on wire (496 bits), 60 bytes captured (480 bits) on interface \\.\pipe\zboss_sniffer_COM6, id 0
IEEE 802.15.4 Data, Dst: 0xd022, Src: 0x0000
ZigBee Network Layer Data, Dst: 0xd022, Src: 0x0000
ZigBee Application Support Layer Data, Dst Endpt: 0, Src Endpt: 0
    Frame Control Field: Data (0x40)
    Destination Endpoint: 0
    Node Descriptor Response (Cluster ID: 0x8002)
    Profile: ZigBee Device Profile (0x0000)
    Source Endpoint: 0
    Counter: 253
ZigBee Device Profile, Node Descriptor Response, Rev: 22, Nwk Addr: 0x0000, Status: Success
    Sequence Number: 1
    Status: Success (0)
    Nwk Addr of Interest: 0x0000
    Node Descriptor
        .... .... .... .000 = Type: 0 (Coordinator)
        .... .... .... 0... = Complex Descriptor: False
        .... .... ...0 .... = User Descriptor: False
        .... 0... .... .... = 868MHz BPSK Band: False
        ..0. .... .... .... = 902MHz BPSK Band: False
        .1.. .... .... .... = 2.4GHz OQPSK Band: True
        0... .... .... .... = EU Sub-GHz FSK Band: False
        Capability Information: 0x8f
            .... ...1 = Alternate Coordinator: True
            .... ..1. = Full-Function Device: True
            .... .1.. = AC Power: True
            .... 1... = Rx On When Idle: True
            .0.. .... = Security Capability: False
            1... .... = Allocate Short Address: True
        Manufacturer Code: 0x115f
        Max Buffer Size: 82
        Max Incoming Transfer Size: 82
        Server Flags: 0x2c41
        Max Outgoing Transfer Size: 82
        Descriptor Capability Field: 0x00

0000   40 00 02 80 00 00 00 fd 01 00 00 00 00 40 8f 5f
0010   11 52 52 00 41 2c 52 00 00

I was able to figure it out (I got lucky and found a reference in an old SmartThings driver). To use an endpoint other than 1, you add a destEndpoint option to the option Map like this . . .

	cmds += zigbee.readAttribute(0x0008, [0x0000, 0x0001, 0x0010, 0x0012, 0x0013], [destEndpoint:ep], 0)

where 'ep' is the endpoint

I only wish there was a source showing every available option. I wonder what else is useful in there!

6 Likes