central boiler - add entites to fine tune the boiler start

This commit is contained in:
Jean-Marc Collin
2024-01-20 10:40:55 +00:00
parent 60de43f241
commit 49ebf9ddae
9 changed files with 377 additions and 73 deletions

View File

@@ -69,10 +69,10 @@ input_number:
icon: mdi:pipe-valve icon: mdi:pipe-valve
unit_of_measurement: percentage unit_of_measurement: percentage
fake_boiler_temperature: fake_boiler_temperature:
name: Boiler temperature name: Central thermostat temp
min: 0 min: 0
max: 30 max: 30
icon: mdi:water-boiler icon: mdi:thermostat
unit_of_measurement: °C unit_of_measurement: °C
mode: box mode: box

View File

@@ -1166,6 +1166,11 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
"""Returns the number of underlying entities""" """Returns the number of underlying entities"""
return len(self._underlyings) return len(self._underlyings)
@property
def underlying_entities(self) -> int:
"""Returns the underlying entities"""
return self._underlyings
@property @property
def is_on(self) -> bool: def is_on(self) -> bool:
"""True if the VTherm is on (! HVAC_OFF)""" """True if the VTherm is on (! HVAC_OFF)"""
@@ -1628,6 +1633,9 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
for under in self._underlyings: for under in self._underlyings:
await under.check_initial_state(self._hvac_mode) await under.check_initial_state(self._hvac_mode)
# Starts the initial control loop (don't wait for an update of temperature)
await self.async_control_heating(force=True)
@callback @callback
async def _async_update_temp(self, state: State): async def _async_update_temp(self, state: State):
"""Update thermostat with latest state from sensor.""" """Update thermostat with latest state from sensor."""

View File

@@ -1,5 +1,5 @@
""" Implements the VersatileThermostat binary sensors component """ """ Implements the VersatileThermostat binary sensors component """
# pylint: disable=unused-argument # pylint: disable=unused-argument, line-too-long
import logging import logging
@@ -14,7 +14,6 @@ from homeassistant.core import (
from homeassistant.const import STATE_ON, STATE_OFF, EVENT_HOMEASSISTANT_START from homeassistant.const import STATE_ON, STATE_OFF, EVENT_HOMEASSISTANT_START
from homeassistant.helpers.device_registry import DeviceInfo, DeviceEntryType from homeassistant.helpers.device_registry import DeviceInfo, DeviceEntryType
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.event import async_track_state_change_event from homeassistant.helpers.event import async_track_state_change_event
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
@@ -25,14 +24,6 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.components.climate import (
ClimateEntity,
HVACMode,
HVACAction,
DOMAIN as CLIMATE_DOMAIN,
)
from custom_components.versatile_thermostat.base_thermostat import BaseThermostat
from .vtherm_api import VersatileThermostatAPI from .vtherm_api import VersatileThermostatAPI
from .commons import ( from .commons import (
VersatileThermostatBaseEntity, VersatileThermostatBaseEntity,
@@ -399,7 +390,7 @@ class CentralBoilerBinarySensor(BinarySensorEntity):
self._hass self._hass
) )
api.register_central_boiler(self) api.register_central_boiler(self)
await self.listen_vtherms_entities() await self.listen_nb_active_vtherm_entity()
if self.hass.state == CoreState.running: if self.hass.state == CoreState.running:
await _async_startup_internal() await _async_startup_internal()
@@ -408,29 +399,28 @@ class CentralBoilerBinarySensor(BinarySensorEntity):
EVENT_HOMEASSISTANT_START, _async_startup_internal EVENT_HOMEASSISTANT_START, _async_startup_internal
) )
async def listen_vtherms_entities(self): async def listen_nb_active_vtherm_entity(self):
"""Initialize the listening of state change of VTherms""" """Initialize the listening of state change of VTherms"""
# Listen to all VTherm state change # Listen to all VTherm state change
self._entities = [] api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(self._hass)
entities_id = []
component: EntityComponent[ClimateEntity] = self.hass.data[CLIMATE_DOMAIN] if (
for entity in component.entities: api.nb_active_vtherm_for_boiler_entity
if isinstance(entity, BaseThermostat) and entity.is_used_by_central_boiler: and api.nb_active_device_for_boiler_threshold_entity
self._entities.append(entity) ):
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( listener_cancel = async_track_state_change_event(
self._hass, self._hass,
entities_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, self.calculate_central_boiler_state,
) )
_LOGGER.info( _LOGGER.debug(
"%s - VTherm that could controls the central boiler are %s", "%s - entity to get the nb of active VTherm is %s",
self, self,
entities_id, api.nb_active_vtherm_for_boiler_entity.entity_id,
) )
self.async_on_remove(listener_cancel) self.async_on_remove(listener_cancel)
else: else:
@@ -443,18 +433,20 @@ class CentralBoilerBinarySensor(BinarySensorEntity):
controls this central boiler""" controls this central boiler"""
_LOGGER.debug("%s - calculating the new central boiler state", self) _LOGGER.debug("%s - calculating the new central boiler state", self)
active = False api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(self._hass)
for entity in self._entities: if (
_LOGGER.debug( api.nb_active_vtherm_for_boiler is None
"Examining the hvac_action of %s", or api.nb_active_device_for_boiler_threshold is None
entity.name, ):
_LOGGER.warning(
"%s - the entities to calculate the boiler state are not initialized. Boiler state cannot be calculated",
self,
) )
if ( return False
entity.hvac_mode == HVACMode.HEAT
and entity.hvac_action == HVACAction.HEATING active = (
): api.nb_active_vtherm_for_boiler >= api.nb_active_device_for_boiler_threshold
active = True )
break
if self._attr_is_on != active: if self._attr_is_on != active:
try: try:

