diff --git a/pyhilo/device/climate.py b/pyhilo/device/climate.py index 3a2b09a..c65a32a 100644 --- a/pyhilo/device/climate.py +++ b/pyhilo/device/climate.py @@ -102,9 +102,20 @@ def hvac_action(self) -> str: """ Gets the current HVAC action of the device. + For 24 V thermostats the action comes from currentState ("HEATING", + "COOLING", "OFF"). For baseboard thermostats it is derived from the + reported heating power. + Returns: - str: 'heating' if heating is active, 'idle' otherwise. + str: one of 'heating', 'cooling', or 'idle'. """ + if self.is_low_voltage: + state = self.current_state + if state == "HEATING": + return "heating" + if state == "COOLING": + return "cooling" + return "idle" attr = self.get_value("heating", 0) return "heating" if attr > 0 else "idle" @@ -170,11 +181,7 @@ def allowed_fan_modes(self) -> list[str]: @property def current_state(self) -> str | None: - """Raw running state reported by a 24 V thermostat. - - Exposed for consumers, but deliberately not mapped to hvac_action yet: - its vocabulary has not been observed in enough operating conditions. - """ + """Raw running state reported by a 24 V thermostat ("HEATING", "COOLING", "OFF").""" return self._optional_str("current_state") @property diff --git a/tests/test_climate.py b/tests/test_climate.py index a6854fd..d331f88 100644 --- a/tests/test_climate.py +++ b/tests/test_climate.py @@ -41,6 +41,33 @@ def _climate(**readings): return device +class TestHvacAction: + @pytest.mark.parametrize( + "current_state, expected", + [ + pytest.param("HEATING", "heating", id="heating"), + pytest.param("COOLING", "cooling", id="cooling"), + pytest.param("OFF", "idle", id="off-is-idle"), + pytest.param(None, "idle", id="unreported-is-idle"), + ], + ) + def test_low_voltage_maps_current_state(self, current_state, expected): + kwargs = {"Thermostat24VMode": "AUTO"} + if current_state is not None: + kwargs["CurrentState"] = current_state + assert _climate(**kwargs).hvac_action == expected + + @pytest.mark.parametrize( + "heating, expected", + [ + pytest.param(1, "heating", id="power-on-is-heating"), + pytest.param(0, "idle", id="power-off-is-idle"), + ], + ) + def test_baseboard_uses_heating_power(self, heating, expected): + assert _climate(Heating=heating).hvac_action == expected + + class TestAsList: def test_none_is_empty(self): assert as_list(None) == []