# pylint: disable=wildcard-import, unused-wildcard-import, protected-access, unused-argument, line-too-long, too-many-lines """ Test the central_configuration """ from unittest.mock import patch, call from datetime import datetime, timedelta from homeassistant.core import HomeAssistant from homeassistant.components.climate import HVACMode # from homeassistant.helpers.entity_component import EntityComponent from homeassistant.components.select import DOMAIN as SELECT_DOMAIN from pytest_homeassistant_custom_component.common import MockConfigEntry from custom_components.versatile_thermostat.thermostat_switch import ( ThermostatOverSwitch, ) from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import from .const 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_config_with_central_mode_true( hass: HomeAssistant, skip_hass_states_is_state ): """A config with central_mode True""" # Add a Switch VTherm 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_USE_CENTRAL_MODE: True, CONF_CYCLE_MIN: 5, CONF_TEMP_MIN: 8, CONF_TEMP_MAX: 18, "frost_temp": 10, "eco_temp": 17, "comfort_temp": 18, "boost_temp": 21, CONF_USE_WINDOW_FEATURE: False, CONF_USE_MOTION_FEATURE: False, CONF_USE_POWER_FEATURE: False, CONF_USE_PRESENCE_FEATURE: False, CONF_HEATER: "switch.mock_switch", CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, CONF_TPI_COEF_INT: 0.3, CONF_TPI_COEF_EXT: 0.01, CONF_MINIMAL_ACTIVATION_DELAY: 30, CONF_SAFETY_DELAY_MIN: 5, CONF_SAFETY_MIN_ON_PERCENT: 0.3, CONF_SAFETY_DEFAULT_ON_PERCENT: 0.1, }, ) with patch("homeassistant.core.ServiceRegistry.async_call"): entity: ThermostatOverSwitch = await create_thermostat( hass, entry, "climate.theoverswitchmockname" ) assert entity assert entity.name == "TheOverSwitchMockName" assert entity.is_over_switch assert entity.is_controlled_by_central_mode assert entity.last_central_mode is None # cause no central config exists @pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_config_with_central_mode_false( hass: HomeAssistant, skip_hass_states_is_state ): """A config with central_mode False""" # Add a Climate VTherm entry = MockConfigEntry( domain=DOMAIN, title="TheOverClimateMockName", unique_id="uniqueId", data={ CONF_NAME: "TheOverClimateMockName", CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE, CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", CONF_USE_CENTRAL_MODE: False, CONF_CYCLE_MIN: 5, CONF_TEMP_MIN: 8, CONF_TEMP_MAX: 18, "frost_temp": 10, "eco_temp": 17, "comfort_temp": 18, "boost_temp": 21, CONF_USE_WINDOW_FEATURE: False, CONF_USE_MOTION_FEATURE: False, CONF_USE_POWER_FEATURE: False, CONF_USE_PRESENCE_FEATURE: False, CONF_CLIMATE: "climate.mock_climate", CONF_MINIMAL_ACTIVATION_DELAY: 30, CONF_SAFETY_DELAY_MIN: 5, CONF_SAFETY_MIN_ON_PERCENT: 0.3, CONF_SAFETY_DEFAULT_ON_PERCENT: 0.1, }, ) with patch("homeassistant.core.ServiceRegistry.async_call"): entity: ThermostatOverSwitch = await create_thermostat( hass, entry, "climate.theoverclimatemockname" ) assert entity assert entity.name == "TheOverClimateMockName" assert entity.is_over_climate assert entity.is_controlled_by_central_mode is False assert entity.last_central_mode is None # cause no central config exists @pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_config_with_central_mode_none( hass: HomeAssistant, skip_hass_states_is_state ): """A config with central_mode is None""" # Add a Switch VTherm entry = MockConfigEntry( domain=DOMAIN, title="TheOverValveMockName", unique_id="uniqueId", data={ CONF_NAME: "TheOverValveMockName", CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_VALVE, CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", CONF_USE_CENTRAL_MODE: True, CONF_CYCLE_MIN: 5, CONF_TEMP_MIN: 8, CONF_TEMP_MAX: 18, "frost_temp": 10, "eco_temp": 17, "comfort_temp": 18, "boost_temp": 21, CONF_USE_WINDOW_FEATURE: False, CONF_USE_MOTION_FEATURE: False, CONF_USE_POWER_FEATURE: False, CONF_USE_PRESENCE_FEATURE: False, CONF_VALVE: "number.mock_valve", CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, CONF_TPI_COEF_INT: 0.3, CONF_TPI_COEF_EXT: 0.01, CONF_MINIMAL_ACTIVATION_DELAY: 30, CONF_SAFETY_DELAY_MIN: 5, CONF_SAFETY_MIN_ON_PERCENT: 0.3, CONF_SAFETY_DEFAULT_ON_PERCENT: 0.1, }, ) with patch("homeassistant.core.ServiceRegistry.async_call"): entity: ThermostatOverSwitch = await create_thermostat( hass, entry, "climate.theovervalvemockname" ) assert entity assert entity.name == "TheOverValveMockName" assert entity.is_over_valve assert entity.is_controlled_by_central_mode assert entity.last_central_mode is None # cause no central config exists @pytest.mark.parametrize("expected_lingering_tasks", [True]) @pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_switch_change_central_mode_true( hass: HomeAssistant, skip_hass_states_is_state, init_central_config ): """test that changes with over_switch config with central_mode True are taken into account""" # Add a Switch VTherm 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_USE_CENTRAL_MODE: True, CONF_CYCLE_MIN: 5, CONF_TEMP_MIN: 8, CONF_TEMP_MAX: 18, "frost_temp": 10, "eco_temp": 17, "comfort_temp": 18, "boost_temp": 21, CONF_USE_WINDOW_FEATURE: False, CONF_USE_MOTION_FEATURE: False, CONF_USE_POWER_FEATURE: False, CONF_USE_PRESENCE_FEATURE: False, CONF_HEATER: "switch.mock_switch", CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, CONF_TPI_COEF_INT: 0.3, CONF_TPI_COEF_EXT: 0.01, CONF_MINIMAL_ACTIVATION_DELAY: 30, CONF_SAFETY_DELAY_MIN: 5, CONF_SAFETY_MIN_ON_PERCENT: 0.3, CONF_SAFETY_DEFAULT_ON_PERCENT: 0.1, }, ) # 1 initialize entity and find select entity with patch("homeassistant.core.ServiceRegistry.async_call"): entity: ThermostatOverSwitch = await create_thermostat( hass, entry, "climate.theoverswitchmockname" ) assert entity assert entity.is_controlled_by_central_mode assert entity.last_central_mode is None # Find the select entity select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) assert select_entity assert select_entity.current_option == CENTRAL_MODE_AUTO assert select_entity.options == CENTRAL_MODES # start entity await entity.async_set_hvac_mode(HVACMode.HEAT) await entity.async_set_preset_mode(PRESET_BOOST) assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_BOOST # 2 change central_mode to STOPPED with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_STOPPED) assert entity.last_central_mode is CENTRAL_MODE_STOPPED assert entity.hvac_mode == HVACMode.OFF assert entity.preset_mode == PRESET_BOOST # 3 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await entity.async_set_preset_mode(PRESET_COMFORT) assert entity.preset_mode == PRESET_COMFORT await select_entity.async_select_option(CENTRAL_MODE_AUTO) # hvac_mode should be restored as before the STOP and preset should be restored with the last choosen preset (COMFORT here) assert entity.last_central_mode is CENTRAL_MODE_AUTO assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_COMFORT # 4 change central_mode to COOL_ONLY with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) # hvac_mode should be set to OFF because there is no COOL mode for this VTherm assert entity.last_central_mode is CENTRAL_MODE_COOL_ONLY assert entity.hvac_mode == HVACMode.OFF assert entity.preset_mode == PRESET_COMFORT # 5 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # hvac_mode should be restored to HEAT assert entity.last_central_mode is CENTRAL_MODE_AUTO assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_COMFORT # 6 change central_mode to HEAT_ONLY with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_HEAT_ONLY) # hvac_mode should stay in HEAT mode assert entity.last_central_mode is CENTRAL_MODE_HEAT_ONLY assert entity.hvac_mode == HVACMode.HEAT # No change assert entity.preset_mode == PRESET_COMFORT # 7 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # hvac_mode should be restored to HEAT assert entity.last_central_mode is CENTRAL_MODE_AUTO assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_COMFORT # 8 change central_mode to FROST_PROTECTION with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_FROST_PROTECTION) # hvac_mode should stay in HEAT mode assert entity.last_central_mode is CENTRAL_MODE_FROST_PROTECTION assert entity.hvac_mode == HVACMode.HEAT # change to Frost assert entity.preset_mode == PRESET_FROST_PROTECTION # 9 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # hvac_mode should be restored to HEAT assert entity.last_central_mode is CENTRAL_MODE_AUTO assert entity.hvac_mode == HVACMode.HEAT # preset restored to COMFORT assert entity.preset_mode == PRESET_COMFORT @pytest.mark.parametrize("expected_lingering_tasks", [True]) @pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_switch_ac_change_central_mode_true( hass: HomeAssistant, skip_hass_states_is_state, init_central_config ): """test that changes with over_switch config with central_mode True are taken into account""" # Add a Switch VTherm 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_USE_CENTRAL_MODE: True, CONF_CYCLE_MIN: 5, CONF_TEMP_MIN: 8, CONF_TEMP_MAX: 18, "frost_temp": 10, "eco_temp": 17, "comfort_temp": 18, "boost_temp": 21, CONF_USE_WINDOW_FEATURE: False, CONF_USE_MOTION_FEATURE: False, CONF_USE_POWER_FEATURE: False, CONF_USE_PRESENCE_FEATURE: False, CONF_HEATER: "switch.mock_switch", CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, CONF_TPI_COEF_INT: 0.3, CONF_TPI_COEF_EXT: 0.01, CONF_MINIMAL_ACTIVATION_DELAY: 30, CONF_SAFETY_DELAY_MIN: 5, CONF_SAFETY_MIN_ON_PERCENT: 0.3, CONF_SAFETY_DEFAULT_ON_PERCENT: 0.1, CONF_AC_MODE: True, }, ) # 1 initialize entity and find select entity with patch("homeassistant.core.ServiceRegistry.async_call"): entity: ThermostatOverSwitch = await create_thermostat( hass, entry, "climate.theoverswitchmockname" ) assert entity assert entity.is_controlled_by_central_mode assert entity.ac_mode is True assert entity.hvac_modes == [HVACMode.HEAT, HVACMode.COOL, HVACMode.OFF] # Find the select entity select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) assert select_entity assert select_entity.current_option == CENTRAL_MODE_AUTO assert select_entity.options == CENTRAL_MODES # start entity in cooling mode await entity.async_set_hvac_mode(HVACMode.COOL) await entity.async_set_preset_mode(PRESET_BOOST) assert entity.hvac_mode == HVACMode.COOL assert entity.preset_mode == PRESET_BOOST # 2 change central_mode to STOPPED with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_STOPPED) assert entity.hvac_mode == HVACMode.OFF assert entity.preset_mode == PRESET_BOOST # 3 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await entity.async_set_preset_mode(PRESET_COMFORT) assert entity.preset_mode == PRESET_COMFORT await select_entity.async_select_option(CENTRAL_MODE_AUTO) # hvac_mode should be restored as before the STOP and preset should be restored with the last choosen preset (COMFORT here) assert entity.hvac_mode == HVACMode.COOL assert entity.preset_mode == PRESET_COMFORT # 4 change central_mode to COOL_ONLY with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) # hvac_mode should be set to OFF because there is no COOL mode for this VTherm assert entity.hvac_mode == HVACMode.COOL assert entity.preset_mode == PRESET_COMFORT # 5 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # hvac_mode should be restored to HEAT assert entity.hvac_mode == HVACMode.COOL assert entity.preset_mode == PRESET_COMFORT # 6 change central_mode to HEAT_ONLY with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_HEAT_ONLY) # hvac_mode should stay in HEAT mode assert entity.hvac_mode == HVACMode.HEAT # No change assert entity.preset_mode == PRESET_COMFORT # 7 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # hvac_mode should be restored to COOL assert entity.hvac_mode == HVACMode.COOL assert entity.preset_mode == PRESET_COMFORT # 8 change central_mode to FROST_PROTECTION with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_FROST_PROTECTION) # hvac_mode should stay in COOL mode assert entity.hvac_mode == HVACMode.HEAT # change to Frost assert entity.preset_mode == PRESET_FROST_PROTECTION # 9 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # hvac_mode should be restored to COOL assert entity.hvac_mode == HVACMode.COOL # preset restored to COMFORT assert entity.preset_mode == PRESET_COMFORT @pytest.mark.parametrize("expected_lingering_tasks", [True]) @pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_climate_ac_change_central_mode_false( hass: HomeAssistant, skip_hass_states_is_state, init_central_config ): """test that changes with over_climate config with central_mode False are not taken into account""" fake_underlying_climate = MockClimate(hass, "mockUniqueId", "MockClimateName", {}) # Add a Climate VTherm entry = MockConfigEntry( domain=DOMAIN, title="TheOverClimateMockName", unique_id="uniqueId", data={ CONF_NAME: "TheOverClimateMockName", CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE, CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", CONF_USE_CENTRAL_MODE: False, CONF_CYCLE_MIN: 5, CONF_TEMP_MIN: 8, CONF_TEMP_MAX: 18, "frost_temp": 10, "eco_temp": 17, "comfort_temp": 18, "boost_temp": 21, CONF_USE_WINDOW_FEATURE: False, CONF_USE_MOTION_FEATURE: False, CONF_USE_POWER_FEATURE: False, CONF_USE_PRESENCE_FEATURE: False, CONF_CLIMATE: "climate.mock_climate", CONF_MINIMAL_ACTIVATION_DELAY: 30, CONF_SAFETY_DELAY_MIN: 5, CONF_SAFETY_MIN_ON_PERCENT: 0.3, CONF_SAFETY_DEFAULT_ON_PERCENT: 0.1, }, ) with patch("homeassistant.core.ServiceRegistry.async_call"), patch( "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate", return_value=fake_underlying_climate, ): entity: ThermostatOverSwitch = await create_thermostat( hass, entry, "climate.theoverclimatemockname" ) assert entity assert entity.name == "TheOverClimateMockName" assert entity.is_over_climate assert entity.is_controlled_by_central_mode is False assert entity.hvac_modes == [HVACMode.OFF, HVACMode.COOL, HVACMode.HEAT] # Find the select entity select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) assert select_entity assert select_entity.current_option == CENTRAL_MODE_AUTO assert select_entity.options == CENTRAL_MODES # start entity in Heating mode await entity.async_set_hvac_mode(HVACMode.HEAT) await entity.async_set_preset_mode(PRESET_BOOST) assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_BOOST # 2 change central_mode to STOPPED with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_STOPPED) # No change assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_BOOST # 3 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await entity.async_set_preset_mode(PRESET_COMFORT) assert entity.preset_mode == PRESET_COMFORT await select_entity.async_select_option(CENTRAL_MODE_AUTO) # No change assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_COMFORT # 4 change central_mode to COOL_ONLY with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) # No change assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_COMFORT # 5 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # No change assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_COMFORT # 6 change central_mode to HEAT_ONLY with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_HEAT_ONLY) # No change assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_COMFORT # 7 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # No change assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_COMFORT # 8 change central_mode to FROST_PROTECTION with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_FROST_PROTECTION) # No change assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_COMFORT # 9 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # No change assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_COMFORT @pytest.mark.parametrize("expected_lingering_tasks", [True]) @pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_climate_ac_only_change_central_mode_true( hass: HomeAssistant, skip_hass_states_is_state, init_central_config ): """test that changes with over_climate with AC only config with central_mode True are taken into account Test also switching from central_mode without coming to AUTO each time""" fake_underlying_climate = MockClimate( hass, "mockUniqueId", "MockClimateName", entry_infos={}, hvac_modes=[HVACMode.OFF, HVACMode.COOL], ) # Add a Climate VTherm entry = MockConfigEntry( domain=DOMAIN, title="TheOverClimateMockName", unique_id="uniqueId", data={ CONF_NAME: "TheOverClimateMockName", CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE, CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", CONF_USE_CENTRAL_MODE: True, CONF_CYCLE_MIN: 5, CONF_TEMP_MIN: 8, CONF_TEMP_MAX: 18, "frost_temp": 10, "eco_temp": 17, "comfort_temp": 18, "boost_temp": 21, CONF_USE_WINDOW_FEATURE: False, CONF_USE_MOTION_FEATURE: False, CONF_USE_POWER_FEATURE: False, CONF_USE_PRESENCE_FEATURE: False, CONF_CLIMATE: "climate.mock_climate", CONF_MINIMAL_ACTIVATION_DELAY: 30, CONF_SAFETY_DELAY_MIN: 5, CONF_SAFETY_MIN_ON_PERCENT: 0.3, CONF_SAFETY_DEFAULT_ON_PERCENT: 0.1, }, ) # 1. set hvac_mode to COOL and preet ECO with patch("homeassistant.core.ServiceRegistry.async_call"), patch( "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate", return_value=fake_underlying_climate, ): entity: ThermostatOverSwitch = await create_thermostat( hass, entry, "climate.theoverclimatemockname" ) assert entity assert entity.name == "TheOverClimateMockName" assert entity.is_over_climate assert entity.is_controlled_by_central_mode is True assert entity.hvac_modes == [HVACMode.OFF, HVACMode.COOL] # Find the select entity select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) assert select_entity assert select_entity.current_option == CENTRAL_MODE_AUTO assert select_entity.options == CENTRAL_MODES # start entity in Cooling mode await entity.async_set_hvac_mode(HVACMode.COOL) await entity.async_set_preset_mode(PRESET_ECO) assert entity.hvac_mode == HVACMode.COOL assert entity.preset_mode == PRESET_ECO # 2 change central_mode to STOPPED with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_STOPPED) # No change assert entity.hvac_mode == HVACMode.OFF assert entity.preset_mode == PRESET_ECO # 3 change central_mode to HEAT ONLY after switching to COMFORT preset with patch("homeassistant.core.ServiceRegistry.async_call"): await entity.async_set_preset_mode(PRESET_COMFORT) assert entity.preset_mode == PRESET_COMFORT await select_entity.async_select_option(CENTRAL_MODE_HEAT_ONLY) # Stay in OFF because HEAT is not permitted assert entity.hvac_mode == HVACMode.OFF assert entity.preset_mode == PRESET_COMFORT # 4 change central_mode to COOL_ONLY with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) # switch back to COOL restoring the preset assert entity.hvac_mode == HVACMode.COOL assert entity.preset_mode == PRESET_COMFORT # 5 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # No change assert entity.hvac_mode == HVACMode.COOL assert entity.preset_mode == PRESET_COMFORT # 6 change central_mode to FROST_PROTECTION with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_FROST_PROTECTION) # No change assert entity.hvac_mode == HVACMode.OFF assert entity.preset_mode == PRESET_COMFORT # 7 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # No change assert entity.hvac_mode == HVACMode.COOL assert entity.preset_mode == PRESET_COMFORT # 8 change central_mode to FROST_PROTECTION with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_FROST_PROTECTION) # No change assert entity.hvac_mode == HVACMode.OFF assert entity.preset_mode == PRESET_COMFORT # 9 change back central_mode to COOL_ONLY with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) # No change assert entity.hvac_mode == HVACMode.COOL assert entity.preset_mode == PRESET_COMFORT await entity.async_set_preset_mode(PRESET_ECO) # 10 change back central_mode to HEAT_ONLY with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_HEAT_ONLY) # Shutdown cause no HEAT assert entity.hvac_mode == HVACMode.OFF assert entity.preset_mode == PRESET_ECO # 11 change back central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): await select_entity.async_select_option(CENTRAL_MODE_AUTO) # No change assert entity.hvac_mode == HVACMode.COOL assert entity.preset_mode == PRESET_ECO @pytest.mark.parametrize("expected_lingering_tasks", [True]) @pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_switch_change_central_mode_true_with_window( hass: HomeAssistant, skip_hass_states_is_state, init_central_config ): """test that changes with over_switch config with central_mode True are taken into account""" # Add a Switch VTherm 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_USE_CENTRAL_MODE: True, CONF_CYCLE_MIN: 5, CONF_TEMP_MIN: 8, CONF_TEMP_MAX: 18, "frost_temp": 10, "eco_temp": 17, "comfort_temp": 18, "boost_temp": 21, CONF_USE_WINDOW_FEATURE: True, CONF_USE_MOTION_FEATURE: True, CONF_USE_POWER_FEATURE: False, CONF_USE_PRESENCE_FEATURE: False, CONF_HEATER: "switch.mock_switch", CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, CONF_TPI_COEF_INT: 0.3, CONF_TPI_COEF_EXT: 0.01, CONF_MINIMAL_ACTIVATION_DELAY: 30, CONF_SAFETY_DELAY_MIN: 5, CONF_SAFETY_MIN_ON_PERCENT: 0.3, CONF_SAFETY_DEFAULT_ON_PERCENT: 0.1, CONF_WINDOW_SENSOR: "binary_sensor.window_sensor", CONF_WINDOW_DELAY: 0, # To be not obliged to wait CONF_MOTION_SENSOR: "input_boolean.motion_sensor", CONF_MOTION_DELAY: 10, CONF_MOTION_OFF_DELAY: 30, CONF_MOTION_PRESET: PRESET_BOOST, CONF_NO_MOTION_PRESET: PRESET_ECO, }, ) tz = get_tz(hass) # pylint: disable=invalid-name event_timestamp = datetime.now(tz) # 1 initialize entity and find select entity with patch("homeassistant.core.ServiceRegistry.async_call"): entity: ThermostatOverSwitch = await create_thermostat( hass, entry, "climate.theoverswitchmockname" ) assert entity assert entity.is_controlled_by_central_mode assert entity.last_central_mode is None # Find the select entity select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) assert select_entity assert select_entity.current_option == CENTRAL_MODE_AUTO assert select_entity.options == CENTRAL_MODES # start entity await entity.async_set_hvac_mode(HVACMode.HEAT) await entity.async_set_preset_mode(PRESET_ACTIVITY) assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_ACTIVITY assert entity.window_state is STATE_UNKNOWN # 2 Open the window with patch( "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" ) as mock_send_event, patch( "homeassistant.helpers.condition.state", return_value=True ): event_timestamp = event_timestamp + timedelta(minutes=1) try_function = await send_window_change_event( entity, True, False, event_timestamp ) await try_function(None) assert mock_send_event.call_count == 1 mock_send_event.assert_has_calls( [call.send_event(EventType.HVAC_MODE_EVENT, {"hvac_mode": HVACMode.OFF})] ) assert entity.hvac_mode == HVACMode.OFF assert entity.preset_mode == PRESET_ACTIVITY assert entity._saved_hvac_mode == HVACMode.HEAT assert entity._saved_preset_mode == PRESET_ACTIVITY assert entity.window_state is STATE_ON # 3 Change central_mode to STOPPED with patch("homeassistant.core.ServiceRegistry.async_call"): event_timestamp = event_timestamp + timedelta(minutes=1) entity._set_now(event_timestamp) await select_entity.async_select_option(CENTRAL_MODE_STOPPED) assert entity.last_central_mode is CENTRAL_MODE_STOPPED # No change assert entity.hvac_mode == HVACMode.OFF assert entity.preset_mode == PRESET_ACTIVITY assert entity._saved_hvac_mode == HVACMode.HEAT assert entity._saved_preset_mode == PRESET_ACTIVITY # 4 Close the window with patch( "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" ) as mock_send_event, patch( "homeassistant.helpers.condition.state", return_value=True ): event_timestamp = event_timestamp + timedelta(minutes=1) try_function = await send_window_change_event( entity, False, True, event_timestamp ) await try_function(None) # No hvac_mode change cause the central mode is STOPPED assert mock_send_event.call_count == 0 # We should stay off because central is STOPPED assert entity.hvac_mode == HVACMode.OFF assert entity.preset_mode == PRESET_ACTIVITY assert entity._saved_hvac_mode == HVACMode.HEAT assert entity._saved_preset_mode == PRESET_ACTIVITY assert entity.window_state is STATE_OFF # 5 Back to Auto with patch( "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" ) as mock_send_event: event_timestamp = event_timestamp + timedelta(minutes=1) await select_entity.async_select_option(CENTRAL_MODE_AUTO) assert mock_send_event.call_count == 1 mock_send_event.assert_has_calls( [call.send_event(EventType.HVAC_MODE_EVENT, {"hvac_mode": HVACMode.HEAT})] ) # We should switch back to HEAT assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_ACTIVITY assert entity._saved_hvac_mode == HVACMode.HEAT assert entity._saved_preset_mode == PRESET_ACTIVITY assert entity.window_state is STATE_OFF @pytest.mark.parametrize("expected_lingering_tasks", [True]) @pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_switch_change_central_mode_true_with_cool_only_and_window( hass: HomeAssistant, skip_hass_states_is_state, init_central_config ): """test that changes with over_switch config with central_mode True are taken into account""" # Add a Switch VTherm 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_USE_CENTRAL_MODE: True, CONF_CYCLE_MIN: 5, CONF_TEMP_MIN: 8, CONF_TEMP_MAX: 18, "frost_temp": 10, "eco_temp": 17, "comfort_temp": 18, "boost_temp": 21, CONF_USE_WINDOW_FEATURE: True, CONF_USE_MOTION_FEATURE: True, CONF_USE_POWER_FEATURE: False, CONF_USE_PRESENCE_FEATURE: False, CONF_HEATER: "switch.mock_switch", CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, CONF_TPI_COEF_INT: 0.3, CONF_TPI_COEF_EXT: 0.01, CONF_MINIMAL_ACTIVATION_DELAY: 30, CONF_SAFETY_DELAY_MIN: 5, CONF_SAFETY_MIN_ON_PERCENT: 0.3, CONF_SAFETY_DEFAULT_ON_PERCENT: 0.1, CONF_WINDOW_SENSOR: "binary_sensor.window_sensor", CONF_WINDOW_DELAY: 0, # To be not obliged to wait CONF_MOTION_SENSOR: "input_boolean.motion_sensor", CONF_MOTION_DELAY: 10, CONF_MOTION_OFF_DELAY: 30, CONF_MOTION_PRESET: PRESET_BOOST, CONF_NO_MOTION_PRESET: PRESET_ECO, }, ) tz = get_tz(hass) # pylint: disable=invalid-name event_timestamp = datetime.now(tz) # 1 initialize entity and find select entity with patch("homeassistant.core.ServiceRegistry.async_call"): entity: ThermostatOverSwitch = await create_thermostat( hass, entry, "climate.theoverswitchmockname" ) assert entity assert entity.is_controlled_by_central_mode assert entity.last_central_mode is None # Find the select entity select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) assert select_entity assert select_entity.current_option == CENTRAL_MODE_AUTO assert select_entity.options == CENTRAL_MODES # start entity await entity.async_set_hvac_mode(HVACMode.HEAT) await entity.async_set_preset_mode(PRESET_ACTIVITY) assert entity.hvac_mode == HVACMode.HEAT assert entity.preset_mode == PRESET_ACTIVITY assert entity.window_state is STATE_UNKNOWN # 2 Change central_mode to COOL_ONLY with patch("homeassistant.core.ServiceRegistry.async_call"): event_timestamp = event_timestamp + timedelta(minutes=1) entity._set_now(event_timestamp) await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) assert entity.last_central_mode is CENTRAL_MODE_COOL_ONLY assert entity.hvac_mode is HVACMode.OFF assert entity.hvac_off_reason == HVAC_OFF_REASON_MANUAL await entity.async_set_preset_mode(PRESET_ACTIVITY) assert entity._saved_hvac_mode == HVACMode.HEAT assert entity._saved_preset_mode == PRESET_ACTIVITY # 3 Open the window with patch( "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" ) as mock_send_event, patch( "homeassistant.helpers.condition.state", return_value=True ): event_timestamp = event_timestamp + timedelta(minutes=1) try_function = await send_window_change_event( entity, True, False, event_timestamp ) await try_function(None) # The VTherm is already off -> window detection is ignored assert mock_send_event.call_count == 0 # mock_send_event.assert_has_calls( # [call.send_event(EventType.HVAC_MODE_EVENT, {"hvac_mode": HVACMode.OFF})] # ) assert entity.hvac_mode == HVACMode.OFF assert entity.hvac_off_reason == HVAC_OFF_REASON_MANUAL assert entity.preset_mode == PRESET_ACTIVITY assert entity._saved_hvac_mode == HVACMode.HEAT assert entity._saved_preset_mode == PRESET_ACTIVITY assert entity.window_state is STATE_ON # 4 Change central_mode to AUTO with patch("homeassistant.core.ServiceRegistry.async_call"): event_timestamp = event_timestamp + timedelta(minutes=1) entity._set_now(event_timestamp) await select_entity.async_select_option(CENTRAL_MODE_AUTO) assert entity.last_central_mode is CENTRAL_MODE_AUTO # No change assert entity.hvac_mode == HVACMode.OFF # We have to a reason of WINDOW_DETECTION assert entity.hvac_off_reason == HVAC_OFF_REASON_WINDOW_DETECTION assert entity.preset_mode == PRESET_ACTIVITY assert entity._saved_hvac_mode == HVACMode.HEAT assert entity._saved_preset_mode == PRESET_ACTIVITY # 5 Close the window with patch( "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" ) as mock_send_event, patch( "homeassistant.helpers.condition.state", return_value=True ): event_timestamp = event_timestamp + timedelta(minutes=1) try_function = await send_window_change_event( entity, False, True, event_timestamp ) await try_function(None) # hvac_mode change to HEAT assert mock_send_event.call_count == 1 mock_send_event.assert_has_calls( [call.send_event(EventType.HVAC_MODE_EVENT, {"hvac_mode": HVACMode.HEAT})] ) # We should stay off because central is STOPPED assert entity.hvac_mode == HVACMode.HEAT assert entity.hvac_off_reason is None assert entity.preset_mode == PRESET_ACTIVITY assert entity._saved_hvac_mode == HVACMode.HEAT assert entity._saved_preset_mode == PRESET_ACTIVITY assert entity.window_state is STATE_OFF