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.brito 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 and config.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.