Compare commits
10 Commits
5.3.3
..
5.3.3.beta4
| Author | SHA1 | Date | |
|---|---|---|---|
| 49ebf9ddae | |||
| 60de43f241 | |||
| f651fbdb37 | |||
| 685911a9aa | |||
| 67844d4ae8 | |||
| 513e65f79c | |||
| 31f782ffa3 | |||
| 2831257732 | |||
| 0343d0f0e8 | |||
| 208c80752c |
@@ -30,8 +30,7 @@
|
||||
"waderyan.gitblame",
|
||||
"keesschollaart.vscode-home-assistant",
|
||||
"vscode.markdown-math",
|
||||
"yzhang.markdown-all-in-one",
|
||||
"github.vscode-github-actions"
|
||||
"yzhang.markdown-all-in-one"
|
||||
],
|
||||
"settings": {
|
||||
"files.eol": "\n",
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
name: Run Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
testu:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.11
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip3 install -r requirements_test.txt
|
||||
|
||||
- name: Run Tests
|
||||
run: |
|
||||
pytest \
|
||||
-qq \
|
||||
--timeout=9 \
|
||||
--durations=10 \
|
||||
-n auto \
|
||||
-o console_output_style=count \
|
||||
-p no:sugar \
|
||||
tests
|
||||
|
||||
- name: Coverage
|
||||
run: |
|
||||
coverage run -m pytest tests/
|
||||
coverage report
|
||||
|
||||
- name: Generate HTML Coverage Report
|
||||
run: coverage html
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./htmlcov
|
||||
@@ -110,6 +110,3 @@ __pycache__
|
||||
config/**
|
||||
custom_components/hacs
|
||||
custom_components/localtuya
|
||||
|
||||
.coverage
|
||||
htmlcov
|
||||
Vendored
-6
@@ -13,12 +13,6 @@
|
||||
"command": "./container restart",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Start coverage",
|
||||
"type": "shell",
|
||||
"command": "./container coverage",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Home Assistant translations update",
|
||||
"type": "shell",
|
||||
|
||||
+6
-12
@@ -544,7 +544,7 @@ Par défaut, le thermomètre extérieur peut déclencher une mise en sécurité
|
||||
|
||||
Voir [exemple de réglages](#examples-tuning) pour avoir des exemples de réglage communs
|
||||
|
||||
>  _*Notes*_
|
||||
>  _*Notes*_
|
||||
> 1. Lorsque le capteur de température viendra à la vie et renverra les températures, le préréglage sera restauré à sa valeur précédente,
|
||||
> 2. Attention, deux températures sont nécessaires : la température interne et la température externe et chacune doit donner la température, sinon le thermostat sera en préréglage "security",
|
||||
> 3. Un service est disponible qui permet de régler les 3 paramètres de sécurité. Ca peut servir à adapter la fonction de sécurité à votre usage,
|
||||
@@ -571,18 +571,12 @@ Depuis la release 5.3, vous avez la possibilité de contrôler une chaudière ce
|
||||
|
||||
Le principe mis en place est globalement le suivant :
|
||||
1. une nouvelle entité de type `binary_sensor` et nommée par défaut `binary_sensor.central_boiler` est ajoutée,
|
||||
2. dans la configuration des VTherms vous indiquez si le VTherm doit contrôler la chaudière. En effet, dans une installation hétérogène, certains VTherm doivent commander la chaudière et d'autres non. Vous devez donc indiquer dans chaque configuration de VTherm si il contrôle la chaudière ou pas,
|
||||
3. le `binary_sensor.central_boiler` écoute les changements d'états des équipements des VTherm marqués comme contrôlant la chaudière,
|
||||
4. dès que le nombre d'équipements pilotés par le VTherm demandant du chauffage (ie son `hvac_action` passe à `Heating`) dépasse un seuil paramétrable, alors le `binary_sensor.central_boiler` passe à `on` et **si un service d'activation a été configuré, alors ce service est appelé**,
|
||||
5. si le nombre d'équipements nécessitant du chauffage repasse en dessous du seuil, alors le `binary_sensor.central_boiler` passe à `off` et si **un service de désactivation a été configuré, alors ce service est appelé**,
|
||||
6. vous avez accès à deux entités :
|
||||
- une de type `number` nommé par défaut `number.boiler_activation_threshold`, donne le seuil de déclenchement. Ce seuil est en nombre d'équipements (radiateurs) qui demande du chauffage.
|
||||
- une de type `sensor` nommé par défaut `sensor.nb_device_active_for_boiler`, donne le nombre d'équipements qui demande du chauffage. Par exemple, un VTherm ayant 4 vannes dont 3 demandes du chauffage fera passé ce capteur à 3. Seuls les équipements des VTherms qui sont marqués pour contrôler la chaudière centrale sont comptabilisés.
|
||||
2. dans la configuration des VTherms vous indiqué si le VTherm doit contrôler la chaudière. En effet, dans une installation hétérogène, certains VTherm doivent commander la chaudière et d'autres non. Vous devez donc indiqué dans chaque configuration de VTherm si il contrôle la chaudière ou pas,
|
||||
3. le `binary_sensor.central_boiler` écoute les changements d'états des VTherm marqués comme contrôlant la chaudière,
|
||||
4. si l'un des VTherm écoutés demande du chauffage (ie son `hvac_action` passe à `Heating`), alors le `binary_sensor.central_boiler` passe à `on` et si un service d'activation a été configuré, alors ce service est appelé,
|
||||
5. si plus aucun VTherm écoutés ne demande du chauffage (ie aucun `hvac_action` n'est `Heating`), alors le `binary_sensor.central_boiler` passe à `off` et si un service de désactivation a été configuré, alors ce service est appelé.
|
||||
|
||||
Vous avez donc en permanence, les informations qui permettent de piloter et régler le déclenchement de la chaudière.
|
||||
|
||||
Toutes ces entités sont rattachés au service de configuration centrale :
|
||||

|
||||
Vous avez donc en permanence, un indicateur qui donne l'info que au moins un des radiateurs est à besoin de chauffer.
|
||||
|
||||
### Configuration
|
||||
Pour configurer cette fonction, vous devez avoir une configuration centralisée (cf. [Configuration](#configuration)) et cochez la case 'Ajouter une chuadière centrale' :
|
||||
|
||||
@@ -558,17 +558,11 @@ Since release 5.3, you have the possibility of controlling a centralized boiler.
|
||||
The principle put in place is generally as follows:
|
||||
1. a new entity of type `binary_sensor` and named by default `binary_sensor.central_boiler` is added,
|
||||
2. in the VTherms configuration you indicate whether the VTherm should control the boiler. Indeed, in a heterogeneous installation, some VTherm must control the boiler and others not. You must therefore indicate in each VTherm configuration whether it controls the boiler or not,
|
||||
3. the `binary_sensor.central_boiler` listens for changes in state of VTherm equipment marked as controlling the boiler,
|
||||
4. as soon as the number of devices controlled by the VTherm requesting heating (ie its `hvac_action` goes to `Heating`) exceeds a configurable threshold, then the `binary_sensor.central_boiler` goes to `on` and **if a activation service has been configured, then this service is called**,
|
||||
5. if the number of devices requiring heating falls below the threshold again, then the `binary_sensor.central_boiler` goes to `off` and if **a deactivation service has been configured, then this service is called**,
|
||||
6. you have access to two entities:
|
||||
- one of type `number` named by default `number.boiler_activation_threshold`, gives the trigger threshold. This threshold is in number of equipment (radiators) which requires heating.
|
||||
- one of type `sensor` named by default `sensor.nb_device_active_for_boiler`, gives the number of devices requiring heating. For example, a VTherm having 4 valves including 3 heating requests will increase this sensor to 3. Only VTherm equipment that is marked to control the central boiler is counted.
|
||||
3. the `binary_sensor.central_boiler` listens for changes in state of the VTherms marked as controlling the boiler,
|
||||
4. if one of the listened VTherms requests heating (ie its `hvac_action` changes to `Heating`), then the `binary_sensor.central_boiler` changes to `on` and if an activation service has been configured, then this service is called,
|
||||
5. if no more listened VTherm requests heating (ie no `hvac_action` is `Heating`), then the `binary_sensor.central_boiler` goes to `off` and if a deactivation service has been configured, then this service is called.
|
||||
|
||||
You therefore always have the information which allows you to control and adjust the activation of the boiler.
|
||||
|
||||
All these entities are attached to the central configuration service:
|
||||

|
||||
You therefore always have an indicator which gives information that at least one of the radiators needs to be heated.
|
||||
|
||||
### Setup
|
||||
To configure this function, you must have a centralized configuration (see [Configuration](#configuration)) and check the 'Add a central boiler' box:
|
||||
|
||||
@@ -43,13 +43,4 @@ case $1 in
|
||||
pwd
|
||||
./scripts/starts_ha.sh
|
||||
;;
|
||||
coverage)
|
||||
rm -rf htmlcov/*
|
||||
echo "Starting coverage tests"
|
||||
coverage run -m pytest tests/
|
||||
echo "Starting coverage report"
|
||||
coverage report
|
||||
echo "Starting coverage html"
|
||||
coverage html
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -133,8 +133,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
await api.reload_central_boiler_entities_list()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -477,7 +477,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
||||
self._saved_preset_mode = PRESET_NONE
|
||||
|
||||
# Power management
|
||||
self._device_power = entry_infos.get(CONF_DEVICE_POWER) or 0
|
||||
self._device_power = entry_infos.get(CONF_DEVICE_POWER)
|
||||
self._pmax_on = False
|
||||
self._current_power = None
|
||||
self._current_power_max = None
|
||||
|
||||
@@ -383,12 +383,13 @@ class CentralBoilerBinarySensor(BinarySensorEntity):
|
||||
async def async_added_to_hass(self) -> None:
|
||||
await super().async_added_to_hass()
|
||||
|
||||
api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(self._hass)
|
||||
api.register_central_boiler(self)
|
||||
|
||||
@callback
|
||||
async def _async_startup_internal(*_):
|
||||
_LOGGER.debug("%s - Calling async_startup_internal", self)
|
||||
api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(
|
||||
self._hass
|
||||
)
|
||||
api.register_central_boiler(self)
|
||||
await self.listen_nb_active_vtherm_entity()
|
||||
|
||||
if self.hass.state == CoreState.running:
|
||||
@@ -405,13 +406,13 @@ class CentralBoilerBinarySensor(BinarySensorEntity):
|
||||
api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(self._hass)
|
||||
|
||||
if (
|
||||
api.nb_active_device_for_boiler_entity
|
||||
api.nb_active_vtherm_for_boiler_entity
|
||||
and api.nb_active_device_for_boiler_threshold_entity
|
||||
):
|
||||
listener_cancel = async_track_state_change_event(
|
||||
self._hass,
|
||||
[
|
||||
api.nb_active_device_for_boiler_entity.entity_id,
|
||||
api.nb_active_vtherm_for_boiler_entity.entity_id,
|
||||
api.nb_active_device_for_boiler_threshold_entity.entity_id,
|
||||
],
|
||||
self.calculate_central_boiler_state,
|
||||
@@ -419,7 +420,7 @@ class CentralBoilerBinarySensor(BinarySensorEntity):
|
||||
_LOGGER.debug(
|
||||
"%s - entity to get the nb of active VTherm is %s",
|
||||
self,
|
||||
api.nb_active_device_for_boiler_entity.entity_id,
|
||||
api.nb_active_vtherm_for_boiler_entity.entity_id,
|
||||
)
|
||||
self.async_on_remove(listener_cancel)
|
||||
else:
|
||||
@@ -434,7 +435,7 @@ class CentralBoilerBinarySensor(BinarySensorEntity):
|
||||
_LOGGER.debug("%s - calculating the new central boiler state", self)
|
||||
api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(self._hass)
|
||||
if (
|
||||
api.nb_active_device_for_boiler is None
|
||||
api.nb_active_vtherm_for_boiler is None
|
||||
or api.nb_active_device_for_boiler_threshold is None
|
||||
):
|
||||
_LOGGER.warning(
|
||||
@@ -444,7 +445,7 @@ class CentralBoilerBinarySensor(BinarySensorEntity):
|
||||
return False
|
||||
|
||||
active = (
|
||||
api.nb_active_device_for_boiler >= api.nb_active_device_for_boiler_threshold
|
||||
api.nb_active_vtherm_for_boiler >= api.nb_active_device_for_boiler_threshold
|
||||
)
|
||||
|
||||
if self._attr_is_on != active:
|
||||
|
||||
@@ -40,11 +40,11 @@ HIDDEN_PRESETS = [PRESET_POWER, PRESET_SECURITY]
|
||||
DOMAIN = "versatile_thermostat"
|
||||
|
||||
PLATFORMS: list[Platform] = [
|
||||
Platform.NUMBER,
|
||||
Platform.SELECT,
|
||||
Platform.CLIMATE,
|
||||
Platform.SENSOR,
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.SENSOR,
|
||||
Platform.SELECT,
|
||||
Platform.NUMBER,
|
||||
]
|
||||
|
||||
CONF_HEATER = "heater_entity_id"
|
||||
|
||||
@@ -51,6 +51,9 @@ async def async_setup_entry(
|
||||
|
||||
async_add_entities(entities, True)
|
||||
|
||||
api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(hass)
|
||||
api.register_central_boiler_activation_number_threshold(entities[0])
|
||||
|
||||
|
||||
class ActivateBoilerThresholdNumber(NumberEntity, RestoreEntity):
|
||||
"""Representation of the threshold of the number of VTherm
|
||||
@@ -92,9 +95,6 @@ class ActivateBoilerThresholdNumber(NumberEntity, RestoreEntity):
|
||||
async def async_added_to_hass(self) -> None:
|
||||
await super().async_added_to_hass()
|
||||
|
||||
api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(self._hass)
|
||||
api.register_central_boiler_activation_number_threshold(self)
|
||||
|
||||
old_state: CoreState = await self.async_get_last_state()
|
||||
_LOGGER.debug(
|
||||
"%s - Calling async_added_to_hass old_state is %s", self, old_state
|
||||
|
||||
@@ -49,7 +49,6 @@ from .const import (
|
||||
CONF_THERMOSTAT_CLIMATE,
|
||||
CONF_THERMOSTAT_TYPE,
|
||||
CONF_THERMOSTAT_CENTRAL_CONFIG,
|
||||
CONF_ADD_CENTRAL_BOILER_CONTROL,
|
||||
overrides,
|
||||
)
|
||||
|
||||
@@ -75,11 +74,9 @@ async def async_setup_entry(
|
||||
entities = None
|
||||
|
||||
if vt_type == CONF_THERMOSTAT_CENTRAL_CONFIG:
|
||||
if entry.data.get(CONF_ADD_CENTRAL_BOILER_CONTROL):
|
||||
entities = [
|
||||
NbActiveDeviceForBoilerSensor(hass, unique_id, name, entry.data)
|
||||
]
|
||||
async_add_entities(entities, True)
|
||||
entities = [NbActiveDeviceForBoilerSensor(hass, unique_id, name, entry.data)]
|
||||
api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(hass)
|
||||
api.register_nb_vtherm_active_boiler(entities[0])
|
||||
else:
|
||||
entities = [
|
||||
LastTemperatureSensor(hass, unique_id, name, entry.data),
|
||||
@@ -108,7 +105,7 @@ async def async_setup_entry(
|
||||
RegulatedTemperatureSensor(hass, unique_id, name, entry.data)
|
||||
)
|
||||
|
||||
async_add_entities(entities, True)
|
||||
async_add_entities(entities, True)
|
||||
|
||||
|
||||
class EnergySensor(VersatileThermostatBaseEntity, SensorEntity):
|
||||
@@ -672,9 +669,6 @@ class NbActiveDeviceForBoilerSensor(SensorEntity):
|
||||
async def async_added_to_hass(self) -> None:
|
||||
await super().async_added_to_hass()
|
||||
|
||||
api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(self._hass)
|
||||
api.register_nb_device_active_boiler(self)
|
||||
|
||||
@callback
|
||||
async def _async_startup_internal(*_):
|
||||
_LOGGER.debug("%s - Calling async_startup_internal", self)
|
||||
@@ -692,25 +686,24 @@ class NbActiveDeviceForBoilerSensor(SensorEntity):
|
||||
|
||||
# Listen to all VTherm state change
|
||||
self._entities = []
|
||||
underlying_entities_id = []
|
||||
entities_id = []
|
||||
|
||||
component: EntityComponent[ClimateEntity] = self.hass.data[CLIMATE_DOMAIN]
|
||||
for entity in component.entities:
|
||||
if isinstance(entity, BaseThermostat) and entity.is_used_by_central_boiler:
|
||||
self._entities.append(entity)
|
||||
for under in entity.underlying_entities:
|
||||
underlying_entities_id.append(under.entity_id)
|
||||
if len(underlying_entities_id) > 0:
|
||||
entities_id.append(entity.entity_id)
|
||||
if len(self._entities) > 0:
|
||||
# Arme l'écoute de la première entité
|
||||
listener_cancel = async_track_state_change_event(
|
||||
self._hass,
|
||||
underlying_entities_id,
|
||||
entities_id,
|
||||
self.calculate_nb_active_devices,
|
||||
)
|
||||
_LOGGER.info(
|
||||
"%s - the underlyings that could controls the central boiler are %s",
|
||||
"%s - VTherm that could controls the central boiler are %s",
|
||||
self,
|
||||
underlying_entities_id,
|
||||
entities_id,
|
||||
)
|
||||
self.async_on_remove(listener_cancel)
|
||||
else:
|
||||
|
||||
@@ -162,6 +162,7 @@ class ThermostatOverClimate(BaseThermostat):
|
||||
self._regulated_target_temp = self.target_temperature
|
||||
|
||||
_LOGGER.info("%s - regulation calculation will be done", self)
|
||||
self._last_regulation_change = now
|
||||
|
||||
new_regulated_temp = round_to_nearest(
|
||||
self._regulation_algo.calculate_regulated_temperature(
|
||||
@@ -187,7 +188,6 @@ class ThermostatOverClimate(BaseThermostat):
|
||||
new_regulated_temp,
|
||||
)
|
||||
|
||||
self._last_regulation_change = now
|
||||
for under in self._underlyings:
|
||||
await under.set_temperature(
|
||||
self.regulated_target_temp, self._attr_max_temp, self._attr_min_temp
|
||||
@@ -526,11 +526,7 @@ class ThermostatOverClimate(BaseThermostat):
|
||||
return
|
||||
|
||||
added_energy = 0
|
||||
if (
|
||||
self.is_over_climate
|
||||
and self._underlying_climate_delta_t is not None
|
||||
and self._device_power
|
||||
):
|
||||
if self.is_over_climate and self._underlying_climate_delta_t is not None:
|
||||
added_energy = self._device_power * self._underlying_climate_delta_t
|
||||
|
||||
self._total_energy += added_energy
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
""" The API of Versatile Thermostat"""
|
||||
import logging
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.core import HomeAssistant, HassJob
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
||||
from .const import (
|
||||
@@ -107,9 +107,15 @@ class VersatileThermostatAPI(dict):
|
||||
"""register the two number entities needed for boiler activation"""
|
||||
self._threshold_number_entity = threshold_number_entity
|
||||
|
||||
def register_nb_device_active_boiler(self, nb_active_number_entity):
|
||||
def register_nb_vtherm_active_boiler(self, nb_active_number_entity):
|
||||
"""register the two number entities needed for boiler activation"""
|
||||
self._nb_active_number_entity = nb_active_number_entity
|
||||
if self._central_boiler_entity:
|
||||
job = HassJob(
|
||||
self._central_boiler_entity.listen_nb_active_vtherm_entity,
|
||||
"init listen nb active VTherm",
|
||||
)
|
||||
self._hass.async_run_hass_job(job)
|
||||
|
||||
async def reload_central_boiler_entities_list(self):
|
||||
"""Reload the central boiler list of entities if a central boiler is used"""
|
||||
@@ -132,12 +138,7 @@ class VersatileThermostatAPI(dict):
|
||||
return self._safety_mode
|
||||
|
||||
@property
|
||||
def central_boiler_entity(self):
|
||||
"""Get the central boiler binary_sensor entity"""
|
||||
return self._central_boiler_entity
|
||||
|
||||
@property
|
||||
def nb_active_device_for_boiler(self):
|
||||
def nb_active_vtherm_for_boiler(self):
|
||||
"""Returns the number of active VTherm which have an
|
||||
influence on boiler"""
|
||||
if self._nb_active_number_entity is None:
|
||||
@@ -146,7 +147,7 @@ class VersatileThermostatAPI(dict):
|
||||
return self._nb_active_number_entity.native_value
|
||||
|
||||
@property
|
||||
def nb_active_device_for_boiler_entity(self):
|
||||
def nb_active_vtherm_for_boiler_entity(self):
|
||||
"""Returns the number of active VTherm entity which have an
|
||||
influence on boiler"""
|
||||
return self._nb_active_number_entity
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
@@ -2,7 +2,5 @@
|
||||
-r requirements_dev.txt
|
||||
aiodiscover
|
||||
ulid_transform
|
||||
pytest
|
||||
coverage
|
||||
pytest-asyncio
|
||||
pytest-homeassistant-custom-component
|
||||
+7
-122
@@ -19,14 +19,6 @@ from homeassistant.components.climate import (
|
||||
ClimateEntityFeature,
|
||||
)
|
||||
|
||||
from homeassistant.components.switch import (
|
||||
SwitchEntity,
|
||||
)
|
||||
|
||||
from homeassistant.components.number import (
|
||||
NumberEntity,
|
||||
)
|
||||
|
||||
from pytest_homeassistant_custom_component.common import MockConfigEntry
|
||||
|
||||
from custom_components.versatile_thermostat.base_thermostat import BaseThermostat
|
||||
@@ -68,7 +60,6 @@ from .const import ( # pylint: disable=unused-import
|
||||
PRESET_NONE,
|
||||
PRESET_ECO,
|
||||
PRESET_ACTIVITY,
|
||||
overrides,
|
||||
)
|
||||
|
||||
|
||||
@@ -177,52 +168,8 @@ FULL_CENTRAL_CONFIG = {
|
||||
CONF_SECURITY_DELAY_MIN: 61,
|
||||
CONF_SECURITY_MIN_ON_PERCENT: 0.5,
|
||||
CONF_SECURITY_DEFAULT_ON_PERCENT: 0.2,
|
||||
CONF_ADD_CENTRAL_BOILER_CONTROL: False,
|
||||
}
|
||||
|
||||
FULL_CENTRAL_CONFIG_WITH_BOILER = {
|
||||
CONF_NAME: CENTRAL_CONFIG_NAME,
|
||||
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CENTRAL_CONFIG,
|
||||
CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
|
||||
CONF_TEMP_MIN: 15,
|
||||
CONF_TEMP_MAX: 30,
|
||||
CONF_TPI_COEF_INT: 0.5,
|
||||
CONF_TPI_COEF_EXT: 0.02,
|
||||
"frost_temp": 10,
|
||||
"eco_temp": 17.1,
|
||||
"comfort_temp": 0,
|
||||
"boost_temp": 19.1,
|
||||
"eco_ac_temp": 25.1,
|
||||
"comfort_ac_temp": 23.1,
|
||||
"boost_ac_temp": 21.1,
|
||||
"frost_away_temp": 15.1,
|
||||
"eco_away_temp": 15.2,
|
||||
"comfort_away_temp": 0,
|
||||
"boost_away_temp": 15.4,
|
||||
"eco_ac_away_temp": 30.5,
|
||||
"comfort_ac_away_temp": 0,
|
||||
"boost_ac_away_temp": 30.7,
|
||||
CONF_WINDOW_DELAY: 15,
|
||||
CONF_WINDOW_AUTO_OPEN_THRESHOLD: 4,
|
||||
CONF_WINDOW_AUTO_CLOSE_THRESHOLD: 1,
|
||||
CONF_WINDOW_AUTO_MAX_DURATION: 31,
|
||||
CONF_MOTION_DELAY: 31,
|
||||
CONF_MOTION_OFF_DELAY: 301,
|
||||
CONF_MOTION_PRESET: "boost",
|
||||
CONF_NO_MOTION_PRESET: "frost",
|
||||
CONF_POWER_SENSOR: "sensor.mock_power_sensor",
|
||||
CONF_MAX_POWER_SENSOR: "sensor.mock_max_power_sensor",
|
||||
CONF_PRESET_POWER: 14,
|
||||
CONF_MINIMAL_ACTIVATION_DELAY: 11,
|
||||
CONF_SECURITY_DELAY_MIN: 61,
|
||||
CONF_SECURITY_MIN_ON_PERCENT: 0.5,
|
||||
CONF_SECURITY_DEFAULT_ON_PERCENT: 0.2,
|
||||
CONF_ADD_CENTRAL_BOILER_CONTROL: True,
|
||||
CONF_CENTRAL_BOILER_ACTIVATION_SRV: "switch.pompe_chaudiere/switch.turn_on",
|
||||
CONF_CENTRAL_BOILER_DEACTIVATION_SRV: "switch.pompe_chaudiere/switch.turn_off",
|
||||
}
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -266,11 +213,6 @@ class MockClimate(ClimateEntity):
|
||||
self._fan_modes = fan_modes if fan_modes else None
|
||||
self._attr_fan_mode = None
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""The name"""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def hvac_action(self):
|
||||
"""The hvac action of the mock climate"""
|
||||
@@ -302,10 +244,6 @@ class MockClimate(ClimateEntity):
|
||||
"""The hvac mode"""
|
||||
self._attr_hvac_mode = hvac_mode
|
||||
|
||||
def set_hvac_mode(self, hvac_mode):
|
||||
"""The hvac mode"""
|
||||
self._attr_hvac_mode = hvac_mode
|
||||
|
||||
def set_hvac_action(self, hvac_action: HVACAction):
|
||||
"""Set the HVACaction"""
|
||||
self._attr_hvac_action = hvac_action
|
||||
@@ -412,66 +350,6 @@ class MagicMockClimate(MagicMock):
|
||||
return 19
|
||||
|
||||
|
||||
class MockSwitch(SwitchEntity):
|
||||
"""A fake switch to be used instead real switch"""
|
||||
|
||||
def __init__( # pylint: disable=unused-argument, dangerous-default-value
|
||||
self, hass: HomeAssistant, unique_id, name, entry_infos={}
|
||||
):
|
||||
"""Init the switch"""
|
||||
super().__init__()
|
||||
|
||||
self.hass = hass
|
||||
self.platform = "switch"
|
||||
self.entity_id = self.platform + "." + unique_id
|
||||
self._name = name
|
||||
self._attr_is_on = False
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""The name"""
|
||||
return self._name
|
||||
|
||||
@overrides
|
||||
def turn_on(self, **kwargs: Any):
|
||||
"""Turns the switch on and notify the state change"""
|
||||
self._attr_is_on = True
|
||||
# self.async_write_ha_state()
|
||||
|
||||
@overrides
|
||||
def turn_off(self, **kwargs: Any):
|
||||
"""Turns the switch on and notify the state change"""
|
||||
self._attr_is_on = False
|
||||
# self.async_write_ha_state()
|
||||
|
||||
|
||||
class MockNumber(NumberEntity):
|
||||
"""A fake switch to be used instead real switch"""
|
||||
|
||||
def __init__( # pylint: disable=unused-argument, dangerous-default-value
|
||||
self, hass: HomeAssistant, unique_id, name, entry_infos={}
|
||||
):
|
||||
"""Init the switch"""
|
||||
super().__init__()
|
||||
|
||||
self.hass = hass
|
||||
self.platform = "number"
|
||||
self.entity_id = self.platform + "." + unique_id
|
||||
self._name = name
|
||||
self._attr_native_value = 0
|
||||
self._attr_native_min_value = 0
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""The name"""
|
||||
return self._name
|
||||
|
||||
@overrides
|
||||
def set_native_value(self, value: float):
|
||||
"""Change the value"""
|
||||
self._attr_native_value = value
|
||||
|
||||
|
||||
async def create_thermostat(
|
||||
hass: HomeAssistant, entry: MockConfigEntry, entity_id: str
|
||||
) -> BaseThermostat:
|
||||
@@ -483,6 +361,13 @@ async def create_thermostat(
|
||||
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
|
||||
|
||||
return search_entity(hass, entity_id, CLIMATE_DOMAIN)
|
||||
|
||||
|
||||
|
||||
+2
-16
@@ -29,11 +29,7 @@ from custom_components.versatile_thermostat.config_flow import (
|
||||
from custom_components.versatile_thermostat.vtherm_api import VersatileThermostatAPI
|
||||
from custom_components.versatile_thermostat.base_thermostat import BaseThermostat
|
||||
|
||||
from .commons import (
|
||||
create_central_config,
|
||||
FULL_CENTRAL_CONFIG,
|
||||
FULL_CENTRAL_CONFIG_WITH_BOILER,
|
||||
)
|
||||
from .commons import create_central_config
|
||||
|
||||
pytest_plugins = "pytest_homeassistant_custom_component" # pylint: disable=invalid-name
|
||||
|
||||
@@ -131,16 +127,6 @@ async def init_central_config_fixture(
|
||||
hass, init_vtherm_api
|
||||
): # pylint: disable=unused-argument
|
||||
"""Initialize the VTherm API"""
|
||||
await create_central_config(hass, FULL_CENTRAL_CONFIG)
|
||||
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(name="init_central_config_with_boiler_fixture")
|
||||
async def init_central_config_with_boiler_fixture(
|
||||
hass, init_vtherm_api
|
||||
): # pylint: disable=unused-argument
|
||||
"""Initialize the VTherm API"""
|
||||
await create_central_config(hass, FULL_CENTRAL_CONFIG_WITH_BOILER)
|
||||
await create_central_config(hass)
|
||||
|
||||
yield
|
||||
|
||||
@@ -1,835 +0,0 @@
|
||||
# pylint: disable=wildcard-import, unused-wildcard-import, protected-access, unused-argument, line-too-long
|
||||
|
||||
""" Test the central_configuration """
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
|
||||
from unittest.mock import patch, call
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
|
||||
from pytest_homeassistant_custom_component.common import MockConfigEntry
|
||||
|
||||
from custom_components.versatile_thermostat.thermostat_switch import (
|
||||
ThermostatOverSwitch,
|
||||
)
|
||||
|
||||
from custom_components.versatile_thermostat.thermostat_valve import (
|
||||
ThermostatOverValve,
|
||||
)
|
||||
|
||||
from custom_components.versatile_thermostat.thermostat_climate import (
|
||||
ThermostatOverClimate,
|
||||
)
|
||||
|
||||
from custom_components.versatile_thermostat.vtherm_api import VersatileThermostatAPI
|
||||
from custom_components.versatile_thermostat.binary_sensor import (
|
||||
CentralBoilerBinarySensor,
|
||||
)
|
||||
|
||||
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_add_a_central_config_with_boiler(
|
||||
hass: HomeAssistant,
|
||||
skip_hass_states_is_state,
|
||||
):
|
||||
"""Tests the clean_central_config_doubon of base_thermostat"""
|
||||
central_config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="TheCentralConfigMockName",
|
||||
unique_id="centralConfigUniqueId",
|
||||
data=FULL_CENTRAL_CONFIG_WITH_BOILER,
|
||||
)
|
||||
|
||||
central_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(central_config_entry.entry_id)
|
||||
assert central_config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
entity: ThermostatOverClimate = search_entity(
|
||||
hass, "climate.thecentralconfigmockname", "climate"
|
||||
)
|
||||
|
||||
assert entity is None
|
||||
|
||||
assert count_entities(hass, "climate.thecentralconfigmockname", "climate") == 0
|
||||
|
||||
# Test that VTherm API find the CentralConfig
|
||||
api = VersatileThermostatAPI.get_vtherm_api(hass)
|
||||
central_configuration = api.find_central_configuration()
|
||||
assert central_configuration is not None
|
||||
|
||||
# Test that VTherm API have any central boiler entities
|
||||
assert api.nb_active_device_for_boiler_entity is not None
|
||||
assert api.nb_active_device_for_boiler == 0
|
||||
|
||||
assert api.nb_active_device_for_boiler_threshold_entity is not None
|
||||
assert api.nb_active_device_for_boiler_threshold is 1 # the default value is 1
|
||||
|
||||
|
||||
async def test_update_central_boiler_state_simple(
|
||||
hass: HomeAssistant,
|
||||
# skip_hass_states_is_state,
|
||||
init_central_config_with_boiler_fixture,
|
||||
):
|
||||
"""Test that the central boiler state behavoir"""
|
||||
|
||||
api = VersatileThermostatAPI.get_vtherm_api(hass)
|
||||
|
||||
switch1 = MockSwitch(hass, "switch1", "theSwitch1")
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="TheOverSwitchMockName",
|
||||
unique_id="uniqueId",
|
||||
data={
|
||||
CONF_NAME: "TheOverSwitchMockName",
|
||||
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH,
|
||||
CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
|
||||
CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
|
||||
CONF_CYCLE_MIN: 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: switch1.entity_id,
|
||||
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||
CONF_INVERSE_SWITCH: False,
|
||||
CONF_TPI_COEF_INT: 0.3,
|
||||
CONF_TPI_COEF_EXT: 0.01,
|
||||
CONF_MINIMAL_ACTIVATION_DELAY: 30,
|
||||
CONF_SECURITY_DELAY_MIN: 5,
|
||||
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
||||
CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1,
|
||||
CONF_USE_MAIN_CENTRAL_CONFIG: True,
|
||||
CONF_USE_TPI_CENTRAL_CONFIG: True,
|
||||
CONF_USE_PRESETS_CENTRAL_CONFIG: True,
|
||||
CONF_USE_ADVANCED_CENTRAL_CONFIG: True,
|
||||
CONF_USED_BY_CENTRAL_BOILER: True,
|
||||
},
|
||||
)
|
||||
|
||||
entity: ThermostatOverSwitch = await create_thermostat(
|
||||
hass, entry, "climate.theoverswitchmockname"
|
||||
)
|
||||
assert entity
|
||||
assert entity.name == "TheOverSwitchMockName"
|
||||
assert entity.is_over_switch
|
||||
assert entity.underlying_entities[0].entity_id == "switch.switch1"
|
||||
|
||||
assert api.nb_active_device_for_boiler_threshold == 1
|
||||
assert api.nb_active_device_for_boiler == 0
|
||||
|
||||
# Force the VTherm to heat
|
||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||
await entity.async_set_preset_mode(PRESET_BOOST)
|
||||
|
||||
tz = get_tz(hass) # pylint: disable=invalid-name
|
||||
now: datetime = datetime.now(tz=tz)
|
||||
await send_temperature_change_event(entity, 10, now)
|
||||
|
||||
assert entity.hvac_mode == HVACMode.HEAT
|
||||
|
||||
boiler_binary_sensor: CentralBoilerBinarySensor = search_entity(
|
||||
hass, "binary_sensor.central_boiler", "binary_sensor"
|
||||
)
|
||||
assert boiler_binary_sensor is not None
|
||||
assert boiler_binary_sensor.state == STATE_OFF
|
||||
|
||||
# 1. start a heater
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await switch1.async_turn_on()
|
||||
switch1.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.HEATING
|
||||
|
||||
assert mock_service_call.call_count >= 1
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
call.service_call(
|
||||
"switch",
|
||||
"turn_on",
|
||||
service_data={},
|
||||
target={"entity_id": "switch.pompe_chaudiere"},
|
||||
),
|
||||
]
|
||||
)
|
||||
assert mock_send_event.call_count >= 1
|
||||
mock_send_event.assert_has_calls(
|
||||
[
|
||||
call.send_vtherm_event(
|
||||
hass=hass,
|
||||
event_type=EventType.CENTRAL_BOILER_EVENT,
|
||||
entity=api.central_boiler_entity,
|
||||
data={"central_boiler": True},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert api.nb_active_device_for_boiler == 1
|
||||
assert boiler_binary_sensor.state == STATE_ON
|
||||
|
||||
# 2. stop a heater
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await switch1.async_turn_off()
|
||||
switch1.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.IDLE
|
||||
|
||||
assert mock_service_call.call_count >= 1
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
call(
|
||||
"switch",
|
||||
"turn_off",
|
||||
service_data={},
|
||||
target={"entity_id": "switch.pompe_chaudiere"},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert mock_send_event.call_count >= 1
|
||||
mock_send_event.assert_has_calls(
|
||||
[
|
||||
call.send_vtherm_event(
|
||||
hass=hass,
|
||||
event_type=EventType.CENTRAL_BOILER_EVENT,
|
||||
entity=api.central_boiler_entity,
|
||||
data={"central_boiler": False},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert api.nb_active_device_for_boiler == 0
|
||||
assert boiler_binary_sensor.state == STATE_OFF
|
||||
|
||||
entity.remove_thermostat()
|
||||
|
||||
|
||||
async def test_update_central_boiler_state_multiple(
|
||||
hass: HomeAssistant,
|
||||
# skip_hass_states_is_state,
|
||||
init_central_config_with_boiler_fixture,
|
||||
):
|
||||
"""Test that the central boiler state behavoir"""
|
||||
|
||||
api = VersatileThermostatAPI.get_vtherm_api(hass)
|
||||
|
||||
switch1 = MockSwitch(hass, "switch1", "theSwitch1")
|
||||
switch2 = MockSwitch(hass, "switch2", "theSwitch2")
|
||||
switch3 = MockSwitch(hass, "switch3", "theSwitch3")
|
||||
switch4 = MockSwitch(hass, "switch4", "theSwitch4")
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="TheOverSwitchMockName",
|
||||
unique_id="uniqueId",
|
||||
data={
|
||||
CONF_NAME: "TheOverSwitchMockName",
|
||||
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH,
|
||||
CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
|
||||
CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
|
||||
CONF_CYCLE_MIN: 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: switch1.entity_id,
|
||||
CONF_HEATER_2: switch2.entity_id,
|
||||
CONF_HEATER_3: switch3.entity_id,
|
||||
CONF_HEATER_4: switch4.entity_id,
|
||||
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||
CONF_INVERSE_SWITCH: False,
|
||||
CONF_TPI_COEF_INT: 0.3,
|
||||
CONF_TPI_COEF_EXT: 0.01,
|
||||
CONF_MINIMAL_ACTIVATION_DELAY: 30,
|
||||
CONF_SECURITY_DELAY_MIN: 5,
|
||||
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
||||
CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1,
|
||||
CONF_USE_MAIN_CENTRAL_CONFIG: True,
|
||||
CONF_USE_TPI_CENTRAL_CONFIG: True,
|
||||
CONF_USE_PRESETS_CENTRAL_CONFIG: True,
|
||||
CONF_USE_ADVANCED_CENTRAL_CONFIG: True,
|
||||
CONF_USED_BY_CENTRAL_BOILER: True,
|
||||
},
|
||||
)
|
||||
|
||||
entity: ThermostatOverSwitch = await create_thermostat(
|
||||
hass, entry, "climate.theoverswitchmockname"
|
||||
)
|
||||
assert entity
|
||||
assert entity.name == "TheOverSwitchMockName"
|
||||
assert entity.is_over_switch
|
||||
assert entity.underlying_entities[0].entity_id == "switch.switch1"
|
||||
assert entity.underlying_entities[1].entity_id == "switch.switch2"
|
||||
assert entity.underlying_entities[2].entity_id == "switch.switch3"
|
||||
assert entity.underlying_entities[3].entity_id == "switch.switch4"
|
||||
|
||||
assert api.nb_active_device_for_boiler_threshold == 1
|
||||
assert api.nb_active_device_for_boiler == 0
|
||||
# Force the VTherm to heat
|
||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||
await entity.async_set_preset_mode(PRESET_BOOST)
|
||||
|
||||
tz = get_tz(hass) # pylint: disable=invalid-name
|
||||
now: datetime = datetime.now(tz=tz)
|
||||
await send_temperature_change_event(entity, 10, now)
|
||||
|
||||
assert entity.hvac_mode == HVACMode.HEAT
|
||||
|
||||
# 0. set threshold to 3
|
||||
api.nb_active_device_for_boiler_threshold_entity.set_native_value(3)
|
||||
assert api.nb_active_device_for_boiler_threshold == 3
|
||||
|
||||
boiler_binary_sensor: CentralBoilerBinarySensor = search_entity(
|
||||
hass, "binary_sensor.central_boiler", "binary_sensor"
|
||||
)
|
||||
assert boiler_binary_sensor is not None
|
||||
assert boiler_binary_sensor.state == STATE_OFF
|
||||
|
||||
# 1. start a first heater
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await switch1.async_turn_on()
|
||||
switch1.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.HEATING
|
||||
|
||||
assert mock_service_call.call_count == 1
|
||||
# No switch of the boiler
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
call.service_call(
|
||||
"switch",
|
||||
"turn_on",
|
||||
{"entity_id": "switch.switch1"},
|
||||
),
|
||||
]
|
||||
)
|
||||
assert mock_send_event.call_count == 0
|
||||
|
||||
assert api.nb_active_device_for_boiler == 1
|
||||
assert boiler_binary_sensor.state == STATE_OFF
|
||||
|
||||
# 2. start a 2nd heater
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await switch2.async_turn_on()
|
||||
switch2.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.HEATING
|
||||
|
||||
# Only the first heater is started by the algo
|
||||
assert mock_service_call.call_count == 1
|
||||
# No switch of the boiler. Caution: each time a underlying heater state change itself,
|
||||
# the cycle restarts. So it is always the first heater that is started
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
call.service_call(
|
||||
"switch",
|
||||
"turn_on",
|
||||
{"entity_id": "switch.switch1"},
|
||||
),
|
||||
]
|
||||
)
|
||||
assert mock_send_event.call_count == 0
|
||||
|
||||
assert api.nb_active_device_for_boiler == 2
|
||||
assert boiler_binary_sensor.state == STATE_OFF
|
||||
|
||||
# 3. start a 3rd heater
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await switch3.async_turn_on()
|
||||
switch3.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.HEATING
|
||||
|
||||
# Only the first heater is started by the algo
|
||||
assert mock_service_call.call_count == 2
|
||||
# No switch of the boiler. Caution: each time a underlying heater state change itself,
|
||||
# the cycle restarts. So it is always the first heater that is started
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
call.service_call(
|
||||
"switch",
|
||||
"turn_on",
|
||||
service_data={},
|
||||
target={"entity_id": "switch.pompe_chaudiere"},
|
||||
),
|
||||
call.service_call(
|
||||
"switch",
|
||||
"turn_on",
|
||||
{"entity_id": "switch.switch1"},
|
||||
),
|
||||
],
|
||||
any_order=True,
|
||||
)
|
||||
assert mock_send_event.call_count == 1
|
||||
mock_send_event.assert_has_calls(
|
||||
[
|
||||
call.send_vtherm_event(
|
||||
hass=hass,
|
||||
event_type=EventType.CENTRAL_BOILER_EVENT,
|
||||
entity=api.central_boiler_entity,
|
||||
data={"central_boiler": True},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert api.nb_active_device_for_boiler == 3
|
||||
assert boiler_binary_sensor.state == STATE_ON
|
||||
|
||||
# 4. start a 4th heater
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await switch4.async_turn_on()
|
||||
switch4.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.HEATING
|
||||
|
||||
# Only the first heater is started by the algo
|
||||
assert mock_service_call.call_count == 1
|
||||
# No switch of the boiler. Caution: each time a underlying heater state change itself,
|
||||
# the cycle restarts. So it is always the first heater that is started
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
call.service_call(
|
||||
"switch",
|
||||
"turn_on",
|
||||
{"entity_id": "switch.switch1"},
|
||||
),
|
||||
]
|
||||
)
|
||||
assert mock_send_event.call_count == 0
|
||||
assert api.nb_active_device_for_boiler == 4
|
||||
assert boiler_binary_sensor.state == STATE_ON
|
||||
|
||||
# 5. stop a heater
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await switch1.async_turn_off()
|
||||
switch1.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.HEATING
|
||||
|
||||
assert mock_service_call.call_count == 0
|
||||
assert mock_send_event.call_count == 0
|
||||
assert api.nb_active_device_for_boiler == 3
|
||||
assert boiler_binary_sensor.state == STATE_ON
|
||||
|
||||
# 6. stop a 2nd heater
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await switch4.async_turn_off()
|
||||
switch4.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.HEATING
|
||||
|
||||
assert mock_service_call.call_count >= 1
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
call(
|
||||
"switch",
|
||||
"turn_off",
|
||||
service_data={},
|
||||
target={"entity_id": "switch.pompe_chaudiere"},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert mock_send_event.call_count >= 1
|
||||
mock_send_event.assert_has_calls(
|
||||
[
|
||||
call.send_vtherm_event(
|
||||
hass=hass,
|
||||
event_type=EventType.CENTRAL_BOILER_EVENT,
|
||||
entity=api.central_boiler_entity,
|
||||
data={"central_boiler": False},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert api.nb_active_device_for_boiler == 2
|
||||
assert boiler_binary_sensor.state == STATE_OFF
|
||||
|
||||
entity.remove_thermostat()
|
||||
|
||||
|
||||
async def test_update_central_boiler_state_simple_valve(
|
||||
hass: HomeAssistant,
|
||||
# skip_hass_states_is_state,
|
||||
init_central_config_with_boiler_fixture,
|
||||
):
|
||||
"""Test that the central boiler state behavoir"""
|
||||
|
||||
api = VersatileThermostatAPI.get_vtherm_api(hass)
|
||||
|
||||
valve1 = MockNumber(hass, "valve1", "theValve1")
|
||||
|
||||
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_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: valve1.entity_id,
|
||||
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||
CONF_INVERSE_SWITCH: False,
|
||||
CONF_TPI_COEF_INT: 0.3,
|
||||
CONF_TPI_COEF_EXT: 0.01,
|
||||
CONF_MINIMAL_ACTIVATION_DELAY: 30,
|
||||
CONF_SECURITY_DELAY_MIN: 5,
|
||||
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
||||
CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1,
|
||||
CONF_USE_MAIN_CENTRAL_CONFIG: True,
|
||||
CONF_USE_TPI_CENTRAL_CONFIG: True,
|
||||
CONF_USE_PRESETS_CENTRAL_CONFIG: True,
|
||||
CONF_USE_ADVANCED_CENTRAL_CONFIG: True,
|
||||
CONF_USED_BY_CENTRAL_BOILER: True,
|
||||
},
|
||||
)
|
||||
|
||||
entity: ThermostatOverValve = await create_thermostat(
|
||||
hass, entry, "climate.theovervalvemockname"
|
||||
)
|
||||
assert entity
|
||||
assert entity.name == "TheOverValveMockName"
|
||||
assert entity.is_over_valve
|
||||
assert entity.underlying_entities[0].entity_id == "number.valve1"
|
||||
|
||||
assert api.nb_active_device_for_boiler_threshold == 1
|
||||
assert api.nb_active_device_for_boiler == 0
|
||||
|
||||
# Force the VTherm to heat
|
||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||
await entity.async_set_preset_mode(PRESET_BOOST)
|
||||
|
||||
tz = get_tz(hass) # pylint: disable=invalid-name
|
||||
now: datetime = datetime.now(tz=tz)
|
||||
|
||||
assert entity.hvac_mode == HVACMode.HEAT
|
||||
|
||||
boiler_binary_sensor: CentralBoilerBinarySensor = search_entity(
|
||||
hass, "binary_sensor.central_boiler", "binary_sensor"
|
||||
)
|
||||
assert boiler_binary_sensor is not None
|
||||
assert boiler_binary_sensor.state == STATE_OFF
|
||||
|
||||
# 1. start a valve
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await send_temperature_change_event(entity, 10, now)
|
||||
# we have to simulate the valve also else the test don't work
|
||||
valve1.set_native_value(10)
|
||||
valve1.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.HEATING
|
||||
|
||||
assert mock_service_call.call_count >= 1
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
call.service_call(
|
||||
"switch",
|
||||
"turn_on",
|
||||
service_data={},
|
||||
target={"entity_id": "switch.pompe_chaudiere"},
|
||||
),
|
||||
]
|
||||
)
|
||||
assert mock_send_event.call_count >= 1
|
||||
mock_send_event.assert_has_calls(
|
||||
[
|
||||
call.send_vtherm_event(
|
||||
hass=hass,
|
||||
event_type=EventType.CENTRAL_BOILER_EVENT,
|
||||
entity=api.central_boiler_entity,
|
||||
data={"central_boiler": True},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert api.nb_active_device_for_boiler == 1
|
||||
assert boiler_binary_sensor.state == STATE_ON
|
||||
|
||||
# 2. stop a heater
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await send_temperature_change_event(entity, 25, now)
|
||||
# Change the valve value to 0
|
||||
valve1.set_native_value(0)
|
||||
valve1.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.IDLE
|
||||
|
||||
assert mock_service_call.call_count >= 1
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
call(
|
||||
"switch",
|
||||
"turn_off",
|
||||
service_data={},
|
||||
target={"entity_id": "switch.pompe_chaudiere"},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert mock_send_event.call_count >= 1
|
||||
mock_send_event.assert_has_calls(
|
||||
[
|
||||
call.send_vtherm_event(
|
||||
hass=hass,
|
||||
event_type=EventType.CENTRAL_BOILER_EVENT,
|
||||
entity=api.central_boiler_entity,
|
||||
data={"central_boiler": False},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert api.nb_active_device_for_boiler == 0
|
||||
assert boiler_binary_sensor.state == STATE_OFF
|
||||
|
||||
entity.remove_thermostat()
|
||||
|
||||
|
||||
async def test_update_central_boiler_state_simple_climate(
|
||||
hass: HomeAssistant,
|
||||
# skip_hass_states_is_state,
|
||||
init_central_config_with_boiler_fixture,
|
||||
):
|
||||
"""Test that the central boiler state behavoir"""
|
||||
|
||||
api = VersatileThermostatAPI.get_vtherm_api(hass)
|
||||
|
||||
climate1 = MockClimate(hass, "climate1", "theClimate1")
|
||||
|
||||
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_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: climate1.entity_id,
|
||||
CONF_MINIMAL_ACTIVATION_DELAY: 30,
|
||||
CONF_SECURITY_DELAY_MIN: 5,
|
||||
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
||||
CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1,
|
||||
CONF_USE_MAIN_CENTRAL_CONFIG: True,
|
||||
CONF_USE_PRESETS_CENTRAL_CONFIG: True,
|
||||
CONF_USE_ADVANCED_CENTRAL_CONFIG: True,
|
||||
CONF_USED_BY_CENTRAL_BOILER: True,
|
||||
},
|
||||
)
|
||||
|
||||
with patch(
|
||||
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
|
||||
return_value=climate1,
|
||||
):
|
||||
entity: ThermostatOverValve = await create_thermostat(
|
||||
hass, entry, "climate.theoverclimatemockname"
|
||||
)
|
||||
assert entity
|
||||
assert entity.name == "TheOverClimateMockName"
|
||||
assert entity.is_over_climate
|
||||
assert entity.underlying_entities[0].entity_id == "climate.climate1"
|
||||
|
||||
assert api.nb_active_device_for_boiler_threshold == 1
|
||||
assert api.nb_active_device_for_boiler == 0
|
||||
|
||||
# Force the VTherm to heat
|
||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||
await entity.async_set_preset_mode(PRESET_BOOST)
|
||||
|
||||
tz = get_tz(hass) # pylint: disable=invalid-name
|
||||
now: datetime = datetime.now(tz=tz)
|
||||
|
||||
assert entity.hvac_mode == HVACMode.HEAT
|
||||
|
||||
boiler_binary_sensor: CentralBoilerBinarySensor = search_entity(
|
||||
hass, "binary_sensor.central_boiler", "binary_sensor"
|
||||
)
|
||||
assert boiler_binary_sensor is not None
|
||||
assert boiler_binary_sensor.state == STATE_OFF
|
||||
|
||||
# 1. start a climate
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await send_temperature_change_event(entity, 10, now)
|
||||
# we have to simulate the climate also else the test don't work
|
||||
climate1.set_hvac_mode(HVACMode.HEAT)
|
||||
climate1.set_hvac_action(HVACAction.HEATING)
|
||||
climate1.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.HEATING
|
||||
|
||||
assert mock_service_call.call_count >= 1
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
call.service_call(
|
||||
"switch",
|
||||
"turn_on",
|
||||
service_data={},
|
||||
target={"entity_id": "switch.pompe_chaudiere"},
|
||||
),
|
||||
]
|
||||
)
|
||||
assert mock_send_event.call_count >= 1
|
||||
mock_send_event.assert_has_calls(
|
||||
[
|
||||
call.send_vtherm_event(
|
||||
hass=hass,
|
||||
event_type=EventType.CENTRAL_BOILER_EVENT,
|
||||
entity=api.central_boiler_entity,
|
||||
data={"central_boiler": True},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert api.nb_active_device_for_boiler == 1
|
||||
assert boiler_binary_sensor.state == STATE_ON
|
||||
|
||||
# 2. stop a climate
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||
) as mock_send_event:
|
||||
await send_temperature_change_event(entity, 25, now)
|
||||
climate1.set_hvac_mode(HVACMode.HEAT)
|
||||
climate1.set_hvac_action(HVACAction.IDLE)
|
||||
climate1.async_write_ha_state()
|
||||
# Wait for state event propagation
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
assert entity.hvac_action == HVACAction.IDLE
|
||||
|
||||
assert mock_service_call.call_count >= 1
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
call(
|
||||
"switch",
|
||||
"turn_off",
|
||||
service_data={},
|
||||
target={"entity_id": "switch.pompe_chaudiere"},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert mock_send_event.call_count >= 1
|
||||
mock_send_event.assert_has_calls(
|
||||
[
|
||||
call.send_vtherm_event(
|
||||
hass=hass,
|
||||
event_type=EventType.CENTRAL_BOILER_EVENT,
|
||||
entity=api.central_boiler_entity,
|
||||
data={"central_boiler": False},
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
assert api.nb_active_device_for_boiler == 0
|
||||
assert boiler_binary_sensor.state == STATE_OFF
|
||||
|
||||
entity.remove_thermostat()
|
||||
@@ -31,8 +31,8 @@ from .commons import * # pylint: disable=wildcard-import, unused-wildcard-impor
|
||||
from .const import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||
|
||||
|
||||
# @pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
# @pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||
async def test_add_a_central_config(hass: HomeAssistant, skip_hass_states_is_state):
|
||||
"""Tests the clean_central_config_doubon of base_thermostat"""
|
||||
central_config_entry = MockConfigEntry(
|
||||
@@ -76,7 +76,6 @@ async def test_add_a_central_config(hass: HomeAssistant, skip_hass_states_is_sta
|
||||
CONF_SECURITY_DELAY_MIN: 61,
|
||||
CONF_SECURITY_MIN_ON_PERCENT: 0.5,
|
||||
CONF_SECURITY_DEFAULT_ON_PERCENT: 0.2,
|
||||
CONF_ADD_CENTRAL_BOILER_CONTROL: False,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -97,16 +96,9 @@ async def test_add_a_central_config(hass: HomeAssistant, skip_hass_states_is_sta
|
||||
central_configuration = api.find_central_configuration()
|
||||
assert central_configuration is not None
|
||||
|
||||
# Test that VTherm API doesn't have any central boiler entities
|
||||
assert api.nb_active_device_for_boiler_entity is None
|
||||
assert api.nb_active_device_for_boiler is None
|
||||
|
||||
assert api.nb_active_device_for_boiler_threshold_entity is None
|
||||
assert api.nb_active_device_for_boiler_threshold is None
|
||||
|
||||
|
||||
# @pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
# @pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||
async def test_minimal_over_switch_wo_central_config(
|
||||
hass: HomeAssistant, skip_hass_states_is_state, init_vtherm_api
|
||||
):
|
||||
@@ -180,11 +172,9 @@ async def test_minimal_over_switch_wo_central_config(
|
||||
assert entity._security_default_on_percent == 0.1
|
||||
assert entity.is_inversed
|
||||
|
||||
entity.remove_thermostat()
|
||||
|
||||
|
||||
# @pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
# @pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||
async def test_full_over_switch_wo_central_config(
|
||||
hass: HomeAssistant, skip_hass_states_is_state, init_vtherm_api
|
||||
):
|
||||
@@ -296,11 +286,9 @@ async def test_full_over_switch_wo_central_config(
|
||||
|
||||
assert entity._presence_sensor_entity_id == "binary_sensor.mock_presence_sensor"
|
||||
|
||||
entity.remove_thermostat()
|
||||
|
||||
|
||||
# @pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
# @pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||
async def test_full_over_switch_with_central_config(
|
||||
hass: HomeAssistant, skip_hass_states_is_state, init_central_config
|
||||
):
|
||||
@@ -408,11 +396,9 @@ async def test_full_over_switch_with_central_config(
|
||||
|
||||
assert entity._presence_sensor_entity_id == "binary_sensor.mock_presence_sensor"
|
||||
|
||||
entity.remove_thermostat()
|
||||
|
||||
|
||||
# @pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
# @pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||
async def test_over_switch_with_central_config_but_no_central_config(
|
||||
hass: HomeAssistant, skip_hass_states_get, init_vtherm_api
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user