Skip to content

Commit 0018ca8

Browse files
kirovilyaKoenkk
andauthored
fix: Home Assistant: support cooling setpoint in climate discovery (#32411)
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
1 parent 2f26083 commit 0018ca8

2 files changed

Lines changed: 47 additions & 13 deletions

File tree

lib/extension/homeassistant.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -643,15 +643,19 @@ export class HomeAssistant extends Extension {
643643
break;
644644
}
645645
case "climate": {
646-
const setpointProperties = ["occupied_heating_setpoint", "current_heating_setpoint"];
647-
const setpoint = (firstExpose as zhc.Climate).features.filter(isNumericExpose).find((f) => setpointProperties.includes(f.name));
646+
const heatingSetpoint = (firstExpose as zhc.Climate).features
647+
.filter(isNumericExpose)
648+
.find((f) => ["occupied_heating_setpoint", "current_heating_setpoint"].includes(f.name));
649+
const coolingSetpoint = (firstExpose as zhc.Climate).features
650+
.filter(isNumericExpose)
651+
.find((f) => f.name === "occupied_cooling_setpoint");
652+
const primarySetpoint = heatingSetpoint ?? coolingSetpoint;
648653
assert(
649-
setpoint && setpoint.value_min !== undefined && setpoint.value_max !== undefined,
654+
primarySetpoint && primarySetpoint.value_min !== undefined && primarySetpoint.value_max !== undefined,
650655
"No setpoint found or it is missing value_min/max",
651656
);
652657
const temperature = (firstExpose as zhc.Climate).features.find((f) => f.name === "local_temperature");
653658
assert(temperature, "No temperature found");
654-
655659
const discoveryEntry: DiscoveryEntry = {
656660
type: "climate",
657661
object_id: endpointName ? `climate_${endpointName}` : "climate",
@@ -662,9 +666,9 @@ export class HomeAssistant extends Extension {
662666
state_topic: false,
663667
temperature_unit: "C",
664668
// Setpoint
665-
temp_step: setpoint.value_step,
666-
min_temp: setpoint.value_min.toString(),
667-
max_temp: setpoint.value_max.toString(),
669+
temp_step: primarySetpoint.value_step,
670+
min_temp: primarySetpoint.value_min.toString(),
671+
max_temp: primarySetpoint.value_max.toString(),
668672
// Temperature
669673
current_temperature_topic: true,
670674
current_temperature_template: `{{ value_json["${temperature.property}"] }}`,
@@ -693,17 +697,16 @@ export class HomeAssistant extends Extension {
693697
discoveryEntry.discovery_payload.action_template = `{% set values = {None:None,'idle':'idle','heat':'heating','cool':'cooling','fan_only':'fan'} %}{{ values[value_json["${state.property}"]] }}`;
694698
}
695699

696-
const coolingSetpoint = (firstExpose as zhc.Climate).features.find((f) => f.name === "occupied_cooling_setpoint");
697-
if (coolingSetpoint) {
698-
discoveryEntry.discovery_payload.temperature_low_command_topic = setpoint.name;
699-
discoveryEntry.discovery_payload.temperature_low_state_template = `{{ value_json["${setpoint.property}"] }}`;
700+
if (heatingSetpoint && coolingSetpoint) {
701+
discoveryEntry.discovery_payload.temperature_low_command_topic = heatingSetpoint.name;
702+
discoveryEntry.discovery_payload.temperature_low_state_template = `{{ value_json["${heatingSetpoint.property}"] }}`;
700703
discoveryEntry.discovery_payload.temperature_low_state_topic = true;
701704
discoveryEntry.discovery_payload.temperature_high_command_topic = coolingSetpoint.name;
702705
discoveryEntry.discovery_payload.temperature_high_state_template = `{{ value_json["${coolingSetpoint.property}"] }}`;
703706
discoveryEntry.discovery_payload.temperature_high_state_topic = true;
704707
} else {
705-
discoveryEntry.discovery_payload.temperature_command_topic = setpoint.name;
706-
discoveryEntry.discovery_payload.temperature_state_template = `{{ value_json["${setpoint.property}"] }}`;
708+
discoveryEntry.discovery_payload.temperature_command_topic = primarySetpoint.name;
709+
discoveryEntry.discovery_payload.temperature_state_template = `{{ value_json["${primarySetpoint.property}"] }}`;
707710
discoveryEntry.discovery_payload.temperature_state_topic = true;
708711
}
709712

test/extensions/homeassistant.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,37 @@ describe("Extension: HomeAssistant", () => {
14501450
});
14511451
});
14521452

1453+
it("Should discover climate with cooling-only setpoint", () => {
1454+
const climateExpose = new zhc.Climate()
1455+
.withSetpoint("occupied_cooling_setpoint", 16, 32, 0.5)
1456+
.withLocalTemperature()
1457+
.withSystemMode(["off", "cool", "auto"]);
1458+
const device = {
1459+
definition: {},
1460+
isDevice: (): boolean => true,
1461+
isGroup: (): boolean => false,
1462+
endpoint: () => undefined,
1463+
options: {},
1464+
exposes: (): zhc.Expose[] => [climateExpose],
1465+
zh: {endpoints: []},
1466+
} as Device;
1467+
1468+
// @ts-expect-error private
1469+
const configs = extension.getConfigs(device);
1470+
const climate = configs.find((c) => c.type === "climate");
1471+
expect(climate).toBeDefined();
1472+
expect(climate!.discovery_payload).toMatchObject({
1473+
temperature_command_topic: "occupied_cooling_setpoint",
1474+
temperature_state_template: '{{ value_json["occupied_cooling_setpoint"] }}',
1475+
temperature_state_topic: true,
1476+
min_temp: "16",
1477+
max_temp: "32",
1478+
temp_step: 0.5,
1479+
});
1480+
expect(climate!.discovery_payload).not.toHaveProperty("temperature_low_command_topic");
1481+
expect(climate!.discovery_payload).not.toHaveProperty("temperature_high_command_topic");
1482+
});
1483+
14531484
it("Should discover devices with cover_position", () => {
14541485
let payload;
14551486

0 commit comments

Comments
 (0)