First unit test ok
This commit is contained in:
@@ -138,7 +138,8 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
|||||||
"target_temperature_step",
|
"target_temperature_step",
|
||||||
"is_used_by_central_boiler",
|
"is_used_by_central_boiler",
|
||||||
"temperature_slope",
|
"temperature_slope",
|
||||||
"max_on_percent"
|
"max_on_percent",
|
||||||
|
"have_valve_regulation",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -2673,6 +2674,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
|||||||
"temperature_slope": round(self.last_temperature_slope or 0, 3),
|
"temperature_slope": round(self.last_temperature_slope or 0, 3),
|
||||||
"hvac_off_reason": self.hvac_off_reason,
|
"hvac_off_reason": self.hvac_off_reason,
|
||||||
"max_on_percent": self._max_on_percent,
|
"max_on_percent": self._max_on_percent,
|
||||||
|
"have_valve_regulation": self.have_valve_regulation,
|
||||||
}
|
}
|
||||||
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
@@ -2691,6 +2693,11 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
|||||||
)
|
)
|
||||||
return super().async_write_ha_state()
|
return super().async_write_ha_state()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def have_valve_regulation(self) -> bool:
|
||||||
|
"""True if the Thermostat is regulated by valve"""
|
||||||
|
return False
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_registry_entry_updated(self):
|
def async_registry_entry_updated(self):
|
||||||
"""update the entity if the config entry have been updated
|
"""update the entity if the config entry have been updated
|
||||||
|
|||||||
@@ -227,11 +227,12 @@ class ThermostatOverClimateValve(ThermostatOverClimate):
|
|||||||
return
|
return
|
||||||
|
|
||||||
for under in self._underlyings:
|
for under in self._underlyings:
|
||||||
await under.set_temperature(
|
if self.target_temperature != under.last_sent_temperature:
|
||||||
self.target_temperature,
|
await under.set_temperature(
|
||||||
self._attr_max_temp,
|
self.target_temperature,
|
||||||
self._attr_min_temp,
|
self._attr_max_temp,
|
||||||
)
|
self._attr_min_temp,
|
||||||
|
)
|
||||||
|
|
||||||
for under in self._underlyings_valve_regulation:
|
for under in self._underlyings_valve_regulation:
|
||||||
await under.set_valve_open_percent()
|
await under.set_valve_open_percent()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
""" Some common resources """
|
""" Some common resources """
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any, Dict, Callable
|
||||||
from unittest.mock import patch, MagicMock # pylint: disable=unused-import
|
from unittest.mock import patch, MagicMock # pylint: disable=unused-import
|
||||||
import pytest # pylint: disable=unused-import
|
import pytest # pylint: disable=unused-import
|
||||||
|
|
||||||
@@ -1007,12 +1008,50 @@ async def set_climate_preset_temp(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# The temperatures to set
|
||||||
|
default_temperatures_ac_away = {
|
||||||
|
"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,
|
||||||
|
}
|
||||||
|
|
||||||
|
default_temperatures_away = {
|
||||||
|
"frost": 7.0,
|
||||||
|
"eco": 17.0,
|
||||||
|
"comfort": 19.0,
|
||||||
|
"boost": 21.0,
|
||||||
|
"frost_away": 7.1,
|
||||||
|
"eco_away": 17.1,
|
||||||
|
"comfort_away": 19.1,
|
||||||
|
"boost_away": 21.1,
|
||||||
|
}
|
||||||
|
|
||||||
|
default_temperatures = {
|
||||||
|
"frost": 7.0,
|
||||||
|
"eco": 17.0,
|
||||||
|
"comfort": 19.0,
|
||||||
|
"boost": 21.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def set_all_climate_preset_temp(
|
async def set_all_climate_preset_temp(
|
||||||
hass, vtherm: BaseThermostat, temps: dict, number_entity_base_name: str
|
hass, vtherm: BaseThermostat, temps: dict | None, number_entity_base_name: str
|
||||||
):
|
):
|
||||||
"""Initialize all temp of preset for a VTherm entity"""
|
"""Initialize all temp of preset for a VTherm entity"""
|
||||||
|
local_temps = temps if temps is not None else default_temperatures
|
||||||
# We initialize
|
# We initialize
|
||||||
for preset_name, value in temps.items():
|
for preset_name, value in local_temps.items():
|
||||||
|
|
||||||
await set_climate_preset_temp(vtherm, preset_name, value)
|
await set_climate_preset_temp(vtherm, preset_name, value)
|
||||||
|
|
||||||
@@ -1028,3 +1067,31 @@ async def set_all_climate_preset_temp(
|
|||||||
assert temp_entity
|
assert temp_entity
|
||||||
# Because set_value is not implemented in Number class (really don't understand why...)
|
# Because set_value is not implemented in Number class (really don't understand why...)
|
||||||
assert temp_entity.state == value
|
assert temp_entity.state == value
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Side effects management
|
||||||
|
#
|
||||||
|
SideEffectDict = Dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
class SideEffects:
|
||||||
|
"""A class to manage sideEffects for mock"""
|
||||||
|
|
||||||
|
def __init__(self, side_effects: SideEffectDict, default_side_effect: Any):
|
||||||
|
"""Initialise the side effects"""
|
||||||
|
self._current_side_effects: SideEffectDict = side_effects
|
||||||
|
self._default_side_effect: Any = default_side_effect
|
||||||
|
|
||||||
|
def get_side_effects(self) -> Callable[[str], Any]:
|
||||||
|
"""returns the method which apply the side effects"""
|
||||||
|
|
||||||
|
def side_effect_method(arg) -> Any:
|
||||||
|
"""Search a side effect definition and return it"""
|
||||||
|
return self._current_side_effects.get(arg, self._default_side_effect)
|
||||||
|
|
||||||
|
return side_effect_method
|
||||||
|
|
||||||
|
def add_or_update_side_effect(self, key: str, new_value: Any):
|
||||||
|
"""Update the value of a side effect"""
|
||||||
|
self._current_side_effects[key] = new_value
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# pylint: disable=wildcard-import, unused-wildcard-import, protected-access, unused-argument, line-too-long, too-many-lines
|
# pylint: disable=wildcard-import, unused-wildcard-import, protected-access, unused-argument, line-too-long, too-many-lines
|
||||||
|
|
||||||
""" Test the Window management """
|
""" Test the over_climate Vtherm """
|
||||||
from unittest.mock import patch, call
|
from unittest.mock import patch, call
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
|||||||
296
tests/test_overclimate_valve.py
Normal file
296
tests/test_overclimate_valve.py
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
# pylint: disable=wildcard-import, unused-wildcard-import, protected-access, unused-argument, line-too-long, too-many-lines
|
||||||
|
|
||||||
|
""" Test the over_climate with valve regulation """
|
||||||
|
from unittest.mock import patch, call
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant.core import HomeAssistant, State
|
||||||
|
|
||||||
|
from custom_components.versatile_thermostat.thermostat_climate_valve import (
|
||||||
|
ThermostatOverClimateValve,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .commons import *
|
||||||
|
from .const import *
|
||||||
|
|
||||||
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
# @pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
|
async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get):
|
||||||
|
"""Test the normal full start of a thermostat in thermostat_over_climate type"""
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
title="TheOverClimateMockName",
|
||||||
|
unique_id="uniqueId",
|
||||||
|
data={
|
||||||
|
CONF_NAME: "TheOverClimateMockName",
|
||||||
|
CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
|
||||||
|
CONF_CYCLE_MIN: 5,
|
||||||
|
CONF_DEVICE_POWER: 1,
|
||||||
|
CONF_USE_MAIN_CENTRAL_CONFIG: False,
|
||||||
|
CONF_USE_CENTRAL_MODE: False,
|
||||||
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE,
|
||||||
|
CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
|
||||||
|
CONF_TEMP_MIN: 15,
|
||||||
|
CONF_TEMP_MAX: 30,
|
||||||
|
CONF_STEP_TEMPERATURE: 0.1,
|
||||||
|
CONF_UNDERLYING_LIST: ["climate.mock_climate"],
|
||||||
|
CONF_AC_MODE: False,
|
||||||
|
CONF_AUTO_REGULATION_MODE: CONF_AUTO_REGULATION_VALVE,
|
||||||
|
CONF_AUTO_REGULATION_DTEMP: 0.5,
|
||||||
|
CONF_AUTO_REGULATION_PERIOD_MIN: 2,
|
||||||
|
CONF_AUTO_FAN_MODE: CONF_AUTO_FAN_HIGH,
|
||||||
|
CONF_AUTO_REGULATION_USE_DEVICE_TEMP: False,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
|
CONF_TPI_COEF_INT: 0.3,
|
||||||
|
CONF_TPI_COEF_EXT: 0.1,
|
||||||
|
CONF_OPENING_DEGREE_LIST: ["number.mock_opening_degree"],
|
||||||
|
CONF_CLOSING_DEGREE_LIST: ["number.mock_closing_degree"],
|
||||||
|
CONF_OFFSET_CALIBRATION_LIST: ["number.mock_offset_calibration"],
|
||||||
|
}
|
||||||
|
| MOCK_DEFAULT_FEATURE_CONFIG
|
||||||
|
| MOCK_DEFAULT_CENTRAL_CONFIG
|
||||||
|
| MOCK_ADVANCED_CONFIG,
|
||||||
|
)
|
||||||
|
|
||||||
|
fake_underlying_climate = MockClimate(hass, "mockUniqueId", "MockClimateName", {})
|
||||||
|
|
||||||
|
# mock_get_state will be called for each OPENING/CLOSING/OFFSET_CALIBRATION list
|
||||||
|
|
||||||
|
mock_get_state_side_effect = SideEffects(
|
||||||
|
{
|
||||||
|
"number.mock_opening_degree": State(
|
||||||
|
"number.mock_opening_degree", "0", {"min": 0, "max": 100}
|
||||||
|
),
|
||||||
|
"number.mock_closing_degree": State(
|
||||||
|
"number.mock_closing_degree", "0", {"min": 0, "max": 100}
|
||||||
|
),
|
||||||
|
"number.mock_offset_calibration": State(
|
||||||
|
"number.mock_offset_calibration", "0", {"min": -12, "max": 12}
|
||||||
|
),
|
||||||
|
},
|
||||||
|
State("unknown.entity_id", "unknown"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# 1. initialize the VTherm
|
||||||
|
tz = get_tz(hass) # pylint: disable=invalid-name
|
||||||
|
now: datetime = datetime.now(tz=tz)
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
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, \
|
||||||
|
patch("homeassistant.core.ServiceRegistry.async_call") as mock_service_call,\
|
||||||
|
patch("homeassistant.core.StateMachine.get", side_effect=mock_get_state_side_effect.get_side_effects()) as mock_get_state:
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
vtherm: ThermostatOverClimateValve = await create_thermostat(hass, entry, "climate.theoverclimatemockname")
|
||||||
|
|
||||||
|
assert vtherm
|
||||||
|
vtherm._set_now(now)
|
||||||
|
assert isinstance(vtherm, ThermostatOverClimateValve)
|
||||||
|
|
||||||
|
assert vtherm.name == "TheOverClimateMockName"
|
||||||
|
assert vtherm.is_over_climate is True
|
||||||
|
assert vtherm.have_valve_regulation is True
|
||||||
|
|
||||||
|
assert vtherm.hvac_action is HVACAction.OFF
|
||||||
|
assert vtherm.hvac_mode is HVACMode.OFF
|
||||||
|
assert vtherm.target_temperature == vtherm.min_temp
|
||||||
|
assert vtherm.preset_modes == [
|
||||||
|
PRESET_NONE,
|
||||||
|
PRESET_FROST_PROTECTION,
|
||||||
|
PRESET_ECO,
|
||||||
|
PRESET_COMFORT,
|
||||||
|
PRESET_BOOST,
|
||||||
|
]
|
||||||
|
assert vtherm.preset_mode is PRESET_NONE
|
||||||
|
assert vtherm._security_state is False
|
||||||
|
assert vtherm._window_state is None
|
||||||
|
assert vtherm._motion_state is None
|
||||||
|
assert vtherm._presence_state is None
|
||||||
|
|
||||||
|
assert vtherm.is_device_active is False
|
||||||
|
assert vtherm.valve_open_percent == 0
|
||||||
|
|
||||||
|
# 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},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_find_climate.assert_called_once()
|
||||||
|
mock_find_climate.assert_has_calls([call.find_underlying_vtherm()])
|
||||||
|
|
||||||
|
# the underlying set temperature call but no call to valve yet because VTherm is off
|
||||||
|
assert mock_service_call.call_count == 3
|
||||||
|
mock_service_call.assert_has_calls(
|
||||||
|
[
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 0}, target={'entity_id': 'number.mock_opening_degree'}),
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 100}, target={'entity_id': 'number.mock_closing_degree'}),
|
||||||
|
# we have no current_temperature yet
|
||||||
|
# call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration'}),
|
||||||
|
call("climate","set_temperature",{
|
||||||
|
"entity_id": "climate.mock_climate",
|
||||||
|
"temperature": 15, # temp-min
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert mock_get_state.call_count > 5 # each temp sensor + each valve
|
||||||
|
|
||||||
|
|
||||||
|
# initialize the temps
|
||||||
|
await set_all_climate_preset_temp(hass, vtherm, None, "theoverclimatemockname")
|
||||||
|
|
||||||
|
await send_temperature_change_event(vtherm, 18, now, True)
|
||||||
|
await send_ext_temperature_change_event(vtherm, 18, now, True)
|
||||||
|
|
||||||
|
# 2. Starts heating slowly (18 vs 19)
|
||||||
|
now = now + timedelta(minutes=1)
|
||||||
|
vtherm._set_now(now)
|
||||||
|
|
||||||
|
await vtherm.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
|
# fmt: off
|
||||||
|
with patch("custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event") as mock_send_event, \
|
||||||
|
patch("homeassistant.core.ServiceRegistry.async_call") as mock_service_call,\
|
||||||
|
patch("homeassistant.core.StateMachine.get", side_effect=mock_get_state_side_effect.get_side_effects()) as mock_get_state:
|
||||||
|
# fmt: on
|
||||||
|
now = now + timedelta(minutes=2) # avoid temporal filter
|
||||||
|
vtherm._set_now(now)
|
||||||
|
|
||||||
|
await vtherm.async_set_preset_mode(PRESET_COMFORT)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert vtherm.hvac_mode is HVACMode.HEAT
|
||||||
|
assert vtherm.preset_mode is PRESET_COMFORT
|
||||||
|
assert vtherm.target_temperature == 19
|
||||||
|
assert vtherm.current_temperature == 18
|
||||||
|
assert vtherm.valve_open_percent == 40 # 0.3*1 + 0.1*1
|
||||||
|
|
||||||
|
|
||||||
|
assert mock_service_call.call_count == 4
|
||||||
|
mock_service_call.assert_has_calls(
|
||||||
|
[
|
||||||
|
call('climate', 'set_temperature', {'entity_id': 'climate.mock_climate', 'temperature': 19.0}),
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 40}, target={'entity_id': 'number.mock_opening_degree'}),
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 60}, target={'entity_id': 'number.mock_closing_degree'}),
|
||||||
|
# 3 = 18 (room) - 15 (current of underlying) + 0 (current offset)
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 3.0}, target={'entity_id': 'number.mock_offset_calibration'})
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# set the opening to 40%
|
||||||
|
mock_get_state_side_effect.add_or_update_side_effect(
|
||||||
|
"number.mock_opening_degree",
|
||||||
|
State(
|
||||||
|
"number.mock_opening_degree", "40", {"min": 0, "max": 100}
|
||||||
|
))
|
||||||
|
|
||||||
|
assert vtherm.hvac_action is HVACAction.HEATING
|
||||||
|
assert vtherm.is_device_active is True
|
||||||
|
|
||||||
|
# 2. Starts heating very slowly (18.9 vs 19)
|
||||||
|
now = now + timedelta(minutes=2)
|
||||||
|
vtherm._set_now(now)
|
||||||
|
# fmt: off
|
||||||
|
with patch("custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event") as mock_send_event, \
|
||||||
|
patch("homeassistant.core.ServiceRegistry.async_call") as mock_service_call,\
|
||||||
|
patch("homeassistant.core.StateMachine.get", side_effect=mock_get_state_side_effect.get_side_effects()) as mock_get_state:
|
||||||
|
# fmt: on
|
||||||
|
# set the offset to 3
|
||||||
|
mock_get_state_side_effect.add_or_update_side_effect(
|
||||||
|
"number.mock_offset_calibration",
|
||||||
|
State(
|
||||||
|
"number.mock_offset_calibration", "3", {"min": -12, "max": 12}
|
||||||
|
))
|
||||||
|
|
||||||
|
await send_temperature_change_event(vtherm, 18.9, now, True)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert vtherm.hvac_mode is HVACMode.HEAT
|
||||||
|
assert vtherm.preset_mode is PRESET_COMFORT
|
||||||
|
assert vtherm.target_temperature == 19
|
||||||
|
assert vtherm.current_temperature == 18.9
|
||||||
|
assert vtherm.valve_open_percent == 13 # 0.3*0.1 + 0.1*1
|
||||||
|
|
||||||
|
|
||||||
|
assert mock_service_call.call_count == 3
|
||||||
|
mock_service_call.assert_has_calls(
|
||||||
|
[
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 13}, target={'entity_id': 'number.mock_opening_degree'}),
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 87}, target={'entity_id': 'number.mock_closing_degree'}),
|
||||||
|
# 6 = 18 (room) - 15 (current of underlying) + 3 (current offset)
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 6.899999999999999}, target={'entity_id': 'number.mock_offset_calibration'})
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# set the opening to 13%
|
||||||
|
mock_get_state_side_effect.add_or_update_side_effect(
|
||||||
|
"number.mock_opening_degree",
|
||||||
|
State(
|
||||||
|
"number.mock_opening_degree", "13", {"min": 0, "max": 100}
|
||||||
|
))
|
||||||
|
|
||||||
|
assert vtherm.hvac_action is HVACAction.HEATING
|
||||||
|
assert vtherm.is_device_active is True
|
||||||
|
|
||||||
|
# 3. Stop heating 21 > 19
|
||||||
|
now = now + timedelta(minutes=2)
|
||||||
|
vtherm._set_now(now)
|
||||||
|
# fmt: off
|
||||||
|
with patch("custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event") as mock_send_event, \
|
||||||
|
patch("homeassistant.core.ServiceRegistry.async_call") as mock_service_call,\
|
||||||
|
patch("homeassistant.core.StateMachine.get", side_effect=mock_get_state_side_effect.get_side_effects()) as mock_get_state:
|
||||||
|
# fmt: on
|
||||||
|
# set the offset to 3
|
||||||
|
mock_get_state_side_effect.add_or_update_side_effect(
|
||||||
|
"number.mock_offset_calibration",
|
||||||
|
State(
|
||||||
|
"number.mock_offset_calibration", "3", {"min": -12, "max": 12}
|
||||||
|
))
|
||||||
|
|
||||||
|
await send_temperature_change_event(vtherm, 21, now, True)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert vtherm.hvac_mode is HVACMode.HEAT
|
||||||
|
assert vtherm.preset_mode is PRESET_COMFORT
|
||||||
|
assert vtherm.target_temperature == 19
|
||||||
|
assert vtherm.current_temperature == 21
|
||||||
|
assert vtherm.valve_open_percent == 0 # 0.3* (-2) + 0.1*1
|
||||||
|
|
||||||
|
|
||||||
|
assert mock_service_call.call_count == 3
|
||||||
|
mock_service_call.assert_has_calls(
|
||||||
|
[
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 0}, target={'entity_id': 'number.mock_opening_degree'}),
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 100}, target={'entity_id': 'number.mock_closing_degree'}),
|
||||||
|
# 6 = 18 (room) - 15 (current of underlying) + 3 (current offset)
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 9.0}, target={'entity_id': 'number.mock_offset_calibration'})
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# set the opening to 13%
|
||||||
|
mock_get_state_side_effect.add_or_update_side_effect(
|
||||||
|
"number.mock_opening_degree",
|
||||||
|
State(
|
||||||
|
"number.mock_opening_degree", "0", {"min": 0, "max": 100}
|
||||||
|
))
|
||||||
|
|
||||||
|
assert vtherm.hvac_action is HVACAction.OFF
|
||||||
|
assert vtherm.is_device_active is False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
@@ -58,6 +58,7 @@ async def test_over_switch_full_start(hass: HomeAssistant, skip_hass_states_is_s
|
|||||||
assert entity._motion_state is None
|
assert entity._motion_state is None
|
||||||
assert entity._presence_state is None
|
assert entity._presence_state is None
|
||||||
assert entity._prop_algorithm is not 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
|
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
||||||
assert mock_send_event.call_count == 2
|
assert mock_send_event.call_count == 2
|
||||||
@@ -94,18 +95,6 @@ async def test_over_climate_full_start(hass: HomeAssistant, skip_hass_states_is_
|
|||||||
return_value=fake_underlying_climate,
|
return_value=fake_underlying_climate,
|
||||||
) as mock_find_climate:
|
) as mock_find_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 = find_my_entity("climate.theoverclimatemockname")
|
|
||||||
|
|
||||||
assert entity
|
assert entity
|
||||||
assert isinstance(entity, ThermostatOverClimate)
|
assert isinstance(entity, ThermostatOverClimate)
|
||||||
@@ -127,6 +116,7 @@ async def test_over_climate_full_start(hass: HomeAssistant, skip_hass_states_is_
|
|||||||
assert entity._window_state is None
|
assert entity._window_state is None
|
||||||
assert entity._motion_state is None
|
assert entity._motion_state is None
|
||||||
assert entity._presence_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
|
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
||||||
assert mock_send_event.call_count == 2
|
assert mock_send_event.call_count == 2
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ async def test_over_valve_full_start(
|
|||||||
assert entity._motion_state is None # pylint: disable=protected-access
|
assert entity._motion_state is None # pylint: disable=protected-access
|
||||||
assert entity._presence_state is None # pylint: disable=protected-access
|
assert entity._presence_state is None # pylint: disable=protected-access
|
||||||
assert entity._prop_algorithm is not None # pylint: disable=protected-access
|
assert entity._prop_algorithm is not None # pylint: disable=protected-access
|
||||||
|
assert entity.have_valve_regulation is False
|
||||||
|
|
||||||
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
||||||
# assert mock_send_event.call_count == 2
|
# assert mock_send_event.call_count == 2
|
||||||
|
|||||||
Reference in New Issue
Block a user