diff --git a/lib/extension/bind.ts b/lib/extension/bind.ts index 444ff26150..9b2f68280b 100755 --- a/lib/extension/bind.ts +++ b/lib/extension/bind.ts @@ -613,9 +613,13 @@ export default class Bind extends Extension { continue; } - let readAttrs = poll.read.attributes; - - if (poll.read.attributesForEndpoint) { + let readAttrs: TClusterAttributeKeys = poll.read.attributes; + let readCluster: ClusterName = poll.read.cluster; + // For devices that have hue_native_control enabled, read state attribute from manuSpecificPhilips2 cluster instead + if (endpoint.meta?.options?.hue_native_control === true) { + readCluster = "manuSpecificPhilips2" as ClusterName; + readAttrs = ["state"] as TClusterAttributeKeys<"manuSpecificPhilips2">; + } else if (poll.read.attributesForEndpoint) { const attrsForEndpoint = await poll.read.attributesForEndpoint(endpoint); readAttrs = [...poll.read.attributes, ...attrsForEndpoint]; } @@ -625,7 +629,7 @@ export default class Bind extends Extension { if (!this.pollDebouncers[key]) { this.pollDebouncers[key] = debounce(async () => { try { - await endpoint.read(poll.read.cluster, readAttrs); + await endpoint.read(readCluster, readAttrs); } catch (error) { // biome-ignore lint/style/noNonNullAssertion: TODO: biome migration: ??? const resolvedDevice = this.zigbee.resolveEntity(device)!; diff --git a/test/extensions/bind.test.ts b/test/extensions/bind.test.ts index 448fc11d10..aa9ff9709d 100644 --- a/test/extensions/bind.test.ts +++ b/test/extensions/bind.test.ts @@ -724,6 +724,7 @@ describe("Extension: Bind", () => { }); it("Should poll bounded Hue bulb when receiving message from Hue dimmer", async () => { + devices.bulb_color.getEndpoint(1)!.meta = {options: {hue_native_control: false}}; const remote = devices.remote; const data = {button: 3, unknown1: 3145728, type: 2, unknown2: 0, time: 1}; const payload = { @@ -741,6 +742,26 @@ describe("Extension: Bind", () => { expect(devices.bulb_color.getEndpoint(1)!.read).toHaveBeenCalledWith("genLevelCtrl", ["currentLevel"]); }); + it("Should poll manuSpecificPhilips2 of bounded Hue bulb when receiving message from Hue dimmer", async () => { + devices.bulb_color.getEndpoint(1)!.meta = {options: {hue_native_control: true}}; + const remote = devices.remote; + const data = {button: 3, unknown1: 3145728, type: 2, unknown2: 0, time: 1}; + const payload = { + data, + cluster: "manuSpecificPhilips", + device: remote, + endpoint: remote.getEndpoint(2)!, + type: "commandHueNotification", + linkquality: 10, + groupID: 0, + }; + await mockZHEvents.message(payload); + await flushPromises(); + expect(devices.bulb_color.getEndpoint(1)!.meta).toStrictEqual({options: {hue_native_control: true}}); + expect(mockDebounce).toHaveBeenCalledTimes(1); + expect(devices.bulb_color.getEndpoint(1)!.read).toHaveBeenCalledWith("manuSpecificPhilips2", ["state"]); + }); + it("Should poll bounded Hue bulb when receiving message from scene controller", async () => { const remote = devices.bj_scene_switch; const data = {action: "recall_2_row_1"};