-
-
Notifications
You must be signed in to change notification settings - Fork 634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Get after Set captures transitional value rather than final value for some devices #452
Comments
I'll need to read the specs to see if there's something about this case. Your device does not support the Association CC, so it won't report the continuous changes by itself. |
This seems to be a larger problem in OpenZWave aswell. They solve it by regularly polling these kinds of devices. I'll need to figure out which interval to use and when to stop. |
I have a similar issue with the HS-WD100+ as well. And interestingly enough, I only get a final value with either manual control or remote control - I forget which. But the HS-FC200+ only sends the final value. I don't have an HS-WD200+ to know if they updated it. What I did to handle this is put a debounce on receiving updates before I send "the final value". When that expires I do a refresh at the end just in case it doesn't send a final value. I've pleaded with HomeSeer to issue a firmware update for the final-value issue but they are slow and seem to be more interested in updating their 200 line. Kind of discouraging considering these devices are expensive. |
What I can think of is:
Thoughts? |
This is code from my system that currently uses OpenZWave. I have a generic multilevel class, and then I optionally use an extended version for the HD-WD100+ switches. (I kind of consider this a device bug more than anything else. If you handled it, I would probably just have the user turn it on a case by case basis. Because even the same device might not have the same bug after a firmware update.) import {ValueId} from "openzwave-shared"
import {Attribute} from "../../"
import {
CC_SWITCH_MULTILEVEL,
CommandClass,
unhandledAttributeError,
} from "../cc"
export default class MultiLevel extends CommandClass {
protected on = false
protected level = 0
declare(vi: ValueId, value: boolean | number | string): void {
if (vi.class_id === CC_SWITCH_MULTILEVEL && vi.index === 0) {
this.level = value as number
this.on = this.level > 0
}
}
update(vi: ValueId, value: boolean | number | string): void {
if (vi.class_id === CC_SWITCH_MULTILEVEL && vi.index === 0) {
this.updateLevel(value as number)
}
}
input(attribute: Attribute): void {
switch (attribute.type) {
case "on":
this.emitter.emit(
"input",
{
node_id: this.nodeId,
class_id: CC_SWITCH_MULTILEVEL,
instance: 1,
index: 0,
},
attribute.value ? 255 : 0
)
break
case "level":
this.emitter.emit(
"input",
{
node_id: this.nodeId,
class_id: CC_SWITCH_MULTILEVEL,
instance: 1,
index: 0,
},
Math.max(0, attribute.value - 1)
)
break
default:
throw unhandledAttributeError(attribute)
}
}
attributes(): Attribute[] {
return [
{
type: "on",
value: this.on,
},
{
type: "level",
value: this.level + 1,
},
]
}
protected updateOn(value: boolean): void {
if (this.on !== value) {
this.on = value
this.emitter.emit("change", this.nodeId, {
type: "on",
value: this.on,
})
}
}
protected updateLevel(value: number): void {
if (this.level !== value) {
this.level = value
const on = value > 0
if (on) {
this.emitter.emit("change", this.nodeId, {
type: "level",
value: value + 1,
})
}
this.updateOn(on)
}
}
} And then I have an optional extended class I use: import debounce from "lodash/debounce"
import {Attribute} from "../../../../attribute"
import Multilevel from "../../../cc/multiLevel"
import {CC_SWITCH_MULTILEVEL} from "../../../cc"
export default class MultilevelRefresh extends Multilevel {
protected refresh = false
init(): void {
this.debounceUpdateLevel = debounce(
this.debounceUpdateLevel.bind(this),
500
)
this.refreshLevel = debounce(this.refreshLevel.bind(this), 250)
}
input(attribute: Attribute): void {
switch (attribute.type) {
case "on":
case "level":
this.refresh = true
this.refreshLevel()
break
}
super.input(attribute)
}
protected updateLevel(value: number): void {
if (this.refresh) {
if (this.level !== value) {
this.level = value
this.refreshLevel()
this.debounceUpdateLevel(value)
}
} else {
super.updateLevel(value)
}
}
private debounceUpdateLevel(value: number): void {
this.refresh = false
this.level = -1
this.updateLevel(value)
}
private refreshLevel(): void {
this.emitter.emit("refresh", {
node_id: this.nodeId,
class_id: CC_SWITCH_MULTILEVEL,
instance: 1,
index: 0,
})
}
} |
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. |
Just installed zjs2z and got hit with this issue on my GE dimmer in HA, for me it worked great with the VerifyChanged device compatibility flag in OZW like Kpine mentioned, you guys are doing a great job fixing the basis CC (double taps) for the same switches so hopefully this issue can be fixed in Zjs at some point too. In the meanwhile, what polling interval do you guys recommend? |
Can we please change the title of this issue as this is not specific to the GE dimmers. I have some Zooz and GE dimmers and they all have the same behavior as described here. This is a more generic issue in that zjs is reporting a transitional value instead of the final value 😄 |
Please test #1453 |
With the PR the behavior of the dimmers is still pretty funky in HA, but it does seem to help a lot at updating the state of the switch and IMO it’s a great starting point. |
Thanks for the feedback. Can you elaborate what you mean with funky? |
It's basically an HA UI issue. The current value does not change until 5 seconds later, so I guess it's updating state in-between that time. This has always been the case with z-wave and HA, even with the original |
When the light is on and you turn it off with HA, the toggle turn off and back on then a little later it turns back off to show the final state. Makes sense? Edit: Isn’t the UI mirroring what happening in the backend, so in the example I mentioned, changing the state of the dimmer 3 times instead of 1? |
Okay that seems like HA thinks switching didn't work until the update comes. |
Not sure what you mean. This PR delays the Get after Set by 5 seconds (or some variation based on the duration). That means there is a single Set, and one Get. |
@kpine I think Al explained better. I know we talked about this issue in discord but since no one had reported back here I figured to do so. |
Adding to my previous comment, the implementation of the My understanding of this PR, correct me if I'm wrong, was that there was no immediate Get, just a Set -> +N seconds Get, and so something in HA is reverting the switch state until it gets the updated value. |
What would be the next step? Should we create an issue in Hass or zjs2m/zjs_server? |
I'm not sure if this is easy to solve. We could cheat by immediately reporting the new "currentValue", but that is likely breaking something else. For now, I'd create an issue in Hass to see if that behavior can be improved. Closing since the zwave-js side is done. |
@AlCalzone Just to add to this...what if the api changed the current value immediately and only updated it to a transitional value if the device failed to reach the targetValue? Is there a reason why it needs to read the transitional value on the way down? |
It does not care about transitional values, that's just a symptom. Currently the code refreshes the current value from the node after setting the target value, just in case the device does not report updates itself. |
This is working much better now. Thanks 😄 |
Are you seeing your switch turn back on in the ui? Which parts are working better? |
so, when i turn a dimmer switch from off to on in the ha ui the switch will move to on, then like a second later it moves back to off, and eventually it moves back to on. and it no longer captures a transitional value, but captures the final value. this is the behavior i used to get with OZW. and it works pretty well for my purposes. it would be really nice for the switch to not flop back and forth, but this works great for me 😄 |
I've discussed with @blhoward2 and the HA devs - I'm going to immediately update the |
that sounds like a good compromise |
Sounds great, thank you. |
relevant PR for those following along: #1522 |
When 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:
Device cache:
The text was updated successfully, but these errors were encountered: