When I set bri=0 state, the state on=false is set. But the light itself is still on at minimal brightness. Like so:
$ PUT /lights/47/state '{ "on": true, "bri": 255, "transitiontime": 0 }' && GET /lights/47 | jq .
[{"success":{"/lights/47/state/on":true}},{"success":{"/lights/47/state/bri":255}}]
{
"ctmax": 454,
"ctmin": 250,
"etag": "edacb59cfb66980bc4aabe521d89ab8e",
"hascolor": true,
"manufacturername": "IKEA of Sweden",
"modelid": "TRADFRI bulb E27 WS opal 980lm",
"name": "Kantoor Dressoir",
"state": {
"alert": "none",
"bri": 255,
"colormode": "ct",
"ct": 454,
"on": true,
"reachable": true
},
"swversion": "1.2.217",
"type": "Color temperature light",
"uniqueid": "00:0b:57:ff:fe:f3:56:3c-01"
}
$ PUT /lights/47/state '{ "bri": 0, "transitiontime": 40 }' && GET /lights/47 | jq .
[{"success":{"/lights/47/state/bri":0}}]
{
"ctmax": 454,
"ctmin": 250,
"etag": "f7a9d8dbe2caff44e568613a82d8aebd",
"hascolor": true,
"manufacturername": "IKEA of Sweden",
"modelid": "TRADFRI bulb E27 WS opal 980lm",
"name": "Kantoor Dressoir",
"state": {
"alert": "none",
"bri": 0,
"colormode": "ct",
"ct": 454,
"on": false,
"reachable": true
},
"swversion": "1.2.217",
"type": "Color temperature light",
"uniqueid": "00:0b:57:ff:fe:f3:56:3c-01"
}
The behavior is the same regardless if I specify the transitiontime or not on the bri=0 state update.
I have found the same. Also the API returns an error if you try to manipulate 'bri' in the 'off' state.
This means you have to control 'on'/'off'/'bri' 'manually' and be careful not to send commands too close in time. If you do, the bulb may hang.
Did some sniffing how the Hue bridge handles state.on and state.bri. It would seem they changed it; at least it looks very different from what I think I remember. Square bridge on the lastest firmware, swversion: 1811120916 and apiversion: 1.29.0. Hue LTW010 color temperature light on the latest firmware, swversion: 1.46.13_r26312.
Body | Command(s)
----- | -------------
{"on": false} | _Off with Effect_ (0, 0)
{"on": false, "transitiontime":_t_} | _Move to Level (with On/Off)_ (0, _t_)
{"on": false", "bri":_b_} | _Move to Level_ (_b_, 4)
_Off with Effect_ (0, 0)
{"on": false", "bri":_b_, "transitiontime":_t_}
(bri seems to be ignored) | _Move to Level (with On/Off)_ (0, _t_)
{"on": true} | _On_
{"on": true, "transitiontime":_t_ }
(transitiontime seems to be ignored) | _On_
{"on": true, "bri":_b_}
(when state.on false) | _Move to Level (with On/Off)_ (2, 0)
_Move to Level_ (_b_, 4)
{"on": true, "bri":_b_}
(when state.on is true) | _On_
_Move to Level_ (_b_, 4)
{"on": true", "bri":_b_, "transitiontime":_t_}
(when state.on false) | _Move to Level (with On/Off)_ (2, 0)
_Move to Level_ (_b_, _t_)
{"on": true", "bri":_b_, "transitiontime":_t_}
(when state.on is true) | _On_
_Move to Level_ (_b_, _t_)
{"bri":_b_}| _Move to Level_ (_b_, 4)
{"bri":_b_, "transitiontime":_t_}| _Move to Level_ (_b_, _t_)
When "bri": 0 is specified, the _Move to Level_ parameter _Level_ is set to 0 (but the light remains on, and state.on remains true, and state.bri returns 1); when "bri": 255 is specified, _Level_ is set to 254. An explicit transitiontime of 4 is handled differently than a missing transitiontime. I see no special handling of transitiontime of 0.
While not intuitive, this behaviour makes total sense to me, except when turning the light off with a transitiontime. The light comes back on at bri 1 instead of at the previous or specified bri. It might be better to ignore the transitiontime when bri is not specified (similar to setting the light on) and to send `_Move to Level_ (_b_, _t_), followed by an _Off with Effect_ (0, 1) when it is.
Interesting: when state.on is false when setting state.bri, the REST API returns error: 201 parameter, bri, is not modifiable. Device is set to off., but the bridge still sends the _Move to Level_ command.
EDIT
The same commands seem to be sent when setting a group action, except that the group's state.all_on and state.any_on aren't considered. To turn the lights on, the _On_ command is sent always, never the _Move to Level (with On/Off)_ (2, 0).
I also noticed that when sending the following body to /lights/<lightid>/state, deCONZ will switch off the light instead of setting it to the lowest brightness.
{
"on": true,
"bri": 1
}
If you remove the on attribute or set bri to 2 instead, then it works correctly and the light is not switched off.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
@Thomas-Vos, Hue lights turn off when receiving a _Move to Level (with On/Off)_ (1, _t_). From the ZCL spec (section 3.10.2.4.5):
If any command that decreases CurrentLevel reduces it to the minimum level allowed by the device, the OnOff attribute of the On/Off cluster on the same endpoint, if implemented, SHALL be set to Off.
I suppose Hue treats 1 as the minimum allowed level, even though CurrentLevel can take values 0 to 254.
The Hue bridge handles {"on": true, "bri": 1} by sending a _Move to Level (with On/Off)_ (2, 0) to turn the light on at minimum brightness, and then a _Move to Level_ (1, 4) to set the brightness to 1 (see above table). The deCONZ REST API plugin sends a single _Move to Level (with On/Off)_ (1, _t_).
@manup I've been meaning to refactor setLightState() (and set GroupState()), but I'm not sure blindly copying the Hue bridge logic is the best way for non-Hue lights. We know there are lights that don't handle _Move to Level (with On/Off)_ correctly (see e.g. https://github.com/dresden-elektronik/deconz-rest-plugin/issues/1205).
We could whitelist the different light types and/or manufacturers and adapt the logic accordingly (as is done for ct for the IKEA Tr氓dfri colour bulb), but that will lead to issues with groups (see https://github.com/dresden-elektronik/deconz-rest-plugin/issues/1479). We could use the same whitelist for homogeneous groups (provided we keep track of the light types and/or manufacturers in a group), but there's no solution for heterogenous groups.
We definitely need to apply "on": true first (before setting brightness, colour (temperature), or effect) and "on": false last (so you can set the brightness and colour (temperature) the light should turn on to next time). We might provide a safety net, by sending _Move to Level (with On/Off)_ (2, 0) followed by _On_, followed by _Move to Level_ (_b_, _t_), but that is an additional ZigBee message.
In pseudo code (with whitelisting):
const tt = "transitiontime": t ? t : 4;
if ("on": true) {
if (Hue-like && !isOn) {
Move_to_Level_with_On_Off(2, 0);
} else {
On();
}
isOn = true;
}
if ("bri": b) {
if (!isOn) {
Error();
}
Move_to_Level(b, tt);
}
// handle `xy`, `ct`, `hs`, `_inc` variants, `effect`, `alert`, etc
if ("on": false) {
if (Hue-like) {
Off_with_Effect(0, 0);
} else {
Off();
}
}
or without whitelisting:
const tt = "transitiontime": t ? t : 4;
if ("on": true) {
Move_to_Level_with_On_Off(2, 0);
On();
isOn = true;
}
if ("bri": b) {
if (!isOn) {
Error();
}
Move_to_Level(b, tt);
}
// handle `xy`, `ct`, `hs`, `_inc` variants, `effect`, `alert`, etc
if ("on": false) {
Off_with_Effect(0, 0);
Off();
}
We could whitelist the different light types and/or manufacturers and adapt the logic accordingly (as is done for ct for the IKEA Tr氓dfri colour bulb), but that will lead to issues with groups (see #1479). We could use the same whitelist for homogeneous groups (provided we keep track of the light types and/or manufacturers in a group), but there's no solution for heterogenous groups.
Yes this might turn out really tricky, albeit possible my main concern here would be poor scaling. With the ever crowing network sizes > 100, unicast messages won't be perceived well. I think we should explore the groupcast path first.
We definitely need to apply "on": true first (before setting brightness, colour (temperature), or effect) and "on": false last (so you can set the brightness and colour (temperature) the light should turn on to next time). We might provide a safety net, by sending Move to Level (with On/Off) (2, 0) followed by On, followed by Move to Level (b, t), but that is an additional ZigBee message.
I like that approach, with careful timing to not trigger the IKEA transition time bug this could actually work well. The extra messages should be fine and compared to dozens of unicast messages, they don't look too bad.
Since this is a sequence of group casts, this screams to be implemented as a simple state machine within the related group scope.
Yes this might turn out really tricky, albeit possible my main concern here would be poor scaling. With the ever crowing network sizes > 100, unicast messages won't be perceived well. I think we should explore the groupcast path first.
Definitely - I sure as hell didn't mean to issue unicast messages for each member light when PUTting a group action. I was merely considering to keep track of the light types/manufacturers in a group, so we can apply the same whitelist as for PUTting light state to PUTting a group action for homegenous groups (with members of the same type/manufacturer). Still a pain in the neck, though.
We might provide a safety net, by sending Move to Level (with On/Off) (2, 0) followed by On, followed by Move to Level (b, t), but that is an additional ZigBee message.
I like that approach
The extra messages should be fine
Cool. I'll have a go at that, then.
with careful timing to not trigger the IKEA transition time bug this could actually work well.
As long as the first command(s) are sent with a transitiontime of 0, we should be OK.
Since this is a sequence of group casts, this screams to be implemented as a simple state machine within the related group scope.
Not sure I like the complexity of that. I haven't sniffed in detail how the Hue bridge handles bodies of {"on": true, "bri": 127, "ct": 300, "transitiontime": 10}. I would expect a sequence of:
or
For IKEA lights, we should either use a transitiontime of 0 for the second command, or issue the third command only after the transtion has completed. For the latter, we would need to keep a timer, or poll _Remaining Time_, neither of which seems like a particularly good idea. For either, the user experience would be different from Hue lights connected to the Hue bridge. I really don't want to sacrifice Hue functionality to work around IKEA issues. So we're back to whitelisting lights and homogenous groups, and not providing a solution for heterogenous groups.
For a next PUT, maybe we could issue a _Stop_ command to actively cancel any running transitions. Haven't tried that, though, so I don't yet know if the IKEA lights would accept that. We should also test how the IKEA light deals with colour transitions.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Most helpful comment
Did some sniffing how the Hue bridge handles
state.onandstate.bri. It would seem they changed it; at least it looks very different from what I think I remember. Square bridge on the lastest firmware,swversion: 1811120916 andapiversion: 1.29.0. Hue LTW010 color temperature light on the latest firmware,swversion: 1.46.13_r26312.Body | Command(s)
----- | -------------
{"on": false}| _Off with Effect_ (0, 0){"on": false, "transitiontime":_t_}| _Move to Level (with On/Off)_ (0, _t_){"on": false", "bri":_b_}| _Move to Level_ (_b_, 4)_Off with Effect_ (0, 0)
{"on": false", "bri":_b_, "transitiontime":_t_}(
briseems to be ignored) | _Move to Level (with On/Off)_ (0, _t_){"on": true}| _On_{"on": true, "transitiontime":_t_}(
transitiontimeseems to be ignored) | _On_{"on": true, "bri":_b_}(when
state.onfalse) | _Move to Level (with On/Off)_ (2, 0)_Move to Level_ (_b_, 4)
{"on": true, "bri":_b_}(when
state.onis true) | _On__Move to Level_ (_b_, 4)
{"on": true", "bri":_b_, "transitiontime":_t_}(when
state.onfalse) | _Move to Level (with On/Off)_ (2, 0)_Move to Level_ (_b_, _t_)
{"on": true", "bri":_b_, "transitiontime":_t_}(when
state.onis true) | _On__Move to Level_ (_b_, _t_)
{"bri":_b_}| _Move to Level_ (_b_, 4){"bri":_b_, "transitiontime":_t_}| _Move to Level_ (_b_, _t_)When
"bri": 0is specified, the _Move to Level_ parameter _Level_ is set to 0 (but the light remains on, andstate.onremains true, andstate.brireturns 1); when"bri": 255is specified, _Level_ is set to 254. An explicittransitiontimeof 4 is handled differently than a missingtransitiontime. I see no special handling oftransitiontimeof 0.While not intuitive, this behaviour makes total sense to me, except when turning the light off with a
transitiontime. The light comes back on atbri1 instead of at the previous or specifiedbri. It might be better to ignore thetransitiontimewhenbriis not specified (similar to setting the light on) and to send `_Move to Level_ (_b_, _t_), followed by an _Off with Effect_ (0, 1) when it is.Interesting: when
state.onis false when settingstate.bri, the REST API returnserror: 201 parameter, bri, is not modifiable. Device is set to off., but the bridge still sends the _Move to Level_ command.EDIT
The same commands seem to be sent when setting a group
action, except that the group'sstate.all_onandstate.any_onaren't considered. To turn the lights on, the _On_ command is sent always, never the _Move to Level (with On/Off)_ (2, 0).