Skip to content

Commit

Permalink
Usa i cancellation token invece di gestire la rientranza
Browse files Browse the repository at this point in the history
  • Loading branch information
virtualdj committed Oct 21, 2023
1 parent 2504d32 commit dcff673
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 38 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
62 changes: 29 additions & 33 deletions custom_components/pun_sensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -90,19 +90,29 @@ 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:
# Modificata impostazione 'Usa dati reali'
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):
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down
10 changes: 5 additions & 5 deletions custom_components/pun_sensor/manifest.json
Original file line number Diff line number Diff line change
@@ -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"
}

0 comments on commit dcff673

Please sign in to comment.