From dcff6734bfa2edaeff324767f33ed1179f06bde5 Mon Sep 17 00:00:00 2001 From: virtualdj Date: Sat, 21 Oct 2023 21:30:45 +0200 Subject: [PATCH] Usa i cancellation token invece di gestire la rientranza --- README.md | 1 + custom_components/pun_sensor/__init__.py | 62 ++++++++++------------ custom_components/pun_sensor/manifest.json | 10 ++-- 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index b3aa383..f7222b7 100644 --- a/README.md +++ b/README.md @@ -68,3 +68,4 @@ Ovviamente non ho alcuna certezza che tutto questo sia la maniera giusta di proc - [dlashua/bolted](https://github.com/dlashua/bolted/blob/50065eba8ffb4abe498587cd889aa9ff7873aeb3/custom_components/bolted/entity_manager.py), [pippyn/Home-Assistant-Sensor-Afvalbeheer](https://github.com/pippyn/Home-Assistant-Sensor-Afvalbeheer/blob/master/custom_components/afvalbeheer/sensor.py) e [questo articolo](https://aarongodfrey.dev/programming/restoring-an-entity-in-home-assistant/) per come salvare e ripristinare lo stato di una entità con `RestoreEntity` - Il componente di Home Assistant [energyzero](https://github.com/home-assistant/core/tree/dev/homeassistant/components/energyzero) per il blocco del `config_flow` già configurato e per esprimere correttamente le unità di misura - La [PR #99213](https://github.com/home-assistant/core/pull/99213/files) di Home Assistant per il suggerimento di usare `async_call_later` anziché sommare il timedelta all'ora corrente +- La [PR #76793](https://github.com/home-assistant/core/pull/76793/files) di Home Assistant per un esempio di come usare il [cancellation token](https://developers.home-assistant.io/docs/integration_listen_events/#available-event-helpers) restituito da `async_track_point_in_time` diff --git a/custom_components/pun_sensor/__init__.py b/custom_components/pun_sensor/__init__.py index 15adee8..1f255c1 100644 --- a/custom_components/pun_sensor/__init__.py +++ b/custom_components/pun_sensor/__init__.py @@ -55,7 +55,7 @@ async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: await hass.config_entries.async_forward_entry_setups(config, PLATFORMS) # Schedula l'aggiornamento via web 10 secondi dopo l'avvio - async_call_later(hass, timedelta(seconds=10), coordinator.update_pun) + coordinator.schedule_token = async_call_later(hass, timedelta(seconds=10), coordinator.update_pun) # Registra il callback di modifica opzioni config.async_on_unload(config.add_update_listener(update_listener)) @@ -90,9 +90,14 @@ async def update_listener(hass: HomeAssistant, config: ConfigEntry) -> None: # (perciò se è uguale esegue subito l'aggiornamento) next_update_pun = next_update_pun + timedelta(days=1) + # Annulla eventuali schedulazioni attive + if coordinator.schedule_token is not None: + coordinator.schedule_token() + coordinator.schedule_token = None + # Schedula la prossima esecuzione coordinator.web_retries = 0 - async_track_point_in_time(coordinator.hass, coordinator.update_pun, next_update_pun) + coordinator.schedule_token = async_track_point_in_time(coordinator.hass, coordinator.update_pun, next_update_pun) _LOGGER.debug('Prossimo aggiornamento web: %s', next_update_pun.strftime('%d/%m/%Y %H:%M:%S %z')) if config.options[CONF_ACTUAL_DATA_ONLY] != coordinator.actual_data_only: @@ -100,9 +105,14 @@ async def update_listener(hass: HomeAssistant, config: ConfigEntry) -> None: coordinator.actual_data_only = config.options[CONF_ACTUAL_DATA_ONLY] _LOGGER.debug('Nuovo valore \'usa dati reali\': %s.', coordinator.actual_data_only) - # Forza un nuovo aggiornamento immediato + # Annulla eventuali schedulazioni attive + if coordinator.schedule_token is not None: + coordinator.schedule_token() + coordinator.schedule_token = None + + # Esegue un nuovo aggiornamento immediatamente coordinator.web_retries = 0 - await coordinator.update_pun() + coordinator.schedule_token = async_call_later(coordinator.hass, timedelta(seconds=5), coordinator.update_pun) class PUNDataUpdateCoordinator(DataUpdateCoordinator): @@ -127,7 +137,7 @@ def __init__(self, hass: HomeAssistant, config: ConfigEntry) -> None: # Inizializza i valori di default self.web_retries = 0 - self.web_last_run = datetime.min.replace(tzinfo=dt_util.UTC) + self.schedule_token = None self.pun = [0.0, 0.0, 0.0, 0.0] self.orari = [0, 0, 0, 0] self.fascia_corrente = None @@ -276,30 +286,6 @@ async def update_fascia(self, now=None): async def update_pun(self, now=None): """Aggiorna i prezzi PUN da Internet (funziona solo se schedulata)""" - # Evita rientranze nella funzione - if ((dt_util.now() - self.web_last_run).total_seconds() < 2): - return - - # Verifica se è il primo aggiornamento dopo l'avvio - first_update = (self.web_last_run == datetime.min.replace(tzinfo=dt_util.UTC)) - self.web_last_run = dt_util.now() - - # Verifica che non sia un nuovo tentativo dopo un errore - if (self.web_retries == 0): - # Verifica l'orario di esecuzione - if ((now is not None) and (not first_update)): - if (now.date() != dt_util.now().date()): - # Esecuzione alla data non corretta (vecchia schedulazione) - _LOGGER.debug('Aggiornamento web ignorato a causa della data di schedulazione non corretta (%s).', now) - return - elif (now.hour != self.scan_hour): - # Esecuzione all'ora non corretta (vecchia schedulazione) - _LOGGER.debug('Aggiornamento web ignorato a causa dell\'ora di schedulazione non corretta (%s != %s).', now.hour, self.scan_hour) - return - elif (now is None): - # Esecuzione non schedulata - _LOGGER.debug('Esecuzione aggiornamento web non schedulato.') - # Aggiorna i dati da web try: # Esegue l'aggiornamento @@ -327,18 +313,23 @@ async def update_pun(self, now=None): # Ulteriori errori (4, 3, 2) self.web_retries -= 1 retry_in_minutes = 60 * (4 - self.web_retries) - + + # Annulla eventuali schedulazioni attive + if self.schedule_token is not None: + self.schedule_token() + self.schedule_token = None + # Prepara la schedulazione if (retry_in_minutes > 0): # Minuti dopo _LOGGER.warn('Errore durante l\'aggiornamento via web, nuovo tentativo tra %s minut%s.', retry_in_minutes, 'o' if retry_in_minutes == 1 else 'i', exc_info=e) - async_call_later(self.hass, timedelta(minutes=retry_in_minutes), self.update_pun) + self.schedule_token = async_call_later(self.hass, timedelta(minutes=retry_in_minutes), self.update_pun) else: # Giorno dopo _LOGGER.error('Errore durante l\'aggiornamento via web, tentativi esauriti.', exc_info=e) next_update_pun = dt_util.now().replace(hour=self.scan_hour, minute=0, second=0, microsecond=0) + timedelta(days=1) - async_track_point_in_time(self.hass, self.update_pun, next_update_pun) + self.schedule_token = async_track_point_in_time(self.hass, self.update_pun, next_update_pun) _LOGGER.debug('Prossimo aggiornamento web: %s', next_update_pun.strftime('%d/%m/%Y %H:%M:%S %z')) # Esce e attende la prossima schedulazione @@ -354,8 +345,13 @@ async def update_pun(self, now=None): # Se l'evento è già trascorso la esegue domani alla stessa ora next_update_pun = next_update_pun + timedelta(days=1) + # Annulla eventuali schedulazioni attive + if self.schedule_token is not None: + self.schedule_token() + self.schedule_token = None + # Schedula la prossima esecuzione - async_track_point_in_time(self.hass, self.update_pun, next_update_pun) + self.schedule_token = async_track_point_in_time(self.hass, self.update_pun, next_update_pun) _LOGGER.debug('Prossimo aggiornamento web: %s', next_update_pun.strftime('%d/%m/%Y %H:%M:%S %z')) def get_fascia_for_xml(data, festivo, ora) -> int: diff --git a/custom_components/pun_sensor/manifest.json b/custom_components/pun_sensor/manifest.json index 5122ccf..fa62479 100644 --- a/custom_components/pun_sensor/manifest.json +++ b/custom_components/pun_sensor/manifest.json @@ -1,14 +1,14 @@ { "domain": "pun_sensor", "name": "Prezzi PUN del mese", - "codeowners": [ - "@virtualdj" - ], + "codeowners": ["@virtualdj"], "config_flow": true, "dependencies": [], "documentation": "https://github.com/virtualdj/pun_sensor", - "iot_class": "local_polling", + "integration_type": "hub", + "iot_class": "cloud_polling", "issue_tracker": "https://github.com/virtualdj/pun_sensor/issues", + "loggers": ["pun_sensor"], "requirements": ["holidays", "bs4"], - "version": "0.3.3" + "version": "0.4.0" }