Compare commits
6 Commits
6.3.0.beta
...
6.3.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70f91f3cbe | ||
|
|
668053b352 | ||
|
|
6ff9ff1ee5 | ||
|
|
3f95ed74f4 | ||
|
|
6e42904ddf | ||
|
|
4c1fc396fb |
@@ -13,7 +13,6 @@ from homeassistant.util import dt as dt_util
|
|||||||
from homeassistant.core import (
|
from homeassistant.core import (
|
||||||
HomeAssistant,
|
HomeAssistant,
|
||||||
callback,
|
callback,
|
||||||
CoreState,
|
|
||||||
Event,
|
Event,
|
||||||
State,
|
State,
|
||||||
)
|
)
|
||||||
@@ -57,7 +56,6 @@ from homeassistant.const import (
|
|||||||
STATE_UNKNOWN,
|
STATE_UNKNOWN,
|
||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
STATE_ON,
|
STATE_ON,
|
||||||
EVENT_HOMEASSISTANT_START,
|
|
||||||
STATE_HOME,
|
STATE_HOME,
|
||||||
STATE_NOT_HOME,
|
STATE_NOT_HOME,
|
||||||
)
|
)
|
||||||
@@ -299,7 +297,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
|||||||
self._presets: dict[str, Any] = {} # presets
|
self._presets: dict[str, Any] = {} # presets
|
||||||
self._presets_away: dict[str, Any] = {} # presets_away
|
self._presets_away: dict[str, Any] = {} # presets_away
|
||||||
|
|
||||||
self._attr_preset_modes: list[str] | None
|
self._attr_preset_modes: list[str] = []
|
||||||
|
|
||||||
self._use_central_config_temperature = False
|
self._use_central_config_temperature = False
|
||||||
|
|
||||||
@@ -1237,7 +1235,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# If AC is on maybe we have to change the temperature in force mode, but not in frost mode (there is no Frost protection possible in AC mode)
|
# If AC is on maybe we have to change the temperature in force mode, but not in frost mode (there is no Frost protection possible in AC mode)
|
||||||
if self._hvac_mode == HVACMode.COOL and self.preset_mode != PRESET_NONE:
|
if self._hvac_mode in [HVACMode.COOL, HVACMode.HEAT, HVACMode.HEAT_COOL] and self.preset_mode != PRESET_NONE:
|
||||||
if self.preset_mode != PRESET_FROST_PROTECTION:
|
if self.preset_mode != PRESET_FROST_PROTECTION:
|
||||||
await self._async_set_preset_mode_internal(self.preset_mode, True)
|
await self._async_set_preset_mode_internal(self.preset_mode, True)
|
||||||
else:
|
else:
|
||||||
@@ -2183,7 +2181,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
|||||||
new_central_mode,
|
new_central_mode,
|
||||||
)
|
)
|
||||||
|
|
||||||
first_init = self._last_central_mode == None
|
first_init = self._last_central_mode is None
|
||||||
|
|
||||||
self._last_central_mode = new_central_mode
|
self._last_central_mode = new_central_mode
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,13 @@ async def async_setup_entry(
|
|||||||
entity = ThermostatOverClimate(hass, unique_id, name, entry.data)
|
entity = ThermostatOverClimate(hass, unique_id, name, entry.data)
|
||||||
elif vt_type == CONF_THERMOSTAT_VALVE:
|
elif vt_type == CONF_THERMOSTAT_VALVE:
|
||||||
entity = ThermostatOverValve(hass, unique_id, name, entry.data)
|
entity = ThermostatOverValve(hass, unique_id, name, entry.data)
|
||||||
|
else:
|
||||||
|
_LOGGER.error(
|
||||||
|
"Cannot create Versatile Thermostat name=%s of type %s which is unknown",
|
||||||
|
name,
|
||||||
|
vt_type,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
async_add_entities([entity], True)
|
async_add_entities([entity], True)
|
||||||
|
|
||||||
|
|||||||
@@ -99,30 +99,31 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
|||||||
|
|
||||||
def _init_feature_flags(self, _):
|
def _init_feature_flags(self, _):
|
||||||
"""Fix features selection depending to infos"""
|
"""Fix features selection depending to infos"""
|
||||||
is_empty: bool = False # TODO remove this not bool(infos)
|
|
||||||
is_central_config = (
|
is_central_config = (
|
||||||
self._infos.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_CENTRAL_CONFIG
|
self._infos.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_CENTRAL_CONFIG
|
||||||
)
|
)
|
||||||
|
|
||||||
self._infos[CONF_USE_WINDOW_FEATURE] = (
|
self._infos[CONF_USE_WINDOW_FEATURE] = (
|
||||||
is_empty
|
self._infos.get(CONF_USE_WINDOW_CENTRAL_CONFIG)
|
||||||
or self._infos.get(CONF_WINDOW_SENSOR) is not None
|
or self._infos.get(CONF_WINDOW_SENSOR) is not None
|
||||||
or self._infos.get(CONF_WINDOW_AUTO_OPEN_THRESHOLD) is not None
|
or self._infos.get(CONF_WINDOW_AUTO_OPEN_THRESHOLD) is not None
|
||||||
)
|
)
|
||||||
self._infos[CONF_USE_MOTION_FEATURE] = (
|
self._infos[CONF_USE_MOTION_FEATURE] = self._infos.get(
|
||||||
is_empty
|
CONF_USE_MOTION_FEATURE
|
||||||
or self._infos.get(CONF_MOTION_SENSOR) is not None
|
) and (self._infos.get(CONF_MOTION_SENSOR) is not None or is_central_config)
|
||||||
or is_central_config
|
|
||||||
)
|
self._infos[CONF_USE_POWER_FEATURE] = self._infos.get(
|
||||||
self._infos[CONF_USE_POWER_FEATURE] = is_empty or (
|
CONF_USE_POWER_CENTRAL_CONFIG
|
||||||
|
) or (
|
||||||
self._infos.get(CONF_POWER_SENSOR) is not None
|
self._infos.get(CONF_POWER_SENSOR) is not None
|
||||||
and self._infos.get(CONF_MAX_POWER_SENSOR) is not None
|
and self._infos.get(CONF_MAX_POWER_SENSOR) is not None
|
||||||
)
|
)
|
||||||
self._infos[CONF_USE_PRESENCE_FEATURE] = (
|
self._infos[CONF_USE_PRESENCE_FEATURE] = (
|
||||||
is_empty or self._infos.get(CONF_PRESENCE_SENSOR) is not None
|
self._infos.get(CONF_USE_PRESENCE_CENTRAL_CONFIG)
|
||||||
|
or self._infos.get(CONF_PRESENCE_SENSOR) is not None
|
||||||
)
|
)
|
||||||
|
|
||||||
self._infos[CONF_USE_CENTRAL_BOILER_FEATURE] = is_empty or (
|
self._infos[CONF_USE_CENTRAL_BOILER_FEATURE] = (
|
||||||
self._infos.get(CONF_CENTRAL_BOILER_ACTIVATION_SRV) is not None
|
self._infos.get(CONF_CENTRAL_BOILER_ACTIVATION_SRV) is not None
|
||||||
and self._infos.get(CONF_CENTRAL_BOILER_DEACTIVATION_SRV) is not None
|
and self._infos.get(CONF_CENTRAL_BOILER_DEACTIVATION_SRV) is not None
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -142,7 +142,17 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
|
|||||||
"""Sends the regulated temperature to all underlying"""
|
"""Sends the regulated temperature to all underlying"""
|
||||||
|
|
||||||
if self.hvac_mode == HVACMode.OFF:
|
if self.hvac_mode == HVACMode.OFF:
|
||||||
_LOGGER.debug("%s - don't send regulated temperature cause VTherm is off ")
|
_LOGGER.debug(
|
||||||
|
"%s - don't send regulated temperature cause VTherm is off ", self
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.target_temperature is None:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"%s - don't send regulated temperature cause VTherm target_temp (%s) is None. This should be a temporary warning message.",
|
||||||
|
self,
|
||||||
|
self.target_temperature,
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
@@ -169,16 +179,17 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
|
|||||||
|
|
||||||
# use _attr_target_temperature_step to round value if _auto_regulation_dtemp is equal to 0
|
# use _attr_target_temperature_step to round value if _auto_regulation_dtemp is equal to 0
|
||||||
regulation_step = self._auto_regulation_dtemp if self._auto_regulation_dtemp else self._attr_target_temperature_step
|
regulation_step = self._auto_regulation_dtemp if self._auto_regulation_dtemp else self._attr_target_temperature_step
|
||||||
_LOGGER.debug("%s - usage of regulation_step: %.2f ",
|
_LOGGER.debug("%s - usage regulation_step: %.2f ", self, regulation_step)
|
||||||
self,
|
|
||||||
regulation_step)
|
if self.current_temperature is not None:
|
||||||
|
new_regulated_temp = round_to_nearest(
|
||||||
new_regulated_temp = round_to_nearest(
|
self._regulation_algo.calculate_regulated_temperature(
|
||||||
self._regulation_algo.calculate_regulated_temperature(
|
self.current_temperature, self._cur_ext_temp
|
||||||
self.current_temperature, self._cur_ext_temp
|
),
|
||||||
),
|
regulation_step,
|
||||||
regulation_step,
|
)
|
||||||
)
|
else:
|
||||||
|
new_regulated_temp = self.target_temperature
|
||||||
dtemp = new_regulated_temp - self._regulated_target_temp
|
dtemp = new_regulated_temp - self._regulated_target_temp
|
||||||
|
|
||||||
if not force and abs(dtemp) < self._auto_regulation_dtemp:
|
if not force and abs(dtemp) < self._auto_regulation_dtemp:
|
||||||
@@ -203,8 +214,10 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
|
|||||||
offset_temp = 0
|
offset_temp = 0
|
||||||
device_temp = 0
|
device_temp = 0
|
||||||
if (
|
if (
|
||||||
|
# current_temperature is set
|
||||||
|
self.current_temperature is not None
|
||||||
# regulation can use the device_temp
|
# regulation can use the device_temp
|
||||||
self.auto_regulation_use_device_temp
|
and self.auto_regulation_use_device_temp
|
||||||
# and we have access to the device temp
|
# and we have access to the device temp
|
||||||
and (device_temp := under.underlying_current_temperature) is not None
|
and (device_temp := under.underlying_current_temperature) is not None
|
||||||
# and target is not reach (ie we need regulation)
|
# and target is not reach (ie we need regulation)
|
||||||
|
|||||||
@@ -987,3 +987,8 @@ async def set_climate_preset_temp(
|
|||||||
)
|
)
|
||||||
if temp_entity:
|
if temp_entity:
|
||||||
await temp_entity.async_set_native_value(temp)
|
await temp_entity.async_set_native_value(temp)
|
||||||
|
else:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"commons tests set_cliamte_preset_temp: cannot find number entity with entity_id '%s'",
|
||||||
|
number_entity_id,
|
||||||
|
)
|
||||||
|
|||||||
@@ -53,18 +53,6 @@ async def test_over_climate_regulation(
|
|||||||
return_value=fake_underlying_climate,
|
return_value=fake_underlying_climate,
|
||||||
):
|
):
|
||||||
entity = await create_thermostat(hass, entry, "climate.theoverclimatemockname")
|
entity = await create_thermostat(hass, entry, "climate.theoverclimatemockname")
|
||||||
# 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: ThermostatOverClimate = find_my_entity("climate.theoverclimatemockname")
|
|
||||||
|
|
||||||
assert entity
|
assert entity
|
||||||
assert isinstance(entity, ThermostatOverClimate)
|
assert isinstance(entity, ThermostatOverClimate)
|
||||||
@@ -163,18 +151,6 @@ async def test_over_climate_regulation_ac_mode(
|
|||||||
return_value=fake_underlying_climate,
|
return_value=fake_underlying_climate,
|
||||||
):
|
):
|
||||||
entity = await create_thermostat(hass, entry, "climate.theoverclimatemockname")
|
entity = await create_thermostat(hass, entry, "climate.theoverclimatemockname")
|
||||||
# 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: ThermostatOverClimate = find_my_entity("climate.theoverclimatemockname")
|
|
||||||
|
|
||||||
assert entity
|
assert entity
|
||||||
assert isinstance(entity, ThermostatOverClimate)
|
assert isinstance(entity, ThermostatOverClimate)
|
||||||
@@ -626,9 +602,7 @@ async def test_over_climate_regulation_dtemp_null(
|
|||||||
|
|
||||||
# the regulated temperature should be greater
|
# the regulated temperature should be greater
|
||||||
assert entity.regulated_target_temp > entity.target_temperature
|
assert entity.regulated_target_temp > entity.target_temperature
|
||||||
assert (
|
assert entity.regulated_target_temp == 20 + 0.9
|
||||||
entity.regulated_target_temp == 20 + 0.9
|
|
||||||
)
|
|
||||||
|
|
||||||
# change temperature so that the regulated temperature should slow down
|
# change temperature so that the regulated temperature should slow down
|
||||||
event_timestamp = now - timedelta(minutes=13)
|
event_timestamp = now - timedelta(minutes=13)
|
||||||
@@ -641,9 +615,7 @@ async def test_over_climate_regulation_dtemp_null(
|
|||||||
|
|
||||||
# the regulated temperature should be greater
|
# the regulated temperature should be greater
|
||||||
assert entity.regulated_target_temp > entity.target_temperature
|
assert entity.regulated_target_temp > entity.target_temperature
|
||||||
assert (
|
assert entity.regulated_target_temp == 20 + 0.5
|
||||||
entity.regulated_target_temp == 20 + 0.5
|
|
||||||
)
|
|
||||||
|
|
||||||
old_regulated_temp = entity.regulated_target_temp
|
old_regulated_temp = entity.regulated_target_temp
|
||||||
# Test if a small temperature change is taken into account : change temperature so that dtemp < 0.5 and time is > period_min (+ 3min)
|
# Test if a small temperature change is taken into account : change temperature so that dtemp < 0.5 and time is > period_min (+ 3min)
|
||||||
@@ -656,4 +628,4 @@ async def test_over_climate_regulation_dtemp_null(
|
|||||||
await send_ext_temperature_change_event(entity, 10, event_timestamp)
|
await send_ext_temperature_change_event(entity, 10, event_timestamp)
|
||||||
|
|
||||||
# the regulated temperature should be greater. This does not work if dtemp is not null
|
# the regulated temperature should be greater. This does not work if dtemp is not null
|
||||||
assert entity.regulated_target_temp > old_regulated_temp
|
assert entity.regulated_target_temp > old_regulated_temp
|
||||||
|
|||||||
@@ -12,6 +12,18 @@ from homeassistant.components.climate import (
|
|||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
from custom_components.versatile_thermostat.config_flow import (
|
||||||
|
VersatileThermostatBaseConfigFlow,
|
||||||
|
)
|
||||||
|
from custom_components.versatile_thermostat.thermostat_valve import ThermostatOverValve
|
||||||
|
from custom_components.versatile_thermostat.thermostat_climate import (
|
||||||
|
ThermostatOverClimate,
|
||||||
|
)
|
||||||
|
from custom_components.versatile_thermostat.thermostat_switch import (
|
||||||
|
ThermostatOverSwitch,
|
||||||
|
)
|
||||||
|
|
||||||
from .commons import *
|
from .commons import *
|
||||||
|
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
@@ -1013,3 +1025,189 @@ async def test_bug_508(
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
|
async def test_bug_500_1(hass: HomeAssistant, init_vtherm_api) -> None:
|
||||||
|
"""Test that the form is served with no input"""
|
||||||
|
|
||||||
|
config = {
|
||||||
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH,
|
||||||
|
CONF_USE_WINDOW_CENTRAL_CONFIG: True,
|
||||||
|
CONF_USE_POWER_CENTRAL_CONFIG: True,
|
||||||
|
CONF_USE_PRESENCE_CENTRAL_CONFIG: True,
|
||||||
|
CONF_USE_MOTION_FEATURE: True,
|
||||||
|
CONF_MOTION_SENSOR: "sensor.theMotionSensor",
|
||||||
|
}
|
||||||
|
|
||||||
|
flow = VersatileThermostatBaseConfigFlow(config)
|
||||||
|
|
||||||
|
assert flow._infos[CONF_USE_WINDOW_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_POWER_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_PRESENCE_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_MOTION_FEATURE] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
|
async def test_bug_500_2(hass: HomeAssistant, init_vtherm_api) -> None:
|
||||||
|
"""Test that the form is served with no input"""
|
||||||
|
|
||||||
|
config = {
|
||||||
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH,
|
||||||
|
CONF_USE_WINDOW_CENTRAL_CONFIG: False,
|
||||||
|
CONF_USE_POWER_CENTRAL_CONFIG: False,
|
||||||
|
CONF_USE_PRESENCE_CENTRAL_CONFIG: False,
|
||||||
|
CONF_USE_MOTION_FEATURE: False,
|
||||||
|
}
|
||||||
|
|
||||||
|
flow = VersatileThermostatBaseConfigFlow(config)
|
||||||
|
|
||||||
|
assert flow._infos[CONF_USE_WINDOW_FEATURE] is False
|
||||||
|
assert flow._infos[CONF_USE_POWER_FEATURE] is False
|
||||||
|
assert flow._infos[CONF_USE_PRESENCE_FEATURE] is False
|
||||||
|
assert flow._infos[CONF_USE_MOTION_FEATURE] is False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
|
async def test_bug_500_3(hass: HomeAssistant, init_vtherm_api) -> None:
|
||||||
|
"""Test that the form is served with no input"""
|
||||||
|
|
||||||
|
config = {
|
||||||
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH,
|
||||||
|
CONF_USE_WINDOW_CENTRAL_CONFIG: False,
|
||||||
|
CONF_WINDOW_SENSOR: "sensor.theWindowSensor",
|
||||||
|
CONF_USE_POWER_CENTRAL_CONFIG: False,
|
||||||
|
CONF_POWER_SENSOR: "sensor.thePowerSensor",
|
||||||
|
CONF_MAX_POWER_SENSOR: "sensor.theMaxPowerSensor",
|
||||||
|
CONF_USE_PRESENCE_CENTRAL_CONFIG: False,
|
||||||
|
CONF_PRESENCE_SENSOR: "sensor.thePresenceSensor",
|
||||||
|
CONF_USE_MOTION_FEATURE: True, # motion sensor need to be checked AND a motion sensor set
|
||||||
|
CONF_MOTION_SENSOR: "sensor.theMotionSensor",
|
||||||
|
}
|
||||||
|
|
||||||
|
flow = VersatileThermostatBaseConfigFlow(config)
|
||||||
|
|
||||||
|
assert flow._infos[CONF_USE_WINDOW_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_POWER_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_PRESENCE_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_MOTION_FEATURE] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
|
async def test_bug_524(hass: HomeAssistant, skip_hass_states_is_state):
|
||||||
|
"""Test when switching from Cool to Heat the new temperature in Heat mode should be used"""
|
||||||
|
|
||||||
|
vtherm_api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(hass)
|
||||||
|
|
||||||
|
# The temperatures to set
|
||||||
|
temps = {
|
||||||
|
"frost": 7.0,
|
||||||
|
"eco": 17.0,
|
||||||
|
"comfort": 19.0,
|
||||||
|
"boost": 21.0,
|
||||||
|
"eco_ac": 27.0,
|
||||||
|
"comfort_ac": 25.0,
|
||||||
|
"boost_ac": 23.0,
|
||||||
|
"frost_away": 7.1,
|
||||||
|
"eco_away": 17.1,
|
||||||
|
"comfort_away": 19.1,
|
||||||
|
"boost_away": 21.1,
|
||||||
|
"eco_ac_away": 27.1,
|
||||||
|
"comfort_ac_away": 25.1,
|
||||||
|
"boost_ac_away": 23.1,
|
||||||
|
}
|
||||||
|
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
title="TheOverClimateMockName",
|
||||||
|
unique_id="overClimateUniqueId",
|
||||||
|
data={
|
||||||
|
CONF_NAME: "overClimate",
|
||||||
|
CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
|
||||||
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE,
|
||||||
|
CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
|
||||||
|
CONF_CYCLE_MIN: 5,
|
||||||
|
CONF_TEMP_MIN: 15,
|
||||||
|
CONF_TEMP_MAX: 30,
|
||||||
|
CONF_USE_WINDOW_FEATURE: False,
|
||||||
|
CONF_USE_MOTION_FEATURE: False,
|
||||||
|
CONF_USE_POWER_FEATURE: False,
|
||||||
|
CONF_USE_PRESENCE_FEATURE: True,
|
||||||
|
CONF_PRESENCE_SENSOR: "binary_sensor.presence_sensor",
|
||||||
|
CONF_CLIMATE: "climate.mock_climate",
|
||||||
|
CONF_MINIMAL_ACTIVATION_DELAY: 30,
|
||||||
|
CONF_SECURITY_DELAY_MIN: 5,
|
||||||
|
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
||||||
|
CONF_AUTO_FAN_MODE: CONF_AUTO_FAN_TURBO,
|
||||||
|
CONF_AC_MODE: True,
|
||||||
|
},
|
||||||
|
# | temps,
|
||||||
|
)
|
||||||
|
|
||||||
|
fake_underlying_climate = MockClimate(
|
||||||
|
hass=hass,
|
||||||
|
unique_id="mock_climate",
|
||||||
|
name="mock_climate",
|
||||||
|
hvac_modes=[HVACMode.OFF, HVACMode.COOL, HVACMode.HEAT, HVACMode.FAN_ONLY],
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
|
||||||
|
return_value=fake_underlying_climate,
|
||||||
|
):
|
||||||
|
vtherm: ThermostatOverClimate = await create_thermostat(
|
||||||
|
hass, config_entry, "climate.overclimate"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert vtherm is not None
|
||||||
|
|
||||||
|
# We search for NumberEntities
|
||||||
|
for preset_name, value in temps.items():
|
||||||
|
|
||||||
|
await set_climate_preset_temp(vtherm, preset_name, value)
|
||||||
|
|
||||||
|
temp_entity: NumberEntity = search_entity(
|
||||||
|
hass,
|
||||||
|
"number.overclimate_preset_" + preset_name + PRESET_TEMP_SUFFIX,
|
||||||
|
NUMBER_DOMAIN,
|
||||||
|
)
|
||||||
|
assert temp_entity
|
||||||
|
# Because set_value is not implemented in Number class (really don't understand why...)
|
||||||
|
assert temp_entity.state == value
|
||||||
|
|
||||||
|
# 1. Set mode to Heat and preset to Comfort
|
||||||
|
await send_presence_change_event(vtherm, True, False, datetime.now())
|
||||||
|
await vtherm.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
|
await vtherm.async_set_preset_mode(PRESET_COMFORT)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert vtherm.target_temperature == 19.0
|
||||||
|
|
||||||
|
# 2. Only change the HVAC_MODE (and keep preset to comfort)
|
||||||
|
await vtherm.async_set_hvac_mode(HVACMode.COOL)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert vtherm.target_temperature == 25.0
|
||||||
|
|
||||||
|
# 3. Only change the HVAC_MODE (and keep preset to comfort)
|
||||||
|
await vtherm.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert vtherm.target_temperature == 19.0
|
||||||
|
|
||||||
|
# 4. Change presence to off
|
||||||
|
await send_presence_change_event(vtherm, False, True, datetime.now())
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert vtherm.target_temperature == 19.1
|
||||||
|
|
||||||
|
# 5. Change hvac_mode to AC
|
||||||
|
await vtherm.async_set_hvac_mode(HVACMode.COOL)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert vtherm.target_temperature == 25.1
|
||||||
|
|
||||||
|
# 6. Change presence to on
|
||||||
|
await send_presence_change_event(vtherm, True, False, datetime.now())
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert vtherm.target_temperature == 25
|
||||||
|
|||||||
@@ -731,7 +731,7 @@ async def test_update_central_boiler_state_simple_climate(
|
|||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
|
||||||
return_value=climate1,
|
return_value=climate1,
|
||||||
):
|
):
|
||||||
entity: ThermostatOverValve = await create_thermostat(
|
entity: ThermostatOverClimate = await create_thermostat(
|
||||||
hass, entry, "climate.theoverclimatemockname"
|
hass, entry, "climate.theoverclimatemockname"
|
||||||
)
|
)
|
||||||
assert entity
|
assert entity
|
||||||
|
|||||||
@@ -5,9 +5,6 @@ from unittest.mock import patch, call
|
|||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from custom_components.versatile_thermostat.thermostat_climate import (
|
|
||||||
ThermostatOverClimate,
|
|
||||||
)
|
|
||||||
from custom_components.versatile_thermostat.thermostat_switch import (
|
from custom_components.versatile_thermostat.thermostat_switch import (
|
||||||
ThermostatOverSwitch,
|
ThermostatOverSwitch,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user