From 13ddfc2fe606c53345891530f47503bfbedbde1d Mon Sep 17 00:00:00 2001 From: Gariam-1 <126163056+Gariam-1@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:26:17 +0100 Subject: [PATCH] Risolto un bug fatale e aggiunti alcuni attributi - Risolto il fallito caricamento dell'integrazione di sabato con contratto tri-orario. - Aggiunto attributo "Fascia successiva" al sensore "Prezzo zonale fascia corrente" - Aggiunti attributi "Ora corrente", "Ora successiva", "Prezzo_successivo" e "Prezzo medio" al sensore "Prezzo zonale orario" - Ora tutti i prezzi si arrotondano automaticamente all'ultima cifra decimale significativa. --- custom_components/pzo_sensor/coordinator.py | 9 +++-- custom_components/pzo_sensor/interfaces.py | 4 ++- custom_components/pzo_sensor/manifest.json | 2 +- custom_components/pzo_sensor/sensor.py | 37 +++++++++++++++------ custom_components/pzo_sensor/utils.py | 20 +++++++---- 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/custom_components/pzo_sensor/coordinator.py b/custom_components/pzo_sensor/coordinator.py index 717e607..26c7f3f 100644 --- a/custom_components/pzo_sensor/coordinator.py +++ b/custom_components/pzo_sensor/coordinator.py @@ -139,7 +139,7 @@ async def _async_update_data(self): """Aggiornamento dati a intervalli prestabiliti.""" # Calcola l'intervallo di date per il mese corrente - date_end = dt_util.now().date() + date_end = dt_util.now().date() + timedelta(days=1) date_start = date(date_end.year, date_end.month, 1) if self.month_average else date_end # All'inizio del mese, aggiunge i valori del mese precedente @@ -203,7 +203,7 @@ async def _async_update_data(self): ) # Estrae i dati dall'archivio - self.pz_data.data = extract_xml(archive, self.pz_data.data, self.zone) + self.pz_data.data = extract_xml(archive, self.pz_data.data, self.zone, self.month_average) archive.close() # Per ogni fascia, calcola il valore dei prezzi zonali @@ -213,7 +213,10 @@ async def _async_update_data(self): self.pz_values.value[fascia] = pz_list[datetime.now().hour] self.pz_values.value[Fascia.MONO] = mean(self.pz_data.data[fascia]) else: - self.pz_values.value[fascia] = mean(self.pz_data.data[fascia]) + if len(self.pz_data.data[fascia]) > 0: + self.pz_values.value[fascia] = mean(self.pz_data.data[fascia]) + else: + self.pz_values.value[fascia] = 0 # Calcola la fascia F23 self.pz_values.value[Fascia.F23] = self.pz_values.value[Fascia.F2] * 0.46 + self.pz_values.value[Fascia.F3] * 0.54 diff --git a/custom_components/pzo_sensor/interfaces.py b/custom_components/pzo_sensor/interfaces.py index 23fbe4c..4da6d5a 100644 --- a/custom_components/pzo_sensor/interfaces.py +++ b/custom_components/pzo_sensor/interfaces.py @@ -11,6 +11,7 @@ class Fascia(Enum): F3 = "F3" F23 = "F23" ORARIA = "ORARIA" + ORARIA_NEXT = "ORARIA_NEXT" class PricesData: @@ -18,10 +19,11 @@ class PricesData: def __init__(self): self.data: dict[Fascia, list[float]] = { - Fascia.ORARIA: [], + Fascia.ORARIA: [0] * 24, Fascia.F1: [], Fascia.F2: [], Fascia.F3: [], + Fascia.ORARIA_NEXT: [0] * 24 } diff --git a/custom_components/pzo_sensor/manifest.json b/custom_components/pzo_sensor/manifest.json index 680148e..7d8a379 100644 --- a/custom_components/pzo_sensor/manifest.json +++ b/custom_components/pzo_sensor/manifest.json @@ -12,5 +12,5 @@ "loggers": ["pzo_sensor"], "requirements": [], "single_config_entry": true, - "version": "1.0.0" + "version": "1.0.1" } diff --git a/custom_components/pzo_sensor/sensor.py b/custom_components/pzo_sensor/sensor.py index 5b0f5ae..451b6ad 100644 --- a/custom_components/pzo_sensor/sensor.py +++ b/custom_components/pzo_sensor/sensor.py @@ -2,7 +2,7 @@ from typing import Any from zoneinfo import ZoneInfo -from datetime import datetime +from datetime import datetime, timedelta from awesomeversion.awesomeversion import AwesomeVersion @@ -215,7 +215,7 @@ def extra_state_attributes(self) -> dict[str, Any]: # Nelle versioni precedenti di Home Assistant # restituisce un valore arrotondato come attributo - return {ATTR_ROUNDED_DECIMALS: str(format(round(self.native_value, 3), ".3f"))} + return {ATTR_ROUNDED_DECIMALS: str(format(round(self.native_value, 6), ".6g"))} class FasciaSensorEntity(CoordinatorEntity, SensorEntity): @@ -271,9 +271,7 @@ def native_value(self) -> str | None: def extra_state_attributes(self) -> dict[str, Any] | None: """Attributi aggiuntivi del sensore.""" return { - "fascia_successiva": self.coordinator.fascia_successiva.value - if self.coordinator.fascia_successiva - else None, + "fascia_successiva": self.coordinator.fascia_successiva.value if self.coordinator.fascia_successiva else None, "inizio_fascia_successiva": self.coordinator.prossimo_cambio_fascia, "termine_fascia_successiva": self.coordinator.termine_prossima_fascia, } @@ -384,15 +382,20 @@ def name(self) -> str: @property def extra_state_attributes(self) -> dict[str, Any]: """Restituisce gli attributi di stato.""" + + attributi = { + "fascia_successiva": str(format(self.coordinator.pz_values.value[self.coordinator.fascia_successiva], ".6g")) + } + if CommonSettings.has_suggested_display_precision: - return {} + return attributi # Nelle versioni precedenti di Home Assistant # restituisce un valore arrotondato come attributo - return {ATTR_ROUNDED_DECIMALS: str(format(round(self.native_value, 3), ".3f"))} + return {ATTR_ROUNDED_DECIMALS: str(format(round(self.native_value, 6), ".6g"))} | attributi class PrezzoOrarioSensorEntity(CoordinatorEntity, SensorEntity, RestoreEntity): - """Sensore che rappresenta il prezzo zonale della fascia corrente.""" + """Sensore che rappresenta il prezzo zonale orario.""" def __init__(self, coordinator: PricesDataUpdateCoordinator) -> None: """Inizializza il sensore.""" @@ -484,9 +487,23 @@ def name(self) -> str: @property def extra_state_attributes(self) -> dict[str, Any]: """Restituisce gli attributi di stato.""" + + data_corrente = datetime.now() + prossima_ora = data_corrente + timedelta(hours=1) + stesso_giorno = data_corrente.day == prossima_ora.day + stesso_mese = data_corrente.month == prossima_ora.month + attributi = { + "ora_corrente": data_corrente.hour, + "ora_successiva": prossima_ora.hour, + "prezzo_successivo": str(format(self.coordinator.pz_data.data[Fascia.ORARIA][prossima_ora.hour] + if (self.coordinator.month_average and stesso_mese) or stesso_giorno + else self.coordinator.pz_data.data[Fascia.ORARIA_NEXT][prossima_ora.hour], ".6g")), + "prezzo_medio": str(format(self.coordinator.pz_values.value[Fascia.MONO], ".6g")) + } + if CommonSettings.has_suggested_display_precision: - return {} + return attributi # Nelle versioni precedenti di Home Assistant # restituisce un valore arrotondato come attributo - return {ATTR_ROUNDED_DECIMALS: str(format(round(self.native_value, 3), ".3f"))} \ No newline at end of file + return {ATTR_ROUNDED_DECIMALS: str(format(round(self.native_value, 6), ".6g"))} | attributi \ No newline at end of file diff --git a/custom_components/pzo_sensor/utils.py b/custom_components/pzo_sensor/utils.py index 94c4cbb..d63304f 100644 --- a/custom_components/pzo_sensor/utils.py +++ b/custom_components/pzo_sensor/utils.py @@ -53,13 +53,15 @@ def get_fascia(dataora: datetime, contract: int) -> tuple[Fascia, datetime]: fascia = Fascia.F23 # Prossima fascia: alle 8 di un giorno non domenica, sabato o festività prossima = get_next_date(dataora, 8, 1, True, True) + + return fascia, prossima elif dataora.weekday() != 5: fascia = Fascia.F3 # Prossima fascia: alle 7 di un giorno non domenica o festività prossima = get_next_date(dataora, 7, 1, True) - return fascia, prossima + return fascia, prossima match dataora.weekday(): # Sabato @@ -148,7 +150,7 @@ def get_next_date(dataora: datetime, ora: int, offset: int = 0, feriale: bool = return prossima -def extract_xml(priceArchive: ZipFile, pz_data: dict, zone: str) -> list[dict[Fascia, list[float]]]: +def extract_xml(priceArchive: ZipFile, pz_data: dict, zone: str, mediaMese: True) -> list[dict[Fascia, list[float]]]: """Estrae i valori dei prezzi per ogni fascia da un archivio zip contenente un XML per giorno del mese. Returns tuple(zonali, consumi zonali): @@ -157,10 +159,11 @@ def extract_xml(priceArchive: ZipFile, pz_data: dict, zone: str) -> list[dict[Fa """ # Carica le festività it_holidays = holidays.IT() # type: ignore[attr-defined] + oggi = datetime.now().date() # Azzera i dati precedenti for f in pz_data.keys(): - pz_data[f].clear() + if (f not in [Fascia.ORARIA, Fascia.ORARIA_NEXT]): pz_data[f].clear() # Esamina ogni file XML negli ZIP (ordinandoli prima) priceFiles = priceArchive.namelist() @@ -202,6 +205,7 @@ def extract_xml(priceArchive: ZipFile, pz_data: dict, zone: str) -> list[dict[Fa int(dat_string.text[4:6]), int(dat_string.text[6:8]), ) + domani = oggi < dat_date # Verifica la festività festivo = dat_date in it_holidays @@ -219,12 +223,14 @@ def extract_xml(priceArchive: ZipFile, pz_data: dict, zone: str) -> list[dict[Fa prezzo_string = prezzo_string.replace(".", "").replace(",", ".") prezzo_pz = float(prezzo_string) / 1000 - # Somma i valori dei diversi file per fascia per poter fare la media in seguito - if file_index > 0: + # Somma i prezzi orari dei diversi file per poter fare la media in seguito + if not domani or (mediaMese and oggi.month == dat_date.month): pz_data[Fascia.ORARIA][ora] += prezzo_pz else: - pz_data[Fascia.ORARIA].append(prezzo_pz) - pz_data[fascia].append(prezzo_pz) + pz_data[Fascia.ORARIA_NEXT][ora] = prezzo_pz + + # Aggiunge il prezzo al calcolo delle varie fasce, eccetto quando è il primo giorno del mese successivo al giorno corrente + if oggi.month == dat_date.month: pz_data[fascia].append(prezzo_pz) # Divide per il numero di file in cui erano presenti prezzi per completare la media for ora in range(len(pz_data[Fascia.ORARIA])):