View File

@@ -44,6 +44,7 @@ PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR, Platform.BINARY_SENSOR,
Platform.SENSOR, Platform.SENSOR,
Platform.SELECT, Platform.SELECT,
Platform.NUMBER,
] ]
CONF_HEATER = "heater_entity_id" CONF_HEATER = "heater_entity_id"

View File

@@ -0,0 +1,117 @@
# pylint: disable=unused-argument
""" Implements the VersatileThermostat select component """
import logging
# from homeassistant.const import EVENT_HOMEASSISTANT_START
from homeassistant.core import HomeAssistant, CoreState # , callback
from homeassistant.components.number import NumberEntity, NumberMode
from homeassistant.helpers.device_registry import DeviceInfo, DeviceEntryType
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from custom_components.versatile_thermostat.vtherm_api import VersatileThermostatAPI
from .const import (
DOMAIN,
DEVICE_MANUFACTURER,
CONF_NAME,
CONF_THERMOSTAT_TYPE,
CONF_THERMOSTAT_CENTRAL_CONFIG,
CONF_ADD_CENTRAL_BOILER_CONTROL,
overrides,
)
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the VersatileThermostat selects with config flow."""
_LOGGER.debug(
"Calling async_setup_entry entry=%s, data=%s", entry.entry_id, entry.data
)
unique_id = entry.entry_id
name = entry.data.get(CONF_NAME)
vt_type = entry.data.get(CONF_THERMOSTAT_TYPE)
is_central_boiler = entry.data.get(CONF_ADD_CENTRAL_BOILER_CONTROL)
if vt_type != CONF_THERMOSTAT_CENTRAL_CONFIG or not is_central_boiler:
return
entities = [
ActivateBoilerThresholdNumber(hass, unique_id, name, entry.data),
]
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
which should be active to activate the boiler"""
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
"""Initialize the energy sensor"""
self._hass = hass
self._config_id = unique_id
self._device_name = entry_infos.get(CONF_NAME)
self._attr_name = "Boiler Activation threshold"
self._attr_unique_id = "boiler_activation_threshold"
self._attr_value = self._attr_native_value = 1 # default value
self._attr_native_min_value = 1
self._attr_native_max_value = 9
self._attr_step = 1 # default value
self._attr_mode = NumberMode.AUTO
@property
def icon(self) -> str | None:
if isinstance(self._attr_native_value, int):
val = int(self._attr_native_value)
return f"mdi:numeric-{val}-box-outline"
else:
return "mdi:numeric-0-box-outline"
@property
def device_info(self) -> DeviceInfo:
"""Return the device info."""
return DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, self._config_id)},
name=self._device_name,
manufacturer=DEVICE_MANUFACTURER,
model=DOMAIN,
)
@overrides
async def async_added_to_hass(self) -> None:
await super().async_added_to_hass()
old_state: CoreState = await self.async_get_last_state()
_LOGGER.debug(
"%s - Calling async_added_to_hass old_state is %s", self, old_state
)
if old_state is not None:
self._attr_value = self._attr_native_value = int(float(old_state.state))
@overrides
def set_native_value(self, value: float) -> None:
"""Change the value"""
int_value = int(value)
old_value = int(self._attr_native_value)
if int_value == old_value:
return
self._attr_value = self._attr_native_value = int_value
def __str__(self):
return f"VersatileThermostat-{self.name}"

