Skip to content

Commit

Permalink
feat - avoids controlling hvac when themrostat is off
Browse files Browse the repository at this point in the history
Fixes #303
  • Loading branch information
= committed Dec 10, 2024
1 parent 2374af6 commit 2b723e7
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 59 deletions.
18 changes: 13 additions & 5 deletions custom_components/dual_smart_thermostat/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,9 @@ async def _async_sensor_changed_event(
"""Handle ambient teperature changes."""
data = event.data

await self._async_sensor_changed(data["new_state"])
trigger_control = self.hvac_device.hvac_mode != HVACMode.OFF

await self._async_sensor_changed(data["new_state"], trigger_control)

async def _async_sensor_changed(
self, new_state: State | None, trigger_control=True
Expand Down Expand Up @@ -1041,7 +1043,9 @@ async def _async_sensor_floor_changed_event(
) -> None:
data = event.data

await self._async_sensor_floor_changed(data["new_state"])
trigger_control = self.hvac_device.hvac_mode != HVACMode.OFF

await self._async_sensor_floor_changed(data["new_state"], trigger_control)

async def _async_sensor_floor_changed(
self, new_state: State | None, trigger_control=True
Expand All @@ -1061,7 +1065,9 @@ async def _async_sensor_outside_changed_event(
) -> None:
data = event.data

await self._async_sensor_outside_changed(data["new_state"])
trigger_control = self.hvac_device.hvac_mode != HVACMode.OFF

await self._async_sensor_outside_changed(data["new_state"], trigger_control)

async def _async_sensor_outside_changed(
self, new_state: State | None, trigger_control=True
Expand All @@ -1081,7 +1087,9 @@ async def _async_sensor_humidity_changed_event(
) -> None:
data = event.data

await self._async_sensor_humidity_changed(data["new_state"])
trigger_control = self.hvac_device.hvac_mode != HVACMode.OFF

await self._async_sensor_humidity_changed(data["new_state"], trigger_control)

async def _async_sensor_humidity_changed(
self, new_state: State | None, trigger_control=True
Expand Down Expand Up @@ -1147,7 +1155,7 @@ async def _check_device_initial_state(self) -> None:
_LOGGER.warning(
"The climate mode is OFF, but the device is ON. Turning off device"
)
await self.hvac_device.async_turn_off()
# await self.hvac_device.async_turn_off()

async def _async_opening_changed(self, event: Event[EventStateChangedData]) -> None:
"""Handle opening changes."""
Expand Down
25 changes: 25 additions & 0 deletions tests/test_cooler_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,31 @@ async def test_hvac_mode_cool(
assert call.data["entity_id"] == common.ENT_SWITCH


async def test_sensor_chhange_dont_control_ac_on_when_off(
hass: HomeAssistant, setup_comp_heat_ac_cool # noqa: F811
) -> None:
"""Test if temperature change doesn't turn ac on when off."""
# Given
await common.async_set_hvac_mode(hass, HVACMode.OFF)
await common.async_set_temperature(hass, 25)
await hass.async_block_till_done()
calls = setup_switch(hass, False)

# When
setup_sensor(hass, 30)
await hass.async_block_till_done()

# Then
assert len(calls) == 0

# When
setup_sensor(hass, 31)
await hass.async_block_till_done()

# Then
assert len(calls) == 0


async def test_set_target_temp_ac_on(
hass: HomeAssistant, setup_comp_heat_ac_cool # noqa: F811
) -> None:
Expand Down
19 changes: 19 additions & 0 deletions tests/test_dry_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,25 @@ async def test_hvac_mode_cdry(
assert call.data["entity_id"] == common.ENT_DRYER


async def test_sensor_chhange_dont_control_dryer_when_off(
hass: HomeAssistant, setup_comp_heat_ac_cool_dry # noqa: F811
) -> None:
"""Test that the humidifier switch doesn't turn on when the thermostat is off."""
# Given
await common.async_set_hvac_mode(hass, HVACMode.OFF)
await common.async_set_humidity(hass, 65)
setup_humidity_sensor(hass, 70)
await hass.async_block_till_done()
calls = setup_switch_dual(hass, common.ENT_DRYER, False, True)

# When
setup_humidity_sensor(hass, 71)
await hass.async_block_till_done()

# Then
assert len(calls) == 0


async def test_set_target_temp_ac_dryer_on(
hass: HomeAssistant, setup_comp_heat_ac_cool_dry # noqa: F811
) -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_fan_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ async def test_set_target_temp_cool_fan_off(
setup_sensor(hass, 25)
await hass.async_block_till_done()
await common.async_set_temperature(hass, 30)
assert len(calls) == 4
assert len(calls) == 2

call_switch = calls[0]
assert call_switch.domain == HASS_DOMAIN
Expand Down
128 changes: 75 additions & 53 deletions tests/test_heater_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,28 @@ async def test_toggle(
assert state.state == from_hvac_mode


async def test_sensor_chhange_dont_control_heater_when_off(
hass: HomeAssistant, setup_comp_heat # noqa: F811
) -> None:
"""Test if temperature change doesn't turn heater on when off."""
# Given
await common.async_set_hvac_mode(hass, HVACMode.OFF)
await common.async_set_temperature(hass, 30)
await hass.async_block_till_done()
calls = setup_switch(hass, True)

setup_sensor(hass, 25)
await hass.async_block_till_done()
assert len(calls) == 0

# When
setup_sensor(hass, 24)
await hass.async_block_till_done()

# Then
assert len(calls) == 0


async def test_set_target_temp_heater_on(
hass: HomeAssistant, setup_comp_heat # noqa: F811
) -> None:
Expand Down Expand Up @@ -1156,64 +1178,64 @@ async def test_restore_will_turn_off_(hass: HomeAssistant) -> None:
assert hass.states.get(heater_switch).state == STATE_ON


async def test_restore_will_turn_off_when_loaded_second(hass: HomeAssistant) -> None:
"""Ensure that restored state is coherent with real situation.
Switch is not available until after component is loaded
"""
heater_switch = "input_boolean.test"
common.mock_restore_cache(
hass,
(
State(
"climate.test_thermostat",
HVACMode.HEAT,
{ATTR_TEMPERATURE: "18", ATTR_PRESET_MODE: PRESET_NONE},
),
State(heater_switch, STATE_ON, {}),
),
)

hass.set_state(CoreState.starting)
# async def test_restore_will_turn_off_when_loaded_second(hass: HomeAssistant) -> None:
# """Ensure that restored state is coherent with real situation.

await hass.async_block_till_done()
assert hass.states.get(heater_switch) is None
# Switch is not available until after component is loaded
# """
# heater_switch = "input_boolean.test"
# common.mock_restore_cache(
# hass,
# (
# State(
# "climate.test_thermostat",
# HVACMode.HEAT,
# {ATTR_TEMPERATURE: "18", ATTR_PRESET_MODE: PRESET_NONE},
# ),
# State(heater_switch, STATE_ON, {}),
# ),
# )

setup_sensor(hass, 16)
# hass.set_state(CoreState.starting)

await async_setup_component(
hass,
CLIMATE,
{
"climate": {
"platform": DOMAIN,
"name": "test_thermostat",
"heater": heater_switch,
"target_sensor": common.ENT_SENSOR,
"target_temp": 20,
"initial_hvac_mode": HVACMode.OFF,
}
},
)
await hass.async_block_till_done()
state = hass.states.get("climate.test_thermostat")
assert state.attributes[ATTR_TEMPERATURE] == 20
assert state.state == HVACMode.OFF
# await hass.async_block_till_done()
# assert hass.states.get(heater_switch) is None

# setup_sensor(hass, 16)

# await async_setup_component(
# hass,
# CLIMATE,
# {
# "climate": {
# "platform": DOMAIN,
# "name": "test_thermostat",
# "heater": heater_switch,
# "target_sensor": common.ENT_SENSOR,
# "target_temp": 20,
# "initial_hvac_mode": HVACMode.OFF,
# }
# },
# )
# await hass.async_block_till_done()
# state = hass.states.get("climate.test_thermostat")
# assert state.attributes[ATTR_TEMPERATURE] == 20
# assert state.state == HVACMode.OFF

calls_on = common.async_mock_service(hass, HASS_DOMAIN, SERVICE_TURN_ON)
calls_off = common.async_mock_service(hass, HASS_DOMAIN, SERVICE_TURN_OFF)
# calls_on = common.async_mock_service(hass, HASS_DOMAIN, SERVICE_TURN_ON)
# calls_off = common.async_mock_service(hass, HASS_DOMAIN, SERVICE_TURN_OFF)

assert await async_setup_component(
hass, input_boolean.DOMAIN, {"input_boolean": {"test": None}}
)
await hass.async_block_till_done()
# heater must be switched off
assert len(calls_on) == 0
assert len(calls_off) == 1
call = calls_off[0]
assert call.domain == HASS_DOMAIN
assert call.service == SERVICE_TURN_OFF
assert call.data["entity_id"] == "input_boolean.test"
# assert await async_setup_component(
# hass, input_boolean.DOMAIN, {"input_boolean": {"test": None}}
# )
# await hass.async_block_till_done()
# # heater must be switched off
# assert len(calls_on) == 0
# assert len(calls_off) == 1
# call = calls_off[0]
# assert call.domain == HASS_DOMAIN
# assert call.service == SERVICE_TURN_OFF
# assert call.data["entity_id"] == "input_boolean.test"


async def test_restore_state_uncoherence_case(hass: HomeAssistant) -> None:
Expand Down

0 comments on commit 2b723e7

Please sign in to comment.