feat: Poll manuSpecificPhilips2 for Hue lights - #32078
burmistrzak wants to merge 18 commits into
Conversation
|
Cool! Can you explain the logic behind polling a little bit, to make sure I understand it? Is it like this? |
|
@andrei-lazarov Correct. Same thing for device-to-device bindings. 😊 |
@Koenkk I was about to do that, but wouldn't it be better to confirm before polling that the |
Updated type assertions for readCluster and readAttrs.
|
I've been thinking: Why not use the state of the Hue Native Control device option to dynamically override the poll target? @Nerivec Would that be doable with existing APIs and also actually be testable? |
|
Not sure how this was implemented. I assume there's a zigbee2mqtt/lib/extension/configure.ts Line 70 in cfc7ab8 |
|
@Nerivec Would you mind sanity checking my test harness? 😊 I think the issue was that |
|
@andrei-lazarov Would you be able to test this PR on your end? |
Yes, just a different cluster (for now). See above. 😅
AFAIK no... But would be a much clearer approach tho. |
|
@Nerivec Let's put this PR on hold until we have a more maintainable way of implementing such overrides from ZHC. Cramming manufacturer-specific code into ZH/Z2M isn't the way to go. 😊 |
|
About the revert, that wasn't strictly related to this PR, just a way to avoid executing the logic if we're not going to enter the About moving this to ZHC, I think we can just introduce something on the definition, since this used by Z2M, not ZH, we don't have to introduce anything at ZH level. zigbee2mqtt/lib/extension/onEvent.ts Line 85 in cfc7ab8 onBindPoll?: (device: Zh.Device, endpoint: Zh.Endpoint) => Promise<void>Note: just a quick overview, need to dig into the requirements from Z2M, and the possible needs from ZHC. |
Thanks for clarifying!
Sounds like an elegant solution to me! 💅
I assume the proposed |
Then I would propose to add a "whatToPoll" function in index.ts which returns the attributes to read for a given command. |
|
@Nerivec Ok, so we now got a rough idea of how to implement this.
But how do we go from here? |
You mean moving the whole POLL_ON_MESSAGE? I was thinking having it as a possible override mechanism that definitions can declare. We need a way to declare, "this is the default" (current), and "this is what this device should do" (intent of this PR). |
Leaving it up to individual definitions doesn't make much sense, IMHO, because that |
|
Just would need to add the entry in the same modern extend as the |
Good point. |
|
Depends if we want something a bit more flexible (possible future ZHC uses). A function that takes device+endpoint and does what it needs to do instead of the default in Z2M is more future-proof (avoids refactoring 😁). |
A more general purpose override function sounds quite useful, but implementation will be a bit more tricky. 😅 |
|
I had an idea that I want to share, a bit off-topic from the Hue cluster.
Sorry, will do! |
@andrei-lazarov Oh, that's an interesting idea! Having less hardcoded stuff around is always good.
No need to rush. 😊 A general purpose override function that allows ZHC to alter device-specific behavior in Z2M would be the most flexible solution. However, it's not yet clear how exactly such overrides would be called from Z2M extensions. I'm in favor of a compromise that moves the override into ZHC but is limited in scope, i.e. not general purpose. |
The same as onEvent, like I mentioned above. Can just call anything from the definition, with whatever args are needed. // in ZHC definition type
onBindPoll?: (device: Zh.Device, toPoll: Set<Zh.Endpoint>: existingPollers: Map<string, () => void>) => Promise<void>
// example use in ZHC definition
...
onBindPoll: (device, toPoll, existingPollers) => {
for (const endpoint of toPoll) {
const key = ...;
let poller = existingPollers.get(key);
if (!poller) {
poller = debounce(async () => {
try {
await endpoint.read<"manuSpecificPhilips2", ManuSpecificPhilips2>("manuSpecificPhilips2", ["state"]);
} catch (error) {
logger.error(`Failed to poll ${readAttrs} from ${device.ieeeAddr} (${(error as Error).message})`);
}
}, 1000);
existingPollers.set(key, poller);
}
poller();
}
}
...// in Z2M
#bindPollers = new Map<string, () => void>(); // replaces `bindDebouncers`
if (data.device.definition?.onBindPoll) {
const toPoll = this.#getEndpointsToPoll(data.device.zh.endpoints, data.groupID);
await data.device.definition.onBindPoll(device, toPoll, this.#bindPollers);
} else {
// default Z2M logic
}For the real thing, need to pass some of |
|
Quite involved for such a "simple" enhancement. 😅 I'm a little bit concerned about the potential overhead caused by the back and forth (ZHC/Z2M) when compared to a static But if everything checks out on that end, I can certainly give it a shot. |
|
It's only a function call on the definition, if defined, barely any impact at all. @Koenkk thoughts on #32078 (comment) ? Seems a lot of stuff in POLL_ON_MESSAGE is manuf-spe/custom clusters, might be worth moving some of that to ZHC as well, better typing & co (can do it over time, like we did custom clusters). |
That's actually quite interesting because it seems to confirm behavior that I've seen before elsewhere. 👌
Only |
This looks like a nice solution and allows for a lot of flexibility. |
|
I just realized that there's no retry mechanism for failed polls. 😳 Just had one older Atmel-based Hue fixtures' @andrei-lazarov Do you still have Atmel-based Hue lights? Another cool feature would be to trigger/publish a scene's state when we notice a scene was recalled via direct bindings. This would reduce polling associated with scenes to zero. |
|
I have only one Atmel bulb |
@andrei-lazarov Lucky you! 😜 Have you ever had it act up or be unreliable? |
|
Yes! It took the whole network down with its typical address 0 conflict. So I put it back in the box 🙂 |
@andrei-lazarov Oh no... If I'm correct and the EMI shield of the Hue Engine is indeed hiding an Atmel chip... Unfortunately, the images from the FCC filings are low resolution and no chip markings are visible. |
|
Folks, after some minimal invasive surgery, I was able to confirm that the Hue 100B-010E platform is indeed based on the Atmel ATSAMR21E family!
This means that all Hue fixtures that contain a Hue Engine v1 are quite underpowered, even when compared to the first generation of EFR32-based Hue Connect modules. In an ideal world, Signify would offer replacement parts so that fixtures could be easily repaired and upgraded. The difference between a ZLL and Z3 fixture is literally just the Hue Connect module. Oh well... @andrei-lazarov And yes, after a thorough clean and repair job, the fixture incl. module is working just fine. |
|
This pull request is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days |

As mentioned in Koenkk/zigbee-herdsman-converters#12256 and #31960, Z2M automatically reads (i.e. polls) specific attributes (brightness, state, etc.) when a device is being controlled via Zigbee Bindings.
Instead of reading only a limited amount of standard attributes, the Philips Hue-exclusive
manuSpecificPhilips2cluster can be used to reduce airtime and improve responsiveness by fetching the complete device state with a single command.To my knowledge, the only Hue device that doesn't feature this cluster is the Hue Smart Plug, but it is capable of reporting anyways.
cc. @andrei-lazarov