View File

@@ -55,7 +55,7 @@ async def async_setup_entry(
class CentralModeSelect(SelectEntity, RestoreEntity): class CentralModeSelect(SelectEntity, RestoreEntity):
"""Representation of a Energy sensor which exposes the energy""" """Representation of the central mode choice"""
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None: def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
"""Initialize the energy sensor""" """Initialize the energy sensor"""

View File

@@ -3,9 +3,15 @@
import logging import logging
import math import math
from homeassistant.core import HomeAssistant, callback, Event from homeassistant.core import HomeAssistant, callback, Event, CoreState
from homeassistant.const import UnitOfTime, UnitOfPower, UnitOfEnergy, PERCENTAGE from homeassistant.const import (
UnitOfTime,
UnitOfPower,
UnitOfEnergy,
PERCENTAGE,
EVENT_HOMEASSISTANT_START,
)
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
SensorEntity, SensorEntity,
@@ -16,9 +22,24 @@ from homeassistant.components.sensor import (
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.device_registry import DeviceInfo, DeviceEntryType
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.event import async_track_state_change_event
from homeassistant.components.climate import (
ClimateEntity,
DOMAIN as CLIMATE_DOMAIN,
HVACAction,
HVACMode,
)
from .base_thermostat import BaseThermostat
from .vtherm_api import VersatileThermostatAPI
from .commons import VersatileThermostatBaseEntity from .commons import VersatileThermostatBaseEntity
from .const import ( from .const import (
DOMAIN,
DEVICE_MANUFACTURER,
CONF_NAME, CONF_NAME,
CONF_DEVICE_POWER, CONF_DEVICE_POWER,
CONF_PROP_FUNCTION, CONF_PROP_FUNCTION,
@@ -28,6 +49,7 @@ from .const import (
CONF_THERMOSTAT_CLIMATE, CONF_THERMOSTAT_CLIMATE,
CONF_THERMOSTAT_TYPE, CONF_THERMOSTAT_TYPE,
CONF_THERMOSTAT_CENTRAL_CONFIG, CONF_THERMOSTAT_CENTRAL_CONFIG,
overrides,
) )
THRESHOLD_WATT_KILO = 100 THRESHOLD_WATT_KILO = 100
@@ -49,33 +71,39 @@ async def async_setup_entry(
name = entry.data.get(CONF_NAME) name = entry.data.get(CONF_NAME)
vt_type = entry.data.get(CONF_THERMOSTAT_TYPE) vt_type = entry.data.get(CONF_THERMOSTAT_TYPE)
entities = None
if vt_type == CONF_THERMOSTAT_CENTRAL_CONFIG: if vt_type == CONF_THERMOSTAT_CENTRAL_CONFIG:
return 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),
LastExtTemperatureSensor(hass, unique_id, name, entry.data),
TemperatureSlopeSensor(hass, unique_id, name, entry.data),
EMATemperatureSensor(hass, unique_id, name, entry.data),
]
if entry.data.get(CONF_DEVICE_POWER):
entities.append(EnergySensor(hass, unique_id, name, entry.data))
if entry.data.get(CONF_THERMOSTAT_TYPE) in [
CONF_THERMOSTAT_SWITCH,
CONF_THERMOSTAT_VALVE,
]:
entities.append(MeanPowerSensor(hass, unique_id, name, entry.data))
entities = [ if entry.data.get(CONF_PROP_FUNCTION) == PROPORTIONAL_FUNCTION_TPI:
LastTemperatureSensor(hass, unique_id, name, entry.data), entities.append(OnPercentSensor(hass, unique_id, name, entry.data))
LastExtTemperatureSensor(hass, unique_id, name, entry.data), entities.append(OnTimeSensor(hass, unique_id, name, entry.data))
TemperatureSlopeSensor(hass, unique_id, name, entry.data), entities.append(OffTimeSensor(hass, unique_id, name, entry.data))
EMATemperatureSensor(hass, unique_id, name, entry.data),
]
if entry.data.get(CONF_DEVICE_POWER):
entities.append(EnergySensor(hass, unique_id, name, entry.data))
if entry.data.get(CONF_THERMOSTAT_TYPE) in [
CONF_THERMOSTAT_SWITCH,
CONF_THERMOSTAT_VALVE,
]:
entities.append(MeanPowerSensor(hass, unique_id, name, entry.data))
if entry.data.get(CONF_PROP_FUNCTION) == PROPORTIONAL_FUNCTION_TPI: if entry.data.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_VALVE:
entities.append(OnPercentSensor(hass, unique_id, name, entry.data)) entities.append(ValveOpenPercentSensor(hass, unique_id, name, entry.data))
entities.append(OnTimeSensor(hass, unique_id, name, entry.data))
entities.append(OffTimeSensor(hass, unique_id, name, entry.data))
if entry.data.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_VALVE: if entry.data.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_CLIMATE:
entities.append(ValveOpenPercentSensor(hass, unique_id, name, entry.data)) entities.append(
RegulatedTemperatureSensor(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) async_add_entities(entities, True)
@@ -597,3 +625,112 @@ class EMATemperatureSensor(VersatileThermostatBaseEntity, SensorEntity):
def suggested_display_precision(self) -> int | None: def suggested_display_precision(self) -> int | None:
"""Return the suggested number of decimal digits for display.""" """Return the suggested number of decimal digits for display."""
return 2 return 2
class NbActiveDeviceForBoilerSensor(SensorEntity):
"""Representation of the threshold of the number of VTherm
which should be active to activate the boiler"""
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
"""Initialize the energy sensor"""
self._hass = hass
self._config_id = unique_id
self._device_name = entry_infos.get(CONF_NAME)
self._attr_name = "Nb device active for boiler"
self._attr_unique_id = "nb_device_active_boiler"
self._attr_value = self._attr_native_value = None # default value
self._entities = []
@property
def icon(self) -> str | None:
return "mdi:heat-wave"
@property
def device_info(self) -> DeviceInfo:
"""Return the device info."""
return DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, self._config_id)},
name=self._device_name,
manufacturer=DEVICE_MANUFACTURER,
model=DOMAIN,
)
@property
def state_class(self) -> SensorStateClass | None:
return SensorStateClass.MEASUREMENT
@property
def suggested_display_precision(self) -> int | None:
"""Return the suggested number of decimal digits for display."""
return 0
@overrides
async def async_added_to_hass(self) -> None:
await super().async_added_to_hass()
@callback
async def _async_startup_internal(*_):
_LOGGER.debug("%s - Calling async_startup_internal", self)
await self.listen_vtherms_entities()
if self.hass.state == CoreState.running:
await _async_startup_internal()
else:
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, _async_startup_internal
)
async def listen_vtherms_entities(self):
"""Initialize the listening of state change of VTherms"""
# Listen to all VTherm state change
self._entities = []
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)
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,
entities_id,
self.calculate_nb_active_devices,
)
_LOGGER.info(
"%s - VTherm that could controls the central boiler are %s",
self,
entities_id,
)
self.async_on_remove(listener_cancel)
else:
_LOGGER.debug("%s - no VTherm could controls the central boiler", self)
await self.calculate_nb_active_devices(None)
async def calculate_nb_active_devices(self, _):
"""Calculate the number of active VTherm that have an
influence on central boiler"""
_LOGGER.debug("%s - calculating the number of active VTherm", self)
nb_active = 0
for entity in self._entities:
_LOGGER.debug(
"Examining the hvac_action of %s",
entity.name,
)
if (
entity.hvac_mode == HVACMode.HEAT
and entity.hvac_action == HVACAction.HEATING
):
for under in entity.underlying_entities:
nb_active += 1 if under.is_device_active else 0
self._attr_native_value = nb_active
self.async_write_ha_state()
def __str__(self):
return f"VersatileThermostat-{self.name}"

View File

@@ -133,14 +133,14 @@ class UnderlyingEntity:
async def check_initial_state(self, hvac_mode: HVACMode): async def check_initial_state(self, hvac_mode: HVACMode):
"""Prevent the underlying to be on but thermostat is off""" """Prevent the underlying to be on but thermostat is off"""
if hvac_mode == HVACMode.OFF and self.is_device_active: if hvac_mode == HVACMode.OFF and self.is_device_active:
_LOGGER.warning( _LOGGER.info(
"%s - The hvac mode is OFF, but the underlying device is ON. Turning off device %s", "%s - The hvac mode is OFF, but the underlying device is ON. Turning off device %s",
self, self,
self._entity_id, self._entity_id,
) )
await self.set_hvac_mode(hvac_mode) await self.set_hvac_mode(hvac_mode)
elif hvac_mode != HVACMode.OFF and not self.is_device_active: elif hvac_mode != HVACMode.OFF and not self.is_device_active:
_LOGGER.warning( _LOGGER.info(
"%s - The hvac mode is %s, but the underlying device is not ON. Turning on device %s if needed", "%s - The hvac mode is %s, but the underlying device is not ON. Turning on device %s if needed",
self, self,
hvac_mode, hvac_mode,
@@ -771,12 +771,14 @@ class UnderlyingValve(UnderlyingEntity):
async def set_hvac_mode(self, hvac_mode: HVACMode) -> bool: async def set_hvac_mode(self, hvac_mode: HVACMode) -> bool:
"""Set the HVACmode. Returns true if something have change""" """Set the HVACmode. Returns true if something have change"""
if hvac_mode == HVACMode.OFF and self.is_device_active:
await self.turn_off()
if hvac_mode != HVACMode.OFF and not self.is_device_active:
await self.turn_on()
if self._hvac_mode != hvac_mode: if self._hvac_mode != hvac_mode:
self._hvac_mode = hvac_mode self._hvac_mode = hvac_mode
if hvac_mode == HVACMode.OFF:
await self.turn_off()
else:
await self.turn_on()
return True return True
else: else:
return False return False

View File

@@ -1,6 +1,6 @@
""" The API of Versatile Thermostat""" """ The API of Versatile Thermostat"""
import logging import logging
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, HassJob
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from .const import ( from .const import (
@@ -49,6 +49,8 @@ class VersatileThermostatAPI(dict):
self._short_ema_params = None self._short_ema_params = None
self._safety_mode = None self._safety_mode = None
self._central_boiler_entity = None self._central_boiler_entity = None
self._threshold_number_entity = None
self._nb_active_number_entity = None
def find_central_configuration(self): def find_central_configuration(self):
"""Search for a central configuration""" """Search for a central configuration"""
@@ -99,10 +101,26 @@ class VersatileThermostatAPI(dict):
class to register itself at creation""" class to register itself at creation"""
self._central_boiler_entity = central_boiler_entity self._central_boiler_entity = central_boiler_entity
def register_central_boiler_activation_number_threshold(
self, threshold_number_entity
):
"""register the two number entities needed for boiler activation"""
self._threshold_number_entity = threshold_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): async def reload_central_boiler_entities_list(self):
"""Reload the central boiler list of entities if a central boiler is used""" """Reload the central boiler list of entities if a central boiler is used"""
if self._central_boiler_entity is not None: if self._nb_active_number_entity is not None:
await self._central_boiler_entity.listen_vtherms_entities() await self._nb_active_number_entity.listen_vtherms_entities()
@property @property
def self_regulation_expert(self): def self_regulation_expert(self):
@@ -119,6 +137,35 @@ class VersatileThermostatAPI(dict):
"""Get the safety_mode params""" """Get the safety_mode params"""
return self._safety_mode return self._safety_mode
@property
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:
return None
else:
return self._nb_active_number_entity.native_value
@property
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
@property
def nb_active_device_for_boiler_threshold_entity(self):
"""Returns the number of active VTherm entity which have an
influence on boiler"""
return self._threshold_number_entity
@property
def nb_active_device_for_boiler_threshold(self):
"""Returns the number of active VTherm entity which have an
influence on boiler"""
if self._threshold_number_entity is None:
return None
return int(self._threshold_number_entity.native_value)
@property @property
def hass(self): def hass(self):
"""Get the HomeAssistant object""" """Get the HomeAssistant object"""