Add the device power and device energy into attributes #25
This commit is contained in:
@@ -118,6 +118,17 @@ template:
|
|||||||
unique_id: maison_occupee
|
unique_id: maison_occupee
|
||||||
state: "{{is_state('person.jmc', 'home') }}"
|
state: "{{is_state('person.jmc', 'home') }}"
|
||||||
device_class: occupancy
|
device_class: occupancy
|
||||||
|
- sensor:
|
||||||
|
- name: "Total énergie switch1"
|
||||||
|
unique_id: total_energie_switch1
|
||||||
|
unit_of_measurement: "kWh"
|
||||||
|
device_class: energy
|
||||||
|
state_class: total_increasing
|
||||||
|
state: >
|
||||||
|
{% set energy = state_attr('climate.thermostat_switch_1', 'total_energy') %}
|
||||||
|
{% if energy == 'unavailable' or energy is none%}unavailable{% else %}
|
||||||
|
{{ ((energy | float) / 1.0) | round(2, default=0) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
switch:
|
switch:
|
||||||
- platform: template
|
- platform: template
|
||||||
|
|||||||
@@ -134,6 +134,8 @@ from .const import (
|
|||||||
CONF_CLIMATE,
|
CONF_CLIMATE,
|
||||||
UnknownEntity,
|
UnknownEntity,
|
||||||
EventType,
|
EventType,
|
||||||
|
ATTR_MEAN_POWER_CYCLE,
|
||||||
|
ATTR_TOTAL_ENERGY,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .prop_algorithm import PropAlgorithm
|
from .prop_algorithm import PropAlgorithm
|
||||||
@@ -201,6 +203,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
# _registry: dict[str, object] = {}
|
# _registry: dict[str, object] = {}
|
||||||
_last_temperature_mesure: datetime
|
_last_temperature_mesure: datetime
|
||||||
_last_ext_temperature_mesure: datetime
|
_last_ext_temperature_mesure: datetime
|
||||||
|
_total_energy: float
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
|
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
|
||||||
"""Initialize the thermostat."""
|
"""Initialize the thermostat."""
|
||||||
@@ -251,6 +254,8 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
|
|
||||||
self._attr_translation_key = "versatile_thermostat"
|
self._attr_translation_key = "versatile_thermostat"
|
||||||
|
|
||||||
|
self._total_energy = None
|
||||||
|
|
||||||
self.post_init(entry_infos)
|
self.post_init(entry_infos)
|
||||||
|
|
||||||
def post_init(self, entry_infos):
|
def post_init(self, entry_infos):
|
||||||
@@ -441,6 +446,8 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
if self._motion_on:
|
if self._motion_on:
|
||||||
self._attr_preset_modes.append(PRESET_ACTIVITY)
|
self._attr_preset_modes.append(PRESET_ACTIVITY)
|
||||||
|
|
||||||
|
self._total_energy = 0
|
||||||
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"%s - Creation of a new VersatileThermostat entity: unique_id=%s heater_entity_id=%s",
|
"%s - Creation of a new VersatileThermostat entity: unique_id=%s heater_entity_id=%s",
|
||||||
self,
|
self,
|
||||||
@@ -780,6 +787,9 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
else:
|
else:
|
||||||
self._hvac_mode = HVACMode.OFF
|
self._hvac_mode = HVACMode.OFF
|
||||||
|
|
||||||
|
old_total_energy = old_state.attributes.get(ATTR_TOTAL_ENERGY)
|
||||||
|
if old_total_energy:
|
||||||
|
self._total_energy = old_total_energy
|
||||||
else:
|
else:
|
||||||
# No previous state, try and restore defaults
|
# No previous state, try and restore defaults
|
||||||
if self._target_temp is None:
|
if self._target_temp is None:
|
||||||
@@ -981,6 +991,21 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mean_cycle_power(self) -> float | None:
|
||||||
|
"""Returns tne mean power consumption during the cycle"""
|
||||||
|
if self._is_over_climate:
|
||||||
|
return None
|
||||||
|
elif self._device_power:
|
||||||
|
return self._device_power * self._prop_algorithm.on_percent
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def total_energy(self) -> float | None:
|
||||||
|
"""Returns the total energy calculated for this thermostast"""
|
||||||
|
return self._total_energy
|
||||||
|
|
||||||
def turn_aux_heat_on(self) -> None:
|
def turn_aux_heat_on(self) -> None:
|
||||||
"""Turn auxiliary heater on."""
|
"""Turn auxiliary heater on."""
|
||||||
if self._is_over_climate and self._underlying_climate:
|
if self._is_over_climate and self._underlying_climate:
|
||||||
@@ -1964,7 +1989,6 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"%s - No action on heater cause duration is 0", self
|
"%s - No action on heater cause duration is 0", self
|
||||||
)
|
)
|
||||||
self.update_custom_attributes()
|
|
||||||
self._async_cancel_cycle = async_call_later(
|
self._async_cancel_cycle = async_call_later(
|
||||||
self.hass,
|
self.hass,
|
||||||
time,
|
time,
|
||||||
@@ -1978,6 +2002,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
heater_action=self._async_heater_turn_on,
|
heater_action=self._async_heater_turn_on,
|
||||||
next_cycle_action=_turn_off_later,
|
next_cycle_action=_turn_off_later,
|
||||||
)
|
)
|
||||||
|
self.update_custom_attributes()
|
||||||
|
|
||||||
async def _turn_off_later(_):
|
async def _turn_off_later(_):
|
||||||
await _turn_on_off_later(
|
await _turn_on_off_later(
|
||||||
@@ -1986,6 +2011,9 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
heater_action=self._async_underlying_entity_turn_off,
|
heater_action=self._async_underlying_entity_turn_off,
|
||||||
next_cycle_action=_turn_on_later,
|
next_cycle_action=_turn_on_later,
|
||||||
)
|
)
|
||||||
|
# increment energy at the end of the cycle
|
||||||
|
self.incremente_energy()
|
||||||
|
self.update_custom_attributes()
|
||||||
|
|
||||||
await _turn_on_later(None)
|
await _turn_on_later(None)
|
||||||
|
|
||||||
@@ -2018,6 +2046,11 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
self.update_custom_attributes()
|
self.update_custom_attributes()
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
def incremente_energy(self):
|
||||||
|
"""increment the energy counter if device is active"""
|
||||||
|
if self.hvac_mode != HVACMode.OFF:
|
||||||
|
self._total_energy += self.mean_cycle_power * float(self._cycle_min) / 60.0
|
||||||
|
|
||||||
def update_custom_attributes(self):
|
def update_custom_attributes(self):
|
||||||
"""Update the custom extra attributes for the entity"""
|
"""Update the custom extra attributes for the entity"""
|
||||||
|
|
||||||
@@ -2054,6 +2087,9 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
"last_ext_temperature_datetime": self._last_ext_temperature_mesure.isoformat(),
|
"last_ext_temperature_datetime": self._last_ext_temperature_mesure.isoformat(),
|
||||||
"security_state": self._security_state,
|
"security_state": self._security_state,
|
||||||
"minimal_activation_delay_sec": self._minimal_activation_delay,
|
"minimal_activation_delay_sec": self._minimal_activation_delay,
|
||||||
|
"device_power": self._device_power,
|
||||||
|
ATTR_MEAN_POWER_CYCLE: self.mean_cycle_power,
|
||||||
|
ATTR_TOTAL_ENERGY: self.total_energy,
|
||||||
"last_update_datetime": datetime.now().isoformat(),
|
"last_update_datetime": datetime.now().isoformat(),
|
||||||
}
|
}
|
||||||
if self._is_over_climate:
|
if self._is_over_climate:
|
||||||
|
|||||||
@@ -135,6 +135,9 @@ SERVICE_SET_SECURITY = "set_security"
|
|||||||
DEFAULT_SECURITY_MIN_ON_PERCENT = 0.5
|
DEFAULT_SECURITY_MIN_ON_PERCENT = 0.5
|
||||||
DEFAULT_SECURITY_DEFAULT_ON_PERCENT = 0.1
|
DEFAULT_SECURITY_DEFAULT_ON_PERCENT = 0.1
|
||||||
|
|
||||||
|
ATTR_TOTAL_ENERGY = "total_energy"
|
||||||
|
ATTR_MEAN_POWER_CYCLE = "mean_cycle_power"
|
||||||
|
|
||||||
|
|
||||||
class EventType(Enum):
|
class EventType(Enum):
|
||||||
"""The event type that can be sent"""
|
"""The event type that can be sent"""
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from pytest_homeassistant_custom_component.common import MockConfigEntry
|
|||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
|
|
||||||
from ..climate import VersatileThermostat
|
from ..climate import VersatileThermostat
|
||||||
from ..const import DOMAIN, PRESET_SECURITY, PRESET_POWER, EventType
|
from ..const import *
|
||||||
|
|
||||||
from homeassistant.components.climate import (
|
from homeassistant.components.climate import (
|
||||||
ClimateEntity,
|
ClimateEntity,
|
||||||
|
|||||||
@@ -11,24 +11,25 @@ async def test_tpi_calculation(hass: HomeAssistant, skip_hass_states_is_state):
|
|||||||
title="TheOverSwitchMockName",
|
title="TheOverSwitchMockName",
|
||||||
unique_id="uniqueId",
|
unique_id="uniqueId",
|
||||||
data={
|
data={
|
||||||
"name": "TheOverSwitchMockName",
|
CONF_NAME: "TheOverSwitchMockName",
|
||||||
"thermostat_type": "thermostat_over_switch",
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH,
|
||||||
"temperature_sensor_entity_id": "sensor.mock_temp_sensor",
|
CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
|
||||||
"external_temperature_sensor_entity_id": "sensor.mock_ext_temp_sensor",
|
CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
|
||||||
"cycle_min": 5,
|
CONF_CYCLE_MIN: 5,
|
||||||
"temp_min": 15,
|
CONF_TEMP_MIN: 15,
|
||||||
"temp_max": 30,
|
CONF_TEMP_MAX: 30,
|
||||||
"use_window_feature": False,
|
CONF_USE_WINDOW_FEATURE: False,
|
||||||
"use_motion_feature": False,
|
CONF_USE_MOTION_FEATURE: False,
|
||||||
"use_power_feature": False,
|
CONF_USE_POWER_FEATURE: False,
|
||||||
"use_presence_feature": False,
|
CONF_USE_PRESENCE_FEATURE: False,
|
||||||
"heater_entity_id": "switch.mock_switch",
|
CONF_HEATER: "switch.mock_switch",
|
||||||
"proportional_function": "tpi",
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
"tpi_coef_int": 0.3,
|
CONF_TPI_COEF_INT: 0.3,
|
||||||
"tpi_coef_ext": 0.01,
|
CONF_TPI_COEF_EXT: 0.01,
|
||||||
"minimal_activation_delay": 30,
|
CONF_MINIMAL_ACTIVATION_DELAY: 30,
|
||||||
"security_delay_min": 5,
|
CONF_SECURITY_DELAY_MIN: 5,
|
||||||
"security_default_on_percent": 0.3,
|
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
||||||
|
# CONF_DEVICE_POWER: 100,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,6 +46,7 @@ async def test_tpi_calculation(hass: HomeAssistant, skip_hass_states_is_state):
|
|||||||
assert tpi_algo.calculated_on_percent == 1
|
assert tpi_algo.calculated_on_percent == 1
|
||||||
assert tpi_algo.on_time_sec == 300
|
assert tpi_algo.on_time_sec == 300
|
||||||
assert tpi_algo.off_time_sec == 0
|
assert tpi_algo.off_time_sec == 0
|
||||||
|
assert entity.mean_cycle_power is None
|
||||||
|
|
||||||
tpi_algo.calculate(15, 14, 5)
|
tpi_algo.calculate(15, 14, 5)
|
||||||
assert tpi_algo.on_percent == 0.4
|
assert tpi_algo.on_percent == 0.4
|
||||||
|
|||||||
Reference in New Issue
Block a user