Philips Hue sniffing - dresden-elektronik/deconz-rest-plugin GitHub Wiki
For now, this page is just my scrap notes sniffing the Hue bridge.
I'm testing using a 2nd gen Hue bridge on swversion
1707040932 with a LCT003 Hue color spot (extended color light) on swversion
5.50.1.19085.
Add a light to the Hue bridge
Recover the network key from the Transport Key APS frame.
Light Polling
The Hue bridge continuously sends a series of Read attribute (0x00) commands to the light: one for the On/Off cluster, one for the Level Control cluster and one for the Color Control cluster. Here's the relevant packages:
1. dstEp: 0x0B, clusterId: 0x0006, profileId: 0x0104, srcEp: 0x40, zclCommandType: 0x00, attributesList: [ 0x0000 ]
2. dstEp: 0x40, clusterId: 0x0006, profileId: 0x0104, srcEp: 0x0B, zclCommandType: 0x01, attributesStatusList: [ 0x0000 ]
3. dstEp: 0x0B, clusterId: 0x0008, profileId: 0x0104, srcEp: 0x40, zclCommandType: 0x00, attributesList: [ 0x0000 ]
4. dstEp: 0x40, clusterId: 0x0008, profileId: 0x0104, srcEp: 0x0B, zclCommandType: 0x01, attributesStatusList: [ 0x0000 ]
5. dstEp: 0x0B, clusterId: 0x0300, profileId: 0x0104, srcEp: 0x40, zclCommandType: 0x00, attributesList: [ 0x0007, 0x4000, 0x0001, 0x0003, 0x0004, 0x0008, 0x4002 ]
6. dstEp: 0x40, clusterId: 0x0300, profileId: 0x0104, srcEp: 0x0B, zclCommandType: 0x01, attributesStatusList: [ 0x0007, 0x4000, 0x0001, 0x0003, 0x0004, 0x0008, 0x4002 ]
The On/Off (0x0006) and Level Control (0x0008) clusters are pretty straightforward. The Color Control (0x0300) provides some nice insight: the bridge uses attributes Color Temperature (0x0007), Enhanced Current Hue (0x4000), Current Sat (0x0001), Current X (0x0003), Current Y (0x0004), Color Mode (0x0008), and Color Loop Active (0x4002).
During longer transitions, the light reports the actual values it currently displays, not the target values specified by commands. This allows you to monitor the transition, as long as the bridge polls the light frequently enough (about once per second with one light connected to the bridge).
Set Light State
state.on
The value of state.on
matches the value of 0x0006/0x0000.
Setting state.on
to true
results in an On (0x0006/0x01) command, without any parameters. The state.transition
seems to be ignored here.
Setting state.on
to false
without specifying state.transitiontime
results in an Off with Effect (0x0006/0x40) command, with parameters effectIdentifier set to Delayed all off
(0x00) and effectVariant to 0x00.
Setting state.on
to false
while specifying state.transitiontime
in a Move to Level (with On/Off) (0x0008/0x04) command, with parameters for the level (0x00) and the transition time. Even specifying the default transition time (4), results in this command.
Note: this behaviour was also observed through the bug in the older OSRAM firmware, where the light would only turn off when specifying a transition time of 0.
state.bri
The value of state.bri
matches the value of attribute 0x0008/0x0000.
Setting state.bri
results in a MovetoLevel (0x0008/0x00) command, with parameters for level (the value specified) and transition time. The bridge provides the default transition time.
Setting state.bri
to 255 results in a command with a level of 0xFE, so the bridge has already translates this to 254. Setting state.bri
to 0 results in a command with a level of 0x00, but on subsequent read, the light reports 0x01 for attribute 0x0008/0x0000.
Setting state.bri_inc
results in a Step (0x0008/0x02) command, with parameters for stepMode (0x00 for Up or positive values; 0x01 for Down or negative values), stepSize (the value specified), and transTime. The bridge provides the default transition time. Setting state.bri_inc
to 0 results in a Stop (0x0008/0x03) command.
With longer transition times, the light reports the actual state on each read, rather than the target state.
state.ct
The value of state.ct
matches the value of attribute 0x0300/0x0007.
Setting state.ct
results in a 0x0300/0x0A command with parameters for the color temperature and the transition time. When no state.transitiontime
is specified, the bridge provides the default value (0x0004).
Setting state.ct_inc
results in a 0x0300/0x4C command with parameters for the direction, value, transition time, and four additional bytes holding 0. Direction is 0x01 for positive values, and 0x03 for negative values. Setting state.ct_inc
to 0 results in the same command, with direction 0x03 and value 0x0000.
state.hue
The value of state.hue
matches the value of attribute 0x0300/0x4000.
Setting state.hue
results is an Enhanced move to hue (0x0300/0x40) command, with parameters for enhancedHue, direction and transTime. The value for direction is 0x00. When state.transitiontime
is not specified, the bridge provides the default value (0x0004).
Setting state.hue_inc
results in an Enhanced step hue (0x0300/0x42) command, with parameters for stepMode, stepSize, and transition time. The value for stepMode is 0x01 for positive values, and 0x03 for negative values. Setting state.hue_inc
to 0 results in a Stop move step (0x0300/0x47) command.
state.sat
The value of state.sat
is baed on the value of attribute 0x0300/0x0001.
Setting state.sat
results in a Move to saturation (0x0300/0x03) command, with parameters saturation and transTime. When no state.transitiontime
is specified, the bridge provides the default value (0x0004). Setting state.sat
to 255 results in a saturation parameter of 254.
Setting state.sat_inc
results in a Step saturation (0x0300/0x05) command, with parameters stepMode, stepSize, and transTime. The value of stepMode is 0x01 for positive values and 0x03 for negative values. Setting state.sat_inc
to 0 results in a Stop move step (0x0300/0x47) command.
state.xy
The value of state.xy
is based on the values of 0x0300/0x0003 (state.xy[0]
) and 0x0300/0x0004 (state.xy[1]
). The Hue bridge reports fixed point values in the range 0.0000..1.0000, where the 0x0300 attributes hold 16-bit integer values 0x0000 - 0xFFFF. The conversion is straigtforward: bridge_value = zigbee_value / 0xFFFF, rounded to four decimals.
Setting state.xy
results in a Move to color (0x0300/0x07) command, with parameters colorX, colorY and transTime. The value for colorX is state.xy[0]
* 0xFFFF, the value for colorY is state.xy[1]
* 0xFFFF. The value of transTime is the value of state.transitiontime
, or 4 when state.transitiontime
is not specified.
Setting state.inc_xy
results in a Step color (0x0300/0x09) command, with parameters stepX, stepY, and transTime. The value for stepX is the value of state.inc_xy[0]
* 0xFFFF as a signed integer (0x8000 for -0.5, 0x0000 for 0.0, and 0x7FFF for 0.5). Similarly, the value for stepY is based on the value of state.inc_xy[1]
. The value of transTime is the value of state.transitiontime
, or 4 when state.transitiontime
is not specified. Setting state.inc_xy
to [0.0, 0.0]
results in a Stop move step (0x0300/0x47) command.
state.colormode
The value of state.colormode
matches the value of attribute 0x0300/0x0008. This is a read-only attribute.
state.alert
Setting state.alert
to select
results in two Trigger effect (0x0003/0x40) commands. The first with parameters effectIdentifier Breathe
(0x01) and effectVariant Default
(0x00). The second with Finish effect
(0xFE) and, again, Default
(0x00). The second command is sent immediately (30ms) after the first. Setting state.alert
to lselect
results in only the first command, which causes the light to breathe for 15s. Setting state.alert
to none
results in only the seconds command.
Apparently the innr PL 110 / UC 110 control boxes don't like the Finish effect command (too soon after the Breathe): they hang on select
, but not on lselect
.
Hue Motion Sensor
Loads of traffic - will take some time to sort out in full.
- I see several ZDO: BindReq requests from the bridge to the motion sensor for the usual clusters: 0x0400, 0x0402, 0x0406, 0x0001; but also for: 0x0000.
- I see several ZCL: Configure reporting requests, from the bridge to the motion sensor, for the usual attributes: 0x0400/0x0000, 0x0402/0x0000, 0x0406/0x0000, 0x0001/0x0021; but also for: 0x0000/0x0033, 0x0000/0x0032, 0x0406/0x0030.
- I see several ZCL: Report attribute commands from the motion sensor to the bridge: for attributes: 0x0406/0x0000, 0x0402/0x0000, 0x0400/0x0000, 0x0001/0x0021, but also for: 0x0000/0x0033, 0x0406/0x0030. More or less consistent with the reporting configuration - maybe I just missed the 0x0000/0x0032 in the capture.
- I see several ZCL: Read attribute response commands: for 0x0000/0x0030, 0x0000/0x0033, 0x0000/0x0032, 0x0406/0x0030, 0x0406/0x0031. I suspect the 0x0406/0x0030 and 0x0406/0x0031 to be
config.sensitivity
andconfig.sensitivitymax
- both have value 0x02. - I see two ZCL: Identify commands with identifyTime of 0x000F - the sensor blinks after joining the network.
Indeed, setting config.sensitivity
on the ZLLPresence sensor sends a Write attributes (0x02) command to 0x0406/0x030. Value 0x00 for low, 0x01 for medium and 0x02 for high. 0x0000/0x0032 (type 0x10) is config.usertest
. 0x0000/0x0033 (type 0x10) is config.ledindication
.
This leads to the following mapping of API attributes to ZCL attributes:
Attribute | Cluster | Attribute | Data Type | |
---|---|---|---|---|
state.presence |
R | 0x0406 | 0x0000 | 8-bit bitmap (0x18) |
state.lightlevel |
R | 0x0400 | 0x0000 | uint16 (0x21) |
state.dark |
R | -- | -- | bool |
state.daylight |
R | -- | -- | bool |
state.temperature |
R | 0x0402 | 0x0000 | int16 (0x29) |
state.lastupdated |
R | -- | -- | string |
config.on |
RW | -- | -- | bool |
config.battery |
R | 0x0001 | 0x0021 | uint8 (0x20) |
config.reachable |
R | -- | -- | bool |
config.alert |
W | 0x0003 | -- | string |
config.ledindication |
RW | 0x0000 | 0x0033 | bool (0x10) |
config.usertest |
RW | 0x0000 | 0x0032 | bool (0x10) |
config.duration * |
RW | 0x0406 | 0x0010 | uint16 (0x21) |
config.sensitivity |
RW | 0x0406 | 0x0030 | uint8 (0x20) |
config.sensitivitymax |
R | 0x0406 | 0x0031 | uint8 (0x20) |
config.tholddark |
RW | -- | -- | uint16 |
config.tholddaylight |
RW | -- | -- | uint16 |
*) not supported by the Hue bridge.
config.alert
Setting config.alert
to select
results in an Identify (0x0003/0x00) command with an identifyTime parameter with value 0x0002. Setting state.alert
to lselect
results in the same command, but now with an identifyTime of 0x000F.