Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 600 energy can be negative after configuration #614

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions custom_components/versatile_thermostat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,20 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:

if hass.state == CoreState.running:
await api.reload_central_boiler_entities_list()
await api.init_vtherm_links()
await api.init_vtherm_links(entry.entry_id)

return True


async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Update listener."""

_LOGGER.debug(
"Calling update_listener entry: entry_id='%s', value='%s'",
entry.entry_id,
entry.data,
)

if entry.data.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_CENTRAL_CONFIG:
await reload_all_vtherm(hass)
else:
Expand All @@ -193,7 +200,7 @@ async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
api: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api(hass)
if api is not None:
await api.reload_central_boiler_entities_list()
await api.init_vtherm_links()
await api.init_vtherm_links(entry.entry_id)


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
Expand Down
49 changes: 47 additions & 2 deletions custom_components/versatile_thermostat/base_thermostat.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
)

from homeassistant.components.climate import ClimateEntity
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.restore_state import (
RestoreEntity,
async_get as restore_async_get,
)
from homeassistant.helpers.entity import Entity
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.device_registry import DeviceInfo, DeviceEntryType
Expand Down Expand Up @@ -84,6 +87,10 @@ def get_tz(hass: HomeAssistant):
return dt_util.get_time_zone(hass.config.time_zone)


_LOGGER_ENERGY = logging.getLogger(
"custom_components.versatile_thermostat.energy_debug"
)

class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
"""Representation of a base class for all Versatile Thermostat device."""

Expand Down Expand Up @@ -198,6 +205,7 @@ def __init__(
self._attr_translation_key = "versatile_thermostat"

self._total_energy = None
_LOGGER_ENERGY.debug("%s - _init_ resetting energy to None", self)

# because energy of climate is calculated in the thermostat we have to keep that here and not in underlying entity
self._underlying_climate_start_hvac_action_date = None
Expand Down Expand Up @@ -470,6 +478,7 @@ def post_init(self, config_entry: ConfigData):
self._presence_state = None

self._total_energy = None
_LOGGER_ENERGY.debug("%s - post_init_ resetting energy to None", self)

# Read the parameter from configuration.yaml if it exists
short_ema_params = DEFAULT_SHORT_EMA_PARAMS
Expand Down Expand Up @@ -585,14 +594,24 @@ async def async_added_to_hass(self):
# issue 428. Link to others entities will start at link
# await self.async_startup()

async def async_will_remove_from_hass(self):
"""Try to force backup of entity"""
_LOGGER_ENERGY.debug(
"%s - force write before remove. Energy is %s", self, self.total_energy
)
# Force dump in background
await restore_async_get(self.hass).async_dump_states()

def remove_thermostat(self):
"""Called when the thermostat will be removed"""
_LOGGER.info("%s - Removing thermostat", self)

for under in self._underlyings:
under.remove_entity()

async def async_startup(self, central_configuration):
"""Triggered on startup, used to get old state and set internal states accordingly"""
"""Triggered on startup, used to get old state and set internal states accordingly. This is triggered by
VTherm API"""
_LOGGER.debug("%s - Calling async_startup", self)

_LOGGER.debug("%s - Calling async_startup_internal", self)
Expand Down Expand Up @@ -804,6 +823,11 @@ async def get_my_previous_state(self):

old_total_energy = old_state.attributes.get(ATTR_TOTAL_ENERGY)
self._total_energy = old_total_energy if old_total_energy is not None else 0
_LOGGER_ENERGY.debug(
"%s - get_my_previous_state restored energy is %s",
self,
self._total_energy,
)

self.restore_specific_previous_state(old_state)
else:
Expand All @@ -817,6 +841,11 @@ async def get_my_previous_state(self):
"No previously saved temperature, setting to %s", self._target_temp
)
self._total_energy = 0
_LOGGER_ENERGY.debug(
"%s - get_my_previous_state no previous state energy is %s",
self,
self._total_energy,
)

if not self._hvac_mode:
self._hvac_mode = HVACMode.OFF
Expand Down Expand Up @@ -2622,6 +2651,22 @@ def update_custom_attributes(self):
"hvac_off_reason": self.hvac_off_reason,
}

_LOGGER_ENERGY.debug(
"%s - update_custom_attributes saved energy is %s",
self,
self.total_energy,
)

@overrides
def async_write_ha_state(self):
"""overrides to have log"""
_LOGGER_ENERGY.debug(
"%s - async_write_ha_state written state energy is %s",
self,
self._total_energy,
)
return super().async_write_ha_state()

@callback
def async_registry_entry_updated(self):
"""update the entity if the config entry have been updated
Expand Down
1 change: 0 additions & 1 deletion custom_components/versatile_thermostat/commons.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

_LOGGER = logging.getLogger(__name__)


def get_tz(hass: HomeAssistant):
"""Get the current timezone"""

Expand Down
2 changes: 1 addition & 1 deletion custom_components/versatile_thermostat/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ async def validate_input(self, data: dict) -> None:
CONF_USE_PRESETS_CENTRAL_CONFIG,
CONF_USE_ADVANCED_CENTRAL_CONFIG,
CONF_USE_CENTRAL_MODE,
CONF_USE_CENTRAL_BOILER_FEATURE,
# CONF_USE_CENTRAL_BOILER_FEATURE, this is for Central Config
CONF_USED_BY_CENTRAL_BOILER,
]:
if data.get(conf) is True:
Expand Down
6 changes: 5 additions & 1 deletion custom_components/versatile_thermostat/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,11 @@
CONF_WINDOW_ECO_TEMP,
]

SUPPORT_FLAGS = ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON
SUPPORT_FLAGS = (
ClimateEntityFeature.TARGET_TEMPERATURE
| ClimateEntityFeature.TURN_OFF
| ClimateEntityFeature.TURN_ON
)

SERVICE_SET_PRESENCE = "set_presence"
SERVICE_SET_PRESET_TEMPERATURE = "set_preset_temperature"
Expand Down
17 changes: 16 additions & 1 deletion custom_components/versatile_thermostat/thermostat_climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
)

_LOGGER = logging.getLogger(__name__)
_LOGGER_ENERGY = logging.getLogger(
"custom_components.versatile_thermostat.energy_debug"
)


HVAC_ACTION_ON = [ # pylint: disable=invalid-name
HVACAction.COOLING,
Expand Down Expand Up @@ -97,7 +101,7 @@ def post_init(self, config_entry: ConfigData):
"""Initialize the Thermostat"""

super().post_init(config_entry)

for climate in config_entry.get(CONF_UNDERLYING_LIST):
self._underlyings.append(
UnderlyingClimate(
Expand Down Expand Up @@ -549,6 +553,7 @@ def update_custom_attributes(self):
] = self._auto_start_stop_algo.accumulated_error_threshold

self.async_write_ha_state()

_LOGGER.debug(
"%s - Calling update_custom_attributes: %s",
self,
Expand Down Expand Up @@ -595,8 +600,18 @@ def incremente_energy(self):

if self._total_energy is None:
self._total_energy = added_energy
_LOGGER_ENERGY.debug(
"%s - incremente_energy set energy is %s",
self,
self._total_energy,
)
else:
self._total_energy += added_energy
_LOGGER_ENERGY.debug(
"%s - incremente_energy incremented energy is %s",
self,
self._total_energy,
)

_LOGGER.debug(
"%s - added energy is %.3f . Total energy is now: %.3f",
Expand Down
14 changes: 13 additions & 1 deletion custom_components/versatile_thermostat/thermostat_switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
from .prop_algorithm import PropAlgorithm

_LOGGER = logging.getLogger(__name__)

_LOGGER_ENERGY = logging.getLogger(
"custom_components.versatile_thermostat.energy_debug"
)

class ThermostatOverSwitch(BaseThermostat[UnderlyingSwitch]):
"""Representation of a base class for a Versatile Thermostat over a switch."""
Expand Down Expand Up @@ -183,8 +185,18 @@ def incremente_energy(self):

if self._total_energy is None:
self._total_energy = added_energy
_LOGGER_ENERGY.debug(
"%s - incremente_energy set energy is %s",
self,
self._total_energy,
)
else:
self._total_energy += added_energy
_LOGGER_ENERGY.debug(
"%s - incremente_energy increment energy is %s",
self,
self._total_energy,
)

self.update_custom_attributes()

Expand Down
14 changes: 13 additions & 1 deletion custom_components/versatile_thermostat/thermostat_valve.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
from .underlyings import UnderlyingValve

_LOGGER = logging.getLogger(__name__)

_LOGGER_ENERGY = logging.getLogger(
"custom_components.versatile_thermostat.energy_debug"
)

class ThermostatOverValve(BaseThermostat[UnderlyingValve]): # pylint: disable=abstract-method
"""Representation of a class for a Versatile Thermostat over a Valve"""
Expand Down Expand Up @@ -265,8 +267,18 @@ def incremente_energy(self):

if self._total_energy is None:
self._total_energy = added_energy
_LOGGER_ENERGY.debug(
"%s - incremente_energy set energy is %s",
self,
self._total_energy,
)
else:
self._total_energy += added_energy
_LOGGER_ENERGY.debug(
"%s - get_my_previous_state increment energy is %s",
self,
self._total_energy,
)

self.update_custom_attributes()

Expand Down
6 changes: 4 additions & 2 deletions custom_components/versatile_thermostat/vtherm_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,11 @@ def get_temperature_number_value(self, config_id, preset_name) -> float | None:
return entity.state
return None

async def init_vtherm_links(self):
async def init_vtherm_links(self, entry_id=None):
"""Initialize all VTherms entities links
This method is called when HA is fully started (and all entities should be initialized)
Or when we need to reload all VTherm links (with Number temp entities, central boiler, ...)
If entry_id is set, only the VTherm of this entry will be reloaded
"""
await self.reload_central_boiler_binary_listener()
await self.reload_central_boiler_entities_list()
Expand All @@ -175,7 +176,8 @@ async def init_vtherm_links(self):
entity.device_info
and entity.device_info.get("model", None) == DOMAIN
):
await entity.async_startup(self.find_central_configuration())
if entry_id is None or entry_id == entity.unique_id:
await entity.async_startup(self.find_central_configuration())

async def init_vtherm_preset_with_central(self):
"""Init all VTherm presets when the VTherm uses central temperature"""
Expand Down
Loading