fix: Home Assistant: don't treat light_type select as an endpoint light (#33472)

This commit is contained in:
Cestercian authored and GitHub committed 2026-10-25 07:32:17 +01:00
1 parent a26e4fc2fd
commit fc7383b940
2 files changed
+47 -2

No files matched your search

+4 -2
View File
@@ -1565,9 +1565,11 @@ export class HomeAssistant extends Extension {
}
/* v8 ignore stop */
const component = topicMatch[1];
const objectID = topicMatch[3];
const lightMatch = /^light_(.*)/.exec(objectID);
const coverMatch = /^cover_(.*)/.exec(objectID);
// Only endpoint lights/covers (`light_l1`, `cover_left`, ...). A `light_type` select shares the prefix.
const lightMatch = component === "light" ? /^light_(.*)/.exec(objectID) : null;
const coverMatch = component === "cover" ? /^cover_(.*)/.exec(objectID) : null;
const match = lightMatch || coverMatch;
+43
View File
@@ -2962,6 +2962,49 @@ describe("Extension: HomeAssistant", () => {
expect(mockMQTTPublishAsync).not.toHaveBeenCalledWith("zigbee2mqtt/U202DST600ZB/l1", expect.any(String), expect.any(Object));
});
it("Should not republish a light_type select as an endpoint light state", async () => {
const entity = getZ2MEntity(devices.bulb);
assert(entity.isDevice());
const definition = entity.definition;
assert(definition);
const originalExposes = definition.exposes;
const lightType = new zhc.Enum("light_type", zhc.access.STATE_SET, ["led", "incandescent", "halogen"]);
definition.exposes = (device, options) => {
const exposes = typeof originalExposes === "function" ? originalExposes(device, options) : originalExposes;
return [...exposes, lightType];
};
try {
await resetExtension();
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
"homeassistant/select/0x000b57fffec6a5b2/light_type/config",
expect.any(String),
expect.any(Object),
);
mockMQTTPublishAsync.mockClear();
await extension.onPublishEntityState({
entity,
message: {state: "OFF", brightness: 254, light_type: "led", linkquality: 255},
payload: {light_type: "led"},
});
expect(mockMQTTPublishAsync).not.toHaveBeenCalledWith("zigbee2mqtt/bulb/type", expect.any(String), expect.any(Object));
// Multi-endpoint covers still republish onto the endpoint topic.
const cover = getZ2MEntity(devices.TS130F_DUAL_COVER_SWITCH);
mockMQTTPublishAsync.mockClear();
await extension.onPublishEntityState({
entity: cover,
message: {state_left: "OPEN", position_left: 20},
payload: {position_left: 20},
});
expect(mockMQTTPublishAsync).toHaveBeenCalledWith("zigbee2mqtt/0xa4c138018cf95021/left", stringify({state: "OPEN", position: 20}), {});
} finally {
definition.exposes = originalExposes;
}
});
it("Shouldnt crash in onPublishEntityState on group publish", async () => {
mockLogger.error.mockClear();
mockMQTTPublishAsync.mockClear();