Implementation of regulation
This commit is contained in:
@@ -11,6 +11,7 @@ from homeassistant.components.sensor import (
|
||||
SensorEntity,
|
||||
SensorDeviceClass,
|
||||
SensorStateClass,
|
||||
UnitOfTemperature
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
||||
@@ -24,6 +25,7 @@ from .const import (
|
||||
PROPORTIONAL_FUNCTION_TPI,
|
||||
CONF_THERMOSTAT_SWITCH,
|
||||
CONF_THERMOSTAT_VALVE,
|
||||
CONF_THERMOSTAT_CLIMATE,
|
||||
CONF_THERMOSTAT_TYPE,
|
||||
)
|
||||
|
||||
@@ -63,6 +65,9 @@ async def async_setup_entry(
|
||||
if entry.data.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_VALVE:
|
||||
entities.append(ValveOpenPercentSensor(hass, unique_id, name, entry.data))
|
||||
|
||||
if entry.data.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_CLIMATE:
|
||||
entities.append(RegulatedTemperatureSensor(hass, unique_id, name, entry.data))
|
||||
|
||||
async_add_entities(entities, True)
|
||||
|
||||
|
||||
@@ -470,3 +475,53 @@ class TemperatureSlopeSensor(VersatileThermostatBaseEntity, SensorEntity):
|
||||
def suggested_display_precision(self) -> int | None:
|
||||
"""Return the suggested number of decimal digits for display."""
|
||||
return 2
|
||||
|
||||
class RegulatedTemperatureSensor(VersatileThermostatBaseEntity, SensorEntity):
|
||||
"""Representation of a Energy sensor which exposes the energy"""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
|
||||
"""Initialize the regulated temperature sensor"""
|
||||
super().__init__(hass, unique_id, entry_infos.get(CONF_NAME))
|
||||
self._attr_name = "Regulated temperature"
|
||||
self._attr_unique_id = f"{self._device_name}_regulated_temperature"
|
||||
|
||||
@callback
|
||||
async def async_my_climate_changed(self, event: Event = None):
|
||||
"""Called when my climate have change"""
|
||||
_LOGGER.debug("%s - climate state change", self._attr_unique_id)
|
||||
|
||||
if math.isnan(self.my_climate.regulated_target_temp) or math.isinf(
|
||||
self.my_climate.regulated_target_temp
|
||||
):
|
||||
raise ValueError(f"Sensor has illegal state {self.my_climate.regulated_target_temp}")
|
||||
|
||||
old_state = self._attr_native_value
|
||||
self._attr_native_value = round(
|
||||
self.my_climate.regulated_target_temp, self.suggested_display_precision
|
||||
)
|
||||
if old_state != self._attr_native_value:
|
||||
self.async_write_ha_state()
|
||||
return
|
||||
|
||||
@property
|
||||
def icon(self) -> str | None:
|
||||
return "mdi:thermometer-auto"
|
||||
|
||||
@property
|
||||
def device_class(self) -> SensorDeviceClass | None:
|
||||
return SensorDeviceClass.TEMPERATURE
|
||||
|
||||
@property
|
||||
def state_class(self) -> SensorStateClass | None:
|
||||
return SensorStateClass.MEASUREMENT
|
||||
|
||||
@property
|
||||
def native_unit_of_measurement(self) -> str | None:
|
||||
if not self.my_climate:
|
||||
return UnitOfTemperature.CELSIUS
|
||||
return self.my_climate.temperature_unit
|
||||
|
||||
@property
|
||||
def suggested_display_precision(self) -> int | None:
|
||||
"""Return the suggested number of decimal digits for display."""
|
||||
return 1
|
||||
|
||||
@@ -40,7 +40,7 @@ class ThermostatOverClimate(BaseThermostat):
|
||||
_entity_component_unrecorded_attributes = BaseThermostat._entity_component_unrecorded_attributes.union(frozenset(
|
||||
{
|
||||
"is_over_climate", "start_hvac_action_date", "underlying_climate_0", "underlying_climate_1",
|
||||
"underlying_climate_2", "underlying_climate_3"
|
||||
"underlying_climate_2", "underlying_climate_3", "regulation_accumulated_error"
|
||||
}))
|
||||
|
||||
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
|
||||
@@ -197,6 +197,7 @@ class ThermostatOverClimate(BaseThermostat):
|
||||
|
||||
if self.is_regulated:
|
||||
self._attr_extra_state_attributes["regulated_target_temp"] = self._regulated_target_temp
|
||||
self._attr_extra_state_attributes["regulation_accumulated_error"] = self._regulation_algo.accumulated_error
|
||||
|
||||
self.async_write_ha_state()
|
||||
_LOGGER.debug(
|
||||
@@ -403,7 +404,8 @@ class ThermostatOverClimate(BaseThermostat):
|
||||
new_state.attributes,
|
||||
)
|
||||
if (
|
||||
self.is_over_climate
|
||||
# we do not change target temperature on regulated VTherm
|
||||
not self.is_regulated
|
||||
and new_state.attributes
|
||||
and (new_target_temp := new_state.attributes.get("temperature"))
|
||||
and new_target_temp != self.target_temperature
|
||||
|
||||
@@ -34,6 +34,8 @@ from .const import ( # pylint: disable=unused-import
|
||||
MOCK_TH_OVER_SWITCH_AC_TYPE_CONFIG,
|
||||
MOCK_TH_OVER_4SWITCH_TYPE_CONFIG,
|
||||
MOCK_TH_OVER_CLIMATE_TYPE_CONFIG,
|
||||
MOCK_TH_OVER_CLIMATE_TYPE_AC_CONFIG,
|
||||
MOCK_TH_OVER_CLIMATE_TYPE_NOT_REGULATED_CONFIG,
|
||||
MOCK_TH_OVER_SWITCH_TPI_CONFIG,
|
||||
MOCK_PRESETS_CONFIG,
|
||||
MOCK_PRESETS_AC_CONFIG,
|
||||
@@ -83,6 +85,20 @@ PARTIAL_CLIMATE_CONFIG = (
|
||||
| MOCK_ADVANCED_CONFIG
|
||||
)
|
||||
|
||||
PARTIAL_CLIMATE_NOT_REGULATED_CONFIG = (
|
||||
MOCK_TH_OVER_CLIMATE_USER_CONFIG
|
||||
| MOCK_TH_OVER_CLIMATE_TYPE_NOT_REGULATED_CONFIG
|
||||
| MOCK_PRESETS_CONFIG
|
||||
| MOCK_ADVANCED_CONFIG
|
||||
)
|
||||
|
||||
PARTIAL_CLIMATE_AC_CONFIG = (
|
||||
MOCK_TH_OVER_CLIMATE_USER_CONFIG
|
||||
| MOCK_TH_OVER_CLIMATE_TYPE_AC_CONFIG
|
||||
| MOCK_PRESETS_CONFIG
|
||||
| MOCK_ADVANCED_CONFIG
|
||||
)
|
||||
|
||||
FULL_4SWITCH_CONFIG = (
|
||||
MOCK_TH_OVER_4SWITCH_USER_CONFIG
|
||||
| MOCK_TH_OVER_4SWITCH_TYPE_CONFIG
|
||||
@@ -101,7 +117,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
class MockClimate(ClimateEntity):
|
||||
"""A Mock Climate class used for Underlying climate mode"""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos, hvac_mode:HVACMode = HVACMode.OFF) -> None: # pylint: disable=unused-argument
|
||||
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos, hvac_mode:HVACMode = HVACMode.OFF, hvac_action:HVACAction = HVACAction.OFF) -> None: # pylint: disable=unused-argument
|
||||
"""Initialize the thermostat."""
|
||||
|
||||
super().__init__()
|
||||
@@ -118,17 +134,25 @@ class MockClimate(ClimateEntity):
|
||||
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
self._attr_target_temperature = 20
|
||||
self._attr_current_temperature = 15
|
||||
self._attr_hvac_action = hvac_action
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
""" Set the target temperature"""
|
||||
temperature = kwargs.get(ATTR_TEMPERATURE)
|
||||
self._attr_target_temperature = temperature
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode):
|
||||
""" The hvac mode"""
|
||||
self._attr_hvac_mode = hvac_mode
|
||||
self.async_write_ha_state()
|
||||
|
||||
@property
|
||||
def hvac_action(self):
|
||||
""" The hvac action of the mock climate"""
|
||||
return self._attr_hvac_action
|
||||
|
||||
def set_hvac_action(self, hvac_action: HVACAction):
|
||||
""" Set the HVACaction """
|
||||
self._attr_hvac_action = hvac_action
|
||||
|
||||
class MockUnavailableClimate(ClimateEntity):
|
||||
"""A Mock Climate class used for Underlying climate mode"""
|
||||
|
||||
@@ -51,7 +51,8 @@ from custom_components.versatile_thermostat.const import (
|
||||
PRESET_AWAY_SUFFIX,
|
||||
CONF_CLIMATE,
|
||||
CONF_AUTO_REGULATION_MODE,
|
||||
CONF_AUTO_REGULATION_MEDIUM
|
||||
CONF_AUTO_REGULATION_MEDIUM,
|
||||
CONF_AUTO_REGULATION_NONE,
|
||||
)
|
||||
MOCK_TH_OVER_SWITCH_USER_CONFIG = {
|
||||
CONF_NAME: "TheOverSwitchMockName",
|
||||
@@ -127,6 +128,18 @@ MOCK_TH_OVER_CLIMATE_TYPE_CONFIG = {
|
||||
CONF_AUTO_REGULATION_MODE: CONF_AUTO_REGULATION_MEDIUM
|
||||
}
|
||||
|
||||
MOCK_TH_OVER_CLIMATE_TYPE_NOT_REGULATED_CONFIG = {
|
||||
CONF_CLIMATE: "climate.mock_climate",
|
||||
CONF_AC_MODE: False,
|
||||
CONF_AUTO_REGULATION_MODE: CONF_AUTO_REGULATION_NONE
|
||||
}
|
||||
|
||||
MOCK_TH_OVER_CLIMATE_TYPE_AC_CONFIG = {
|
||||
CONF_CLIMATE: "climate.mock_climate",
|
||||
CONF_AC_MODE: True,
|
||||
CONF_AUTO_REGULATION_MODE: CONF_AUTO_REGULATION_MEDIUM
|
||||
}
|
||||
|
||||
MOCK_PRESETS_CONFIG = {
|
||||
PRESET_ECO + "_temp": 16,
|
||||
PRESET_COMFORT + "_temp": 17,
|
||||
|
||||
210
tests/test_auto_regulation.py
Normal file
210
tests/test_auto_regulation.py
Normal file
@@ -0,0 +1,210 @@
|
||||
# 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 datetime import datetime, timedelta
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.components.climate import HVACAction, HVACMode
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.components.climate import ClimateEntity, DOMAIN as CLIMATE_DOMAIN
|
||||
|
||||
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 .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_climate_regulation(hass: HomeAssistant, skip_hass_states_is_state):
|
||||
"""Test the regulation of an over climate thermostat"""
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="TheOverClimateMockName",
|
||||
unique_id="uniqueId",
|
||||
# This is include a medium regulation
|
||||
data=PARTIAL_CLIMATE_CONFIG,
|
||||
)
|
||||
|
||||
tz = get_tz(hass) # pylint: disable=invalid-name
|
||||
now: datetime = datetime.now(tz=tz)
|
||||
|
||||
fake_underlying_climate = MockClimate(hass, "mockUniqueId", "MockClimateName", {})
|
||||
|
||||
# Creates the regulated VTherm over climate
|
||||
with patch(
|
||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||
), patch(
|
||||
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
|
||||
return_value=fake_underlying_climate,
|
||||
):
|
||||
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 isinstance(entity, ThermostatOverClimate)
|
||||
|
||||
assert entity.name == "TheOverClimateMockName"
|
||||
assert entity.is_over_climate is True
|
||||
assert entity.is_regulated 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_ECO,
|
||||
PRESET_COMFORT,
|
||||
PRESET_BOOST,
|
||||
]
|
||||
assert entity.preset_mode is PRESET_NONE
|
||||
|
||||
# Activate the heating by changing HVACMode and temperature
|
||||
with patch(
|
||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||
):
|
||||
# Select a hvacmode, presence and preset
|
||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||
assert entity.hvac_mode is HVACMode.HEAT
|
||||
assert entity.hvac_action == HVACAction.OFF
|
||||
|
||||
# change temperature so that the heating will start
|
||||
event_timestamp = now - timedelta(minutes=10)
|
||||
await send_temperature_change_event(entity, 15, event_timestamp)
|
||||
await send_ext_temperature_change_event(entity, 10, event_timestamp)
|
||||
|
||||
|
||||
# set manual target temp
|
||||
await entity.async_set_temperature(temperature=18)
|
||||
|
||||
fake_underlying_climate.set_hvac_action(HVACAction.HEATING) # simulate under heating
|
||||
assert entity.hvac_action == HVACAction.HEATING
|
||||
assert entity.preset_mode == PRESET_NONE # Manual mode
|
||||
|
||||
# the regulated temperature should be greater
|
||||
assert entity.regulated_target_temp > entity.target_temperature
|
||||
assert entity.regulated_target_temp == 18+2.9 # In medium we could go up to +3 degre
|
||||
assert entity.hvac_action == HVACAction.HEATING
|
||||
|
||||
# change temperature so that the regulated temperature should slow down
|
||||
event_timestamp = now - timedelta(minutes=9)
|
||||
await send_temperature_change_event(entity, 19, event_timestamp)
|
||||
await send_ext_temperature_change_event(entity, 18, event_timestamp)
|
||||
|
||||
# the regulated temperature should be under
|
||||
assert entity.regulated_target_temp < entity.target_temperature
|
||||
assert entity.regulated_target_temp == 18-0.1
|
||||
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||
async def test_over_climate_regulation_ac_mode(hass: HomeAssistant, skip_hass_states_is_state):
|
||||
"""Test the regulation of an over climate thermostat"""
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="TheOverClimateMockName",
|
||||
unique_id="uniqueId",
|
||||
# This is include a medium regulation
|
||||
data=PARTIAL_CLIMATE_AC_CONFIG,
|
||||
)
|
||||
|
||||
tz = get_tz(hass) # pylint: disable=invalid-name
|
||||
now: datetime = datetime.now(tz=tz)
|
||||
|
||||
fake_underlying_climate = MockClimate(hass, "mockUniqueId", "MockClimateName", {})
|
||||
|
||||
# Creates the regulated VTherm over climate
|
||||
with patch(
|
||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||
), patch(
|
||||
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
|
||||
return_value=fake_underlying_climate,
|
||||
):
|
||||
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 isinstance(entity, ThermostatOverClimate)
|
||||
|
||||
assert entity.name == "TheOverClimateMockName"
|
||||
assert entity.is_over_climate is True
|
||||
assert entity.is_regulated is True
|
||||
assert entity.hvac_action is HVACAction.OFF
|
||||
assert entity.hvac_mode is HVACMode.OFF
|
||||
assert entity.target_temperature == entity.max_temp
|
||||
assert entity.preset_modes == [
|
||||
PRESET_NONE,
|
||||
PRESET_ECO,
|
||||
PRESET_COMFORT,
|
||||
PRESET_BOOST,
|
||||
]
|
||||
assert entity.preset_mode is PRESET_NONE
|
||||
|
||||
# Activate the heating by changing HVACMode and temperature
|
||||
with patch(
|
||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||
):
|
||||
# Select a hvacmode, presence and preset
|
||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||
assert entity.hvac_mode is HVACMode.HEAT
|
||||
assert entity.hvac_action == HVACAction.OFF
|
||||
|
||||
# change temperature so that the heating will start
|
||||
event_timestamp = now - timedelta(minutes=10)
|
||||
await send_temperature_change_event(entity, 30, event_timestamp)
|
||||
await send_ext_temperature_change_event(entity, 35, event_timestamp)
|
||||
|
||||
|
||||
# set manual target temp
|
||||
await entity.async_set_temperature(temperature=25)
|
||||
|
||||
fake_underlying_climate.set_hvac_action(HVACAction.COOLING) # simulate under heating
|
||||
assert entity.hvac_action == HVACAction.COOLING
|
||||
assert entity.preset_mode == PRESET_NONE # Manual mode
|
||||
|
||||
# the regulated temperature should be lower
|
||||
assert entity.regulated_target_temp < entity.target_temperature
|
||||
assert entity.regulated_target_temp == 25-3 # In medium we could go up to -3 degre
|
||||
assert entity.hvac_action == HVACAction.COOLING
|
||||
|
||||
# change temperature so that the regulated temperature should slow down
|
||||
event_timestamp = now - timedelta(minutes=9)
|
||||
await send_temperature_change_event(entity, 26, event_timestamp)
|
||||
await send_ext_temperature_change_event(entity, 35, event_timestamp)
|
||||
|
||||
# the regulated temperature should be under
|
||||
assert entity.regulated_target_temp < entity.target_temperature
|
||||
assert entity.regulated_target_temp == 25-2.7
|
||||
|
||||
# change temperature so that the regulated temperature should slow down
|
||||
event_timestamp = now - timedelta(minutes=9)
|
||||
await send_temperature_change_event(entity, 20, event_timestamp)
|
||||
await send_ext_temperature_change_event(entity, 30, event_timestamp)
|
||||
|
||||
# the regulated temperature should be greater
|
||||
assert entity.regulated_target_temp > entity.target_temperature
|
||||
assert entity.regulated_target_temp == 25+1.8
|
||||
@@ -463,11 +463,11 @@ async def test_bug_101(
|
||||
domain=DOMAIN,
|
||||
title="TheOverClimateMockName",
|
||||
unique_id="uniqueId",
|
||||
data=PARTIAL_CLIMATE_CONFIG, # 5 minutes security delay
|
||||
data=PARTIAL_CLIMATE_NOT_REGULATED_CONFIG, # 5 minutes security delay
|
||||
)
|
||||
|
||||
# Underlying is in HEAT mode but should be shutdown at startup
|
||||
fake_underlying_climate = MockClimate(hass, "mockUniqueId", "MockClimateName", {}, HVACMode.HEAT)
|
||||
fake_underlying_climate = MockClimate(hass, "mockUniqueId", "MockClimateName", {}, HVACMode.HEAT, HVACAction.HEATING)
|
||||
|
||||
with patch(
|
||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||
@@ -495,7 +495,7 @@ async def test_bug_101(
|
||||
assert entity.name == "TheOverClimateMockName"
|
||||
assert entity.is_over_climate is True
|
||||
assert entity.hvac_mode is HVACMode.OFF
|
||||
# because the underlying is heating. In real life the underlying should be shut-off
|
||||
# because in MockClimate HVACAction is HEATING if hvac_mode is not set
|
||||
assert entity.hvac_action is HVACAction.HEATING
|
||||
# Underlying should have been shutdown
|
||||
assert mock_underlying_set_hvac_mode.call_count == 1
|
||||
@@ -539,6 +539,7 @@ async def test_bug_101(
|
||||
# 2. Change the target temp of underlying thermostat at 11 sec later -> the event will be taken
|
||||
# Wait 11 sec
|
||||
event_timestamp = now + timedelta(seconds=11)
|
||||
assert entity.is_regulated is False
|
||||
await send_climate_change_event_with_temperature(entity, HVACMode.HEAT, HVACMode.HEAT, HVACAction.OFF, HVACAction.OFF, event_timestamp, 12.75)
|
||||
assert entity.target_temperature == 12.75
|
||||
assert entity.preset_mode is PRESET_NONE
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
# pylint: disable=wildcard-import, unused-wildcard-import, protected-access, unused-argument, line-too-long
|
||||
|
||||
""" Test the Security featrure """
|
||||
from unittest.mock import patch, call
|
||||
|
||||
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||
|
||||
from datetime import timedelta, datetime
|
||||
import logging
|
||||
|
||||
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
|
||||
|
||||
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
@@ -55,7 +59,7 @@ async def test_security_feature(hass: HomeAssistant, skip_hass_states_is_state):
|
||||
|
||||
# 1. creates a thermostat and check that security is off
|
||||
now: datetime = datetime.now(tz=tz)
|
||||
entity: VersatileThermostat = await create_thermostat(
|
||||
entity: ThermostatOverSwitch = await create_thermostat(
|
||||
hass, entry, "climate.theoverswitchmockname"
|
||||
)
|
||||
assert entity
|
||||
@@ -211,7 +215,7 @@ async def test_security_over_climate(
|
||||
data=PARTIAL_CLIMATE_CONFIG, # 5 minutes security delay
|
||||
)
|
||||
|
||||
fake_underlying_climate = MockClimate(hass, "mockUniqueId", "MockClimateName", {}, HVACMode.HEAT)
|
||||
fake_underlying_climate = MockClimate(hass, "mockUniqueId", "MockClimateName", {}, HVACMode.HEAT, HVACAction.HEATING)
|
||||
|
||||
with patch(
|
||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||
@@ -230,7 +234,7 @@ async def test_security_over_climate(
|
||||
if entity.entity_id == entity_id:
|
||||
return entity
|
||||
|
||||
entity = find_my_entity("climate.theoverclimatemockname")
|
||||
entity: ThermostatOverClimate = find_my_entity("climate.theoverclimatemockname")
|
||||
|
||||
assert entity
|
||||
|
||||
@@ -295,11 +299,11 @@ async def test_security_over_climate(
|
||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||
) as mock_send_event, patch(
|
||||
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_on"
|
||||
) as mock_heater_on:
|
||||
):
|
||||
event_timestamp = now - timedelta(minutes=6)
|
||||
|
||||
await send_temperature_change_event(entity, 15, event_timestamp)
|
||||
# Should stay False because a climate is never in security mode
|
||||
assert entity.security_state is False
|
||||
assert entity.preset_mode == 'none'
|
||||
assert entity._saved_preset_mode == 'none'
|
||||
assert entity._saved_preset_mode == 'none'
|
||||
|
||||
Reference in New Issue
Block a user