From 41822ed721de08ec1cd1f955097d1ad66c236ffc Mon Sep 17 00:00:00 2001 From: Koen Kanters Date: Wed, 30 Sep 2026 21:53:11 +0200 Subject: [PATCH] fix: Home Assistant: fix humidity incorrect for multi-endpoint climate devices (#33236) --- lib/extension/homeassistant.ts | 5 ++++- test/extensions/homeassistant.test.ts | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/extension/homeassistant.ts b/lib/extension/homeassistant.ts index 65ac46cb8..27bfb3a56 100644 --- a/lib/extension/homeassistant.ts +++ b/lib/extension/homeassistant.ts @@ -922,7 +922,10 @@ export class HomeAssistant extends Extension { discoveryEntries.push(discoveryEntry); } - const currentHumidity = allExposes?.filter(isNumericExpose).find((e) => e.name === "humidity" && e.access & ACCESS_STATE); + // Prefer the humidity of the same endpoint as the climate (multi-endpoint thermostats, e.g. Danfoss Icon2), + // fall back to a humidity without endpoint. + const humidities = allExposes.filter(isNumericExpose).filter((e) => e.name === "humidity" && e.access & ACCESS_STATE); + const currentHumidity = humidities.find((e) => e.endpoint === endpointName) ?? humidities.find((e) => e.endpoint === undefined); if (currentHumidity) { discoveryEntry.discovery_payload.current_humidity_template = `{{ value_json["${currentHumidity.property}"] }}`; discoveryEntry.discovery_payload.current_humidity_topic = true; diff --git a/test/extensions/homeassistant.test.ts b/test/extensions/homeassistant.test.ts index d89c22b28..8d185f5b7 100644 --- a/test/extensions/homeassistant.test.ts +++ b/test/extensions/homeassistant.test.ts @@ -1623,6 +1623,31 @@ describe("Extension: HomeAssistant", () => { }); }); + it("Should use humidity of the same endpoint for multi-endpoint climate", () => { + const climateL1Expose = new zhc.Climate().withSetpoint("occupied_heating_setpoint", 5, 35, 0.5).withLocalTemperature().withEndpoint("l1"); + const climateL2Expose = new zhc.Climate().withSetpoint("occupied_heating_setpoint", 5, 35, 0.5).withLocalTemperature().withEndpoint("l2"); + const humidityL1Expose = new zhc.Numeric("humidity", zhc.access.STATE_GET).withUnit("%").withEndpoint("l1"); + const humidityExpose = new zhc.Numeric("humidity", zhc.access.STATE_GET).withUnit("%"); + const device = { + definition: {}, + isDevice: (): boolean => true, + isGroup: (): boolean => false, + endpoint: () => undefined, + options: {}, + exposes: (): zhc.Expose[] => [climateL1Expose, climateL2Expose, humidityL1Expose, humidityExpose], + zh: {endpoints: []}, + } as Device; + + // @ts-expect-error private + const configs = extension.getConfigs(device); + const climateL1 = configs.find((c) => c.type === "climate" && c.object_id === "climate_l1"); + const climateL2 = configs.find((c) => c.type === "climate" && c.object_id === "climate_l2"); + // Same endpoint humidity is preferred + expect(climateL1!.discovery_payload.current_humidity_template).toStrictEqual('{{ value_json["humidity_l1"] }}'); + // Falls back to humidity without endpoint + expect(climateL2!.discovery_payload.current_humidity_template).toStrictEqual('{{ value_json["humidity"] }}'); + }); + it("Should discover climate with cooling-only setpoint", () => { const climateExpose = new zhc.Climate() .withSetpoint("occupied_cooling_setpoint", 16, 32, 0.5)