Get after Set captures transitional value rather than final value for some devices
See original GitHub issueWhen changing the value of dimmers using the commandClass .set command, I get a value updated
event for currentValue on a slightly-changed transitional brightness value as the dimmer smoothly transitions from off=>on or on=>off. I would expect it to receive the final value state, or keep updating until the final state is reached.
I have seen references to a property called targetValue, but that is always undefined for my devices. Is this something I should be seeing? Is it Z-Wave Plus?
I expect this might be a fluke with the type of wall module I use, so the question might be whether the zwave-js library should attempt to refresh the value after a delay, or that should be handled by the application code. I am fine handling it on my side if it is a legacy device issue that you do not want to support.
REPL example:
zwave.controller.nodes.get(15).commandClasses[38].get().then(console.log)
> { currentValue: 0, targetValue: undefined, duration: undefined }
zwave.controller.nodes.get(15).commandClasses[38].set(255)
[`value updated` called for node 15 with {commandClassName: "Multilevel Switch", propertyName: "currentValue", newValue: 2}]
// At this point, the light reaches its final brightness
zwave.controller.nodes.get(15).getValue({commandClass: 0x26, endpoint: 0, property: "currentValue"})
> 2
// The light now reports currentValue of 2 until I call Multilevel Switch .get()
zwave.controller.nodes.get(15).commandClasses[38].get().then(console.log)
> { currentValue: 97, targetValue: undefined, duration: undefined }
[`value updated` called for node 15 with {commandClassName: "Multilevel Switch", propertyName: "currentValue", newValue: 97}]
Device cache:
"15": {
"id": 15,
"interviewStage": "Complete",
"deviceClass": {
"basic": 4,
"generic": 17,
"specific": 1
},
"isListening": true,
"isFrequentListening": false,
"isRouting": true,
"maxBaudRate": 40000,
"isSecure": false,
"isBeaming": true,
"version": 4,
"commandClasses": {
"0x26": {
"name": "Multilevel Switch",
"isSupported": true,
"isControlled": false,
"version": 1,
"values": [
{
"endpoint": 0,
"property": "currentValue",
"value": 0
},
{
"endpoint": 0,
"property": "interviewComplete",
"value": true
}
]
},
"0x27": {
"name": "All Switch",
"isSupported": true,
"isControlled": false,
"version": 0
},
"0x70": {
"name": "Configuration",
"isSupported": true,
"isControlled": false,
"version": 1,
"values": [
{
"endpoint": 0,
"property": 3,
"value": 0
},
{
"endpoint": 0,
"property": 4,
"value": 0
},
{
"endpoint": 0,
"property": 5,
"value": 1
},
{
"endpoint": 0,
"property": 7,
"value": 1
},
{
"endpoint": 0,
"property": 8,
"value": 3
},
{
"endpoint": 0,
"property": 9,
"value": 1
},
{
"endpoint": 0,
"property": 10,
"value": 3
},
{
"endpoint": 0,
"property": 11,
"value": 1
},
{
"endpoint": 0,
"property": 12,
"value": 3
},
{
"endpoint": 0,
"property": "interviewComplete",
"value": true
}
],
"metadata": [
{
"endpoint": 0,
"property": 3,
"metadata": {
"type": "number",
"readable": true,
"writeable": true,
"valueSize": 1,
"min": 0,
"max": 255,
"default": 0,
"format": 1,
"allowManualEntry": false,
"states": {
"0": "LED on when switch is OFF",
"1": "LED on when switch is ON",
"2": "LED always off"
},
"label": "Night Light",
"description": "Night Light",
"isFromConfig": true
}
},
{
"endpoint": 0,
"property": 4,
"metadata": {
"type": "number",
"readable": true,
"writeable": true,
"valueSize": 1,
"min": 0,
"max": 255,
"default": 0,
"format": 1,
"allowManualEntry": false,
"states": {
"0": "No",
"1": "Yes"
},
"label": "Invert Switch",
"description": "Invert Switch",
"isFromConfig": true
}
},
{
"endpoint": 0,
"property": 5,
"metadata": {
"type": "number",
"readable": true,
"writeable": true,
"valueSize": 1,
"min": 0,
"max": 255,
"default": 0,
"format": 1,
"allowManualEntry": false,
"states": {
"0": "No",
"1": "Yes"
},
"label": "Ignore Start-Level (Receiving)",
"description": "This dimmer will start dimming from its current level.",
"isFromConfig": true
}
},
{
"endpoint": 0,
"property": 7,
"metadata": {
"type": "number",
"readable": true,
"writeable": true,
"valueSize": 1,
"min": 1,
"max": 99,
"default": 1,
"format": 0,
"allowManualEntry": true,
"label": "On/Off Command Dim Step",
"description": "On/Off Command Dim Step",
"isFromConfig": true
}
},
{
"endpoint": 0,
"property": 8,
"metadata": {
"type": "number",
"readable": true,
"writeable": true,
"valueSize": 1,
"min": 1,
"max": 255,
"default": 3,
"format": 1,
"allowManualEntry": true,
"label": "On/Off Command Dim Rate",
"description": "On/Off Command Dim Rate",
"isFromConfig": true
}
},
{
"endpoint": 0,
"property": 9,
"metadata": {
"type": "number",
"readable": true,
"writeable": true,
"valueSize": 1,
"min": 1,
"max": 99,
"default": 1,
"format": 0,
"allowManualEntry": true,
"label": "Local Control Dim Step",
"description": "Local Control Dim Step",
"isFromConfig": true
}
},
{
"endpoint": 0,
"property": 10,
"metadata": {
"type": "number",
"readable": true,
"writeable": true,
"valueSize": 1,
"min": 1,
"max": 255,
"default": 3,
"format": 1,
"allowManualEntry": true,
"label": "Local Control Dim Rate",
"description": "Local Control Dim Rate",
"isFromConfig": true
}
},
{
"endpoint": 0,
"property": 11,
"metadata": {
"type": "number",
"readable": true,
"writeable": true,
"valueSize": 1,
"min": 1,
"max": 99,
"default": 1,
"format": 0,
"allowManualEntry": true,
"label": "ALL ON/ALL OFF Dim Step",
"description": "ALL ON/ALL OFF Dim Step",
"isFromConfig": true
}
},
{
"endpoint": 0,
"property": 12,
"metadata": {
"type": "number",
"readable": true,
"writeable": true,
"valueSize": 1,
"min": 1,
"max": 255,
"default": 3,
"format": 1,
"allowManualEntry": true,
"label": "ALL ON/ALL OFF Dim Rate",
"description": "ALL ON/ALL OFF Dim Rate",
"isFromConfig": true
}
}
]
},
"0x72": {
"name": "Manufacturer Specific",
"isSupported": true,
"isControlled": false,
"version": 1,
"values": [
{
"endpoint": 0,
"property": "manufacturerId",
"value": 99
},
{
"endpoint": 0,
"property": "productType",
"value": 18756
},
{
"endpoint": 0,
"property": "productId",
"value": 12337
},
{
"endpoint": 0,
"property": "interviewComplete",
"value": true
}
]
},
"0x73": {
"name": "Powerlevel",
"isSupported": true,
"isControlled": false,
"version": 0
},
"0x77": {
"name": "Node Naming and Location",
"isSupported": true,
"isControlled": false,
"version": 0
},
"0x86": {
"name": "Version",
"isSupported": true,
"isControlled": false,
"version": 1,
"values": [
{
"endpoint": 0,
"property": "libraryType",
"value": 6
},
{
"endpoint": 0,
"property": "protocolVersion",
"value": "3.40"
},
{
"endpoint": 0,
"property": "firmwareVersions",
"value": [
"3.35"
]
},
{
"endpoint": 0,
"property": "interviewComplete",
"value": true
}
]
}
}
},
Issue Analytics
- State:
- Created 4 years ago
- Comments:28 (23 by maintainers)
Top GitHub Comments
A bit of a warning with all the HA/OZW refugees incoming… this is one of the most commonly encountered issues I’ve seen with HA/OZW. The result is that the switch state in HA will appear off or on when it is physically in the opposite state. A search of the community forum shows dozens of threads of people complaining about the issue. It’s come up in the HA Discord too many times to count as well.
OZW tried to solve this with the VerifyChanged device compatibility flag. This issue tracks the implementation of the value refresh that was never finished properly. There are problems with the unfinished implementation.
Consider the difference between devices that are Multilevel Switch V1-V3 (no target value reported) vs. Multilevel Switch V4+ (target value reported). If there is no target value in the report, are you able to reliably track the desired target (what happens if a new Set is sent in the meantime, or if the switch is toggled locally)? Or would you need to take the approach of OZW and refresh until the current value is stable? With the target in the report it’s much more straightforward. The spec has a note about the current value in the report:
I’m not 100% of the interpretation, but I’m leaning towards it saying that you cannot compare the current value to any value from a Set to determine if a transition has ended.
It can also be an issue if you poll too quickly (250ms makes my GE’s perform erratically, 10-12 GETs for a single change, but the refresh does get the final value eventually) and if toggle more than one light (or worse a roller-shade) at a time.
You might also consider the duration that is being set. If it’s 0xFF (factory default) then you might expect it to change fairly quickly, except of course my GE switches take a few seconds to turn on or off. What if the user sets a duration that is 1 minute? Do you refresh after the 1 minute, or some interval in-between? Should the refresh interval scale by the duration? etc.
relevant PR for those following along: https://github.com/zwave-js/node-zwave-js/pull/1522