From 0308f01b295a8ecfef9938b67514aa1b7b95e5bc Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Sun, 16 Aug 2026 09:14:02 +0200 Subject: [PATCH] Add support for inverted output in Shelly climate entity (#179208) --- homeassistant/components/shelly/climate.py | 6 +++- tests/components/shelly/test_climate.py | 35 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/shelly/climate.py b/homeassistant/components/shelly/climate.py index 422618df9179..c8cfc68f517c 100644 --- a/homeassistant/components/shelly/climate.py +++ b/homeassistant/components/shelly/climate.py @@ -727,6 +727,9 @@ class RpcClimate(ShellyRpcEntity, ClimateEntity): self._thermostat_type = coordinator.device.config[self.key].get( "type", "heating" ) + self._invert_output = coordinator.device.config[self.key].get( + "invert_output", False + ) if self._thermostat_type == "cooling": self._attr_hvac_modes = [HVACMode.OFF, HVACMode.COOL] else: @@ -770,7 +773,8 @@ class RpcClimate(ShellyRpcEntity, ClimateEntity): @override def hvac_action(self) -> HVACAction: """HVAC current action.""" - if not self.status["output"]: + # When inverted, relay on means idle; otherwise relay on means active. + if self.status["output"] == self._invert_output: return HVACAction.IDLE return ( diff --git a/tests/components/shelly/test_climate.py b/tests/components/shelly/test_climate.py index 03abc95d1680..e249324a895d 100644 --- a/tests/components/shelly/test_climate.py +++ b/tests/components/shelly/test_climate.py @@ -736,6 +736,41 @@ async def test_rpc_climate_hvac_mode_cool( assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.COOLING +@pytest.mark.parametrize( + ("thermostat_type", "invert_output", "output", "expected_action"), + [ + ("heating", False, True, HVACAction.HEATING), + ("heating", False, False, HVACAction.IDLE), + ("heating", True, True, HVACAction.IDLE), + ("heating", True, False, HVACAction.HEATING), + ("cooling", True, True, HVACAction.IDLE), + ("cooling", True, False, HVACAction.COOLING), + ], +) +async def test_rpc_climate_hvac_action_inverted_output( + hass: HomeAssistant, + mock_rpc_device: Mock, + monkeypatch: pytest.MonkeyPatch, + thermostat_type: str, + invert_output: bool, + output: bool, + expected_action: HVACAction, +) -> None: + """Test climate hvac action with inverted output.""" + entity_id = "climate.test_name" + + new_config = deepcopy(mock_rpc_device.config) + new_config["thermostat:0"]["type"] = thermostat_type + new_config["thermostat:0"]["invert_output"] = invert_output + monkeypatch.setattr(mock_rpc_device, "config", new_config) + monkeypatch.setitem(mock_rpc_device.status["thermostat:0"], "output", output) + + await init_integration(hass, 2, model=MODEL_WALL_DISPLAY) + + assert (state := hass.states.get(entity_id)) + assert state.attributes[ATTR_HVAC_ACTION] == expected_action + + async def test_wall_display_thermostat_mode( hass: HomeAssistant, mock_rpc_device: Mock,