* With Sonoff configuration ok * Fix configuration * Next (not finished) * With 1rst implementation of VTherm TRVZB and underlying * Work in simuated environment * Fix Testus * Release * Fix release name * Add #602 - implement a max_on_percent setting * Calculate offset_calibration as room_temp - local_temp Fix hvac_action calculation * Fix hvac_action Fix offset_calibration=room_temp - (local_temp - current_offset) * Fix underlying target is not updated * Issue #655 - combine motion and presence * Fix Valve testus. Improve sending the open percent to valve * Update custom_components/versatile_thermostat/translations/en.json Co-authored-by: Alexander Dransfield <2844540+alexdrans@users.noreply.github.com> * Indus step1 * Step 2 - renaming. All tests ok * Step 2: manual tests ok * First unit test ok * Test multi ok * All tests ok. Add a multi test for climate with valve regulation * With testu for config_flow ok * Documentation (not finished) * Fix #661 - central boiler doesn't starts with Sonoff TRVZB * Remove // testing * Fix exception when there is no offset at all * Fix class attributes and instance attributes mixing * Documentation 2 * Documentation 3 * Documentation ++ * documentation * Try to fix the central boiler calculation * Fix #669 * Documentation ++ * Documentation ok for FR * Readme FR|EN --------- Co-authored-by: Jean-Marc Collin <jean-marc.collin-extern@renault.com> Co-authored-by: Alexander Dransfield <2844540+alexdrans@users.noreply.github.com>
277 lines
10 KiB
Python
277 lines
10 KiB
Python
# pylint: disable=wildcard-import, unused-wildcard-import, protected-access, unused-argument, line-too-long
|
|
|
|
""" Test the normal start of a Thermostat """
|
|
from unittest.mock import patch, call
|
|
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.components.climate import HVACAction, HVACMode
|
|
|
|
from pytest_homeassistant_custom_component.common import MockConfigEntry
|
|
|
|
from custom_components.versatile_thermostat.base_thermostat import BaseThermostat
|
|
from custom_components.versatile_thermostat.thermostat_climate import (
|
|
ThermostatOverClimate,
|
|
)
|
|
from custom_components.versatile_thermostat.thermostat_switch import (
|
|
ThermostatOverSwitch,
|
|
)
|
|
|
|
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
|
|
|
|
|
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
|
async def test_over_switch_full_start(hass: HomeAssistant, skip_hass_states_is_state):
|
|
"""Test the normal full start of a thermostat in thermostat_over_switch type"""
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
title="TheOverSwitchMockName",
|
|
unique_id="uniqueId",
|
|
data=FULL_SWITCH_CONFIG,
|
|
)
|
|
|
|
with patch(
|
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
|
) as mock_send_event:
|
|
entity = await create_thermostat(hass, entry, "climate.theoverswitchmockname")
|
|
|
|
assert entity
|
|
assert isinstance(entity, ThermostatOverSwitch)
|
|
|
|
assert entity.name == "TheOverSwitchMockName"
|
|
assert entity.is_over_climate is False
|
|
assert entity.hvac_action is HVACAction.OFF
|
|
assert entity.hvac_mode is HVACMode.OFF
|
|
assert entity.target_temperature == entity.min_temp
|
|
assert entity.preset_modes == [
|
|
PRESET_NONE,
|
|
PRESET_FROST_PROTECTION,
|
|
PRESET_ECO,
|
|
PRESET_COMFORT,
|
|
PRESET_BOOST,
|
|
PRESET_ACTIVITY,
|
|
]
|
|
assert entity.preset_mode is PRESET_NONE
|
|
assert entity._security_state is False
|
|
assert entity._window_state is None
|
|
assert entity._motion_state is None
|
|
assert entity._presence_state is None
|
|
assert entity._prop_algorithm is not None
|
|
assert entity.have_valve_regulation is False
|
|
|
|
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
|
assert mock_send_event.call_count == 2
|
|
|
|
mock_send_event.assert_has_calls(
|
|
[
|
|
call.send_event(EventType.PRESET_EVENT, {"preset": PRESET_NONE}),
|
|
call.send_event(
|
|
EventType.HVAC_MODE_EVENT,
|
|
{"hvac_mode": HVACMode.OFF},
|
|
),
|
|
]
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
|
async def test_over_climate_full_start(hass: HomeAssistant, skip_hass_states_is_state):
|
|
"""Test the normal full start of a thermostat in thermostat_over_climate type"""
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
title="TheOverClimateMockName",
|
|
unique_id="uniqueId",
|
|
data=PARTIAL_CLIMATE_CONFIG,
|
|
)
|
|
|
|
fake_underlying_climate = MockClimate(hass, "mockUniqueId", "MockClimateName", {})
|
|
|
|
with patch(
|
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
|
) as mock_send_event, patch(
|
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
|
|
return_value=fake_underlying_climate,
|
|
) as mock_find_climate:
|
|
entity = await create_thermostat(hass, entry, "climate.theoverclimatemockname")
|
|
|
|
assert entity
|
|
assert isinstance(entity, ThermostatOverClimate)
|
|
|
|
assert entity.name == "TheOverClimateMockName"
|
|
assert entity.is_over_climate is True
|
|
assert entity.hvac_action is HVACAction.OFF
|
|
assert entity.hvac_mode is HVACMode.OFF
|
|
assert entity.target_temperature == entity.min_temp
|
|
assert entity.preset_modes == [
|
|
PRESET_NONE,
|
|
PRESET_FROST_PROTECTION,
|
|
PRESET_ECO,
|
|
PRESET_COMFORT,
|
|
PRESET_BOOST,
|
|
]
|
|
assert entity.preset_mode is PRESET_NONE
|
|
assert entity._security_state is False
|
|
assert entity._window_state is None
|
|
assert entity._motion_state is None
|
|
assert entity._presence_state is None
|
|
assert entity.have_valve_regulation is False
|
|
|
|
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
|
assert mock_send_event.call_count == 2
|
|
mock_send_event.assert_has_calls(
|
|
[
|
|
call.send_event(EventType.PRESET_EVENT, {"preset": PRESET_NONE}),
|
|
call.send_event(
|
|
EventType.HVAC_MODE_EVENT,
|
|
{"hvac_mode": HVACMode.OFF},
|
|
),
|
|
]
|
|
)
|
|
|
|
assert mock_find_climate.call_count == 1
|
|
assert mock_find_climate.mock_calls[0] == call()
|
|
mock_find_climate.assert_has_calls([call.find_underlying_entity()])
|
|
|
|
|
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
|
async def test_over_4switch_full_start(hass: HomeAssistant, skip_hass_states_is_state):
|
|
"""Test the normal full start of a thermostat in thermostat_over_switch with 4 switches type"""
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
title="TheOver4SwitchMockName",
|
|
unique_id="uniqueId",
|
|
data=FULL_4SWITCH_CONFIG,
|
|
)
|
|
|
|
with patch(
|
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
|
) as mock_send_event:
|
|
entity = await create_thermostat(hass, entry, "climate.theover4switchmockname")
|
|
# entry.add_to_hass(hass)
|
|
# await hass.config_entries.async_setup(entry.entry_id)
|
|
# assert entry.state is ConfigEntryState.LOADED
|
|
#
|
|
# def find_my_entity(entity_id) -> ClimateEntity:
|
|
# """Find my new entity"""
|
|
# component: EntityComponent[ClimateEntity] = hass.data[CLIMATE_DOMAIN]
|
|
# for entity in component.entities:
|
|
# if entity.entity_id == entity_id:
|
|
# return entity
|
|
#
|
|
# entity: BaseThermostat = find_my_entity("climate.theover4switchmockname")
|
|
|
|
assert entity
|
|
|
|
assert entity.name == "TheOver4SwitchMockName"
|
|
assert entity.is_over_switch
|
|
assert entity.hvac_action is HVACAction.OFF
|
|
assert entity.hvac_mode is HVACMode.OFF
|
|
assert entity.target_temperature == entity.min_temp
|
|
assert entity.preset_modes == [
|
|
PRESET_NONE,
|
|
PRESET_FROST_PROTECTION,
|
|
PRESET_ECO,
|
|
PRESET_COMFORT,
|
|
PRESET_BOOST,
|
|
PRESET_ACTIVITY,
|
|
]
|
|
assert entity.preset_mode is PRESET_NONE
|
|
assert entity._security_state is False
|
|
assert entity._window_state is None
|
|
assert entity._motion_state is None
|
|
assert entity._presence_state is None
|
|
assert entity._prop_algorithm is not None
|
|
|
|
assert entity.nb_underlying_entities == 4
|
|
|
|
# Checks that we have the 4 UnderlyingEntity correctly configured
|
|
for idx in range(4):
|
|
under = entity.underlying_entity(idx)
|
|
assert under is not None
|
|
assert isinstance(under, UnderlyingSwitch)
|
|
assert under.entity_id == "switch.mock_4switch" + str(idx)
|
|
assert under.initial_delay_sec == 8 * 60 / 4 * idx
|
|
|
|
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
|
assert mock_send_event.call_count == 2
|
|
|
|
mock_send_event.assert_has_calls(
|
|
[
|
|
call.send_event(EventType.PRESET_EVENT, {"preset": PRESET_NONE}),
|
|
call.send_event(
|
|
EventType.HVAC_MODE_EVENT,
|
|
{"hvac_mode": HVACMode.OFF},
|
|
),
|
|
]
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
|
async def test_over_switch_deactivate_preset(
|
|
hass: HomeAssistant, skip_hass_states_is_state
|
|
):
|
|
"""Test the normal full start of a thermostat in thermostat_over_switch type"""
|
|
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
title="TheOverSwitchMockName",
|
|
unique_id="uniqueId",
|
|
data={
|
|
CONF_NAME: "TheOverSwitchMockName",
|
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH,
|
|
CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
|
|
CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
|
|
CONF_CYCLE_MIN: 8,
|
|
CONF_TEMP_MIN: 15,
|
|
CONF_TEMP_MAX: 30,
|
|
"frost_temp": 0,
|
|
"eco_temp": 17,
|
|
"comfort_temp": 0,
|
|
"boost_temp": 19,
|
|
CONF_USE_WINDOW_FEATURE: False,
|
|
CONF_USE_MOTION_FEATURE: False,
|
|
CONF_USE_POWER_FEATURE: False,
|
|
CONF_USE_PRESENCE_FEATURE: False,
|
|
CONF_HEATER: "switch.mock_switch1",
|
|
CONF_HEATER_2: None,
|
|
CONF_HEATER_3: None,
|
|
CONF_HEATER_4: None,
|
|
CONF_HEATER_KEEP_ALIVE: 0,
|
|
CONF_SECURITY_DELAY_MIN: 10,
|
|
CONF_MINIMAL_ACTIVATION_DELAY: 10,
|
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
|
CONF_TPI_COEF_INT: 0.6,
|
|
CONF_TPI_COEF_EXT: 0.01,
|
|
},
|
|
)
|
|
|
|
entity: BaseThermostat = await create_thermostat(
|
|
hass, entry, "climate.theoverswitchmockname"
|
|
)
|
|
assert entity
|
|
assert isinstance(entity, ThermostatOverSwitch)
|
|
|
|
assert entity.preset_modes == [
|
|
PRESET_NONE,
|
|
# PRESET_FROST_PROTECTION,
|
|
PRESET_ECO,
|
|
# PRESET_COMFORT,
|
|
PRESET_BOOST,
|
|
]
|
|
assert entity.preset_mode is PRESET_NONE
|
|
|
|
# try to set the COMFORT Preset which is absent
|
|
try:
|
|
await entity.async_set_preset_mode(PRESET_COMFORT)
|
|
except ValueError as err:
|
|
print(err)
|
|
else:
|
|
assert False
|
|
finally:
|
|
assert entity.preset_mode is PRESET_NONE
|