Skip to content
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
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ La prima casella a discesa permette di selezionare la _zona geografica_ di rifer

Tramite lo slider invece è possibile selezionare un'_ora del giorno_ in cui scaricare i prezzi aggiornati dell'energia (default: 1); il minuto di esecuzione, invece, è determinato automaticamente per evitare di gravare eccessivamente sulle API del sito (e mantenuto fisso, finché l'ora non viene modificata). Se per qualche ragione il sito non fosse raggiungibile, verranno effettuati altri tentativi dopo 10, 60, 120 e 180 minuti.

Nel caso si fosse interessati ai prezzi zonali, selezionare un'orario uguale o superiore a 15, così da essere sicuri che il GME abbia pubblicato i dati anche del giorno successivo (accessibili tramite gli [attributi dello stesso sensore](#prezzo-zonale)).
Nel caso si fosse interessati ai prezzi zonali, selezionare un'**orario uguale o superiore a 15**, così da essere sicuri che il GME abbia pubblicato i dati anche del **giorno successivo** (accessibili tramite gli [attributi dello stesso sensore](#prezzo-zonale)).

Se la casella di controllo _Usa solo dati reali ad inizio mese_ è **attivata**, all'inizio del mese quando non ci sono i prezzi per tutte le fasce orarie questi vengono disabilitati (non viene mostrato quindi un prezzo in €/kWh finché i dati non sono in numero sufficiente); nel caso invece la casella fosse **disattivata** (default) nel conteggio vengono inclusi gli ultimi giorni del mese precedente in modo da avere sempre un valore in €/kWh.

Expand All @@ -41,7 +41,7 @@ Se la casella di controllo _Usa solo dati reali ad inizio mese_ è **attivata**,

L'integrazione fornisce il nome della fascia corrente relativa all'orario di Home Assistant (tra F1 / F2 / F3), i prezzi delle tre fasce F1 / F2 / F3 più la fascia mono-oraria, la [fascia F23](#fascia-f23-)\* e il prezzo della fascia corrente. Questi sono i dati intesi come mensili, da paragonare a quelli in bolletta una volta aggiunti costi fissi e tasse (vedere [_prezzo al dettaglio_](#prezzo-al-dettaglio)).

Poi ci sono i due sensori con i prezzi orari (con il simbolo dell'orologio nell'icona), ad esempio utilizzabili per calcoli con impianti fotovoltaici: [PUN orario](#pun-orario) e [prezzo zonale](#prezzo-zonale).
Poi ci sono i sensori con i prezzi orari (con il simbolo dell'orologio nell'icona), ad esempio utilizzabili per calcoli con impianti fotovoltaici: [PUN orario](#pun-orario-e-pun-15-minuti) e [prezzo zonale](#prezzo-zonale) che dalla versione 4 (ottobre 2025) sono disponibili anche nelle varianti a 15 minuti.

### Prezzo al dettaglio

Expand Down Expand Up @@ -88,25 +88,34 @@ Prezzo zonale di oggi e domani
{%- set prezzo_prossimo = state_attr('sensor.pun_prezzo_zonale', orario_prossimo | string) -%}
Prezzo zonale prossimo = {{ "%.6f" % prezzo_prossimo }} €/kWh
({{ orario_prossimo }})

{# Esempio di recupero del prossimo prezzo zonale da 15 minuti #}
{%- set orario_prossimo_15min = (utcnow() + timedelta(minutes=15)).astimezone(now().tzinfo) -%}
{%- set orario_prossimo_15min = orario_prossimo_15min.replace(minute=(orario_prossimo_15min.minute // 15) * 15, second=0, microsecond=0) -%}
{%- set prezzo_prossimo_15min = state_attr('sensor.pun_prezzo_zonale_15min', orario_prossimo_15min | string) -%}
Prezzo zonale prossimo da 15 minuti = {{ "%.6f" % prezzo_prossimo_15min }} €/kWh
({{ orario_prossimo_15min }})
```

I dati sono visibili anche in _Home Assistant > Strumenti per sviluppatori > Stati_ filtrando `sensor.pun_prezzo_zonale` come entità e attivando la casella di controllo _Attributi_.
I dati sono visibili anche in _Home Assistant > Strumenti per sviluppatori > Stati_ filtrando `sensor.pun_prezzo_zonale` come entità e attivando la casella di controllo _Attributi_. Lo stesso vale per i prezzi a 15 minuti, filtrando `sensor.pun_prezzo_zonale_15min`.

### PUN orario
### PUN orario e PUN 15 minuti

In maniera simile al prezzo zonale, anche il valore del PUN orario (nome sensore: `sensor.pun_orario`) ha gli attributi con i prezzi di oggi e domani, se disponibili.
In maniera simile al prezzo zonale, anche i valori del PUN orario (nome sensore: `sensor.pun_orario`) e PUN 15 minuti (nome sensore: `pun_15min`) hanno gli attributi con i prezzi di oggi e domani, se disponibili.

### In caso di problemi

È possibile abilitare la registrazione dei log tramite l'interfaccia grafica in **Impostazioni > Dispositivi e servizi > Prezzi PUN del mese** e cliccando sul pulsante **Abilita la registrazione di debug**.
È possibile abilitare la registrazione dei log tramite l'interfaccia grafica in **Impostazioni > Dispositivi e servizi > Prezzi PUN del mese** e cliccando sul pulsante **⋮ > Abilita la registrazione di debug**.

![Abilitazione log di debug](screenshot_debug_1.png "Abilitazione log di debug")

Il tasto verrà modificato come nell'immagine qui sotto:
Il tasto verrà modificato come nell'immagine qui sotto; dopo che si verifica il problema, premere su **Disabilita**.

![Disabilitazione log di debug](screenshot_debug_2.png "Disabilitazione log di debug")

![Estrazione log di debug](screenshot_debug_2.png "Estrazione log di debug")
In questo modo verrà scaricato un file di log con le informazioni da allegare alle [Issue](https://github.com/virtualdj/pun_sensor/issues).

Dopo che si verifica il problema, premerlo nuovamente: in questo modo verrà scaricato un file di log con le informazioni da allegare alle [Issue](https://github.com/virtualdj/pun_sensor/issues).
![Download del file di log](screenshot_debug_3.png "Download del file di log")

## Note di sviluppo

Expand Down
3 changes: 3 additions & 0 deletions custom_components/pun_sensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry) -> bool:
# Aggiorna immediatamente il prezzo zonale corrente
await coordinator.update_prezzo_zonale()

# Aggiorna immediatamente il prezzo zonale a 15 minuti corrente
await coordinator.update_prezzo_zonale_15min()

# Crea i sensori con la configurazione specificata
await hass.config_entries.async_forward_entry_setups(config, PLATFORMS)

Expand Down
1 change: 1 addition & 0 deletions custom_components/pun_sensor/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
EVENT_UPDATE_FASCIA: str = "event_update_fascia"
EVENT_UPDATE_PUN: str = "event_update_pun"
EVENT_UPDATE_PREZZO_ZONALE: str = "event_update_prezzo_zonale"
EVENT_UPDATE_PREZZO_ZONALE_15MIN: str = "event_update_prezzo_zonale_15min"

# Parametri configurabili da configuration.yaml
CONF_SCAN_HOUR: str = "scan_hour"
Expand Down
26 changes: 24 additions & 2 deletions custom_components/pun_sensor/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
DOMAIN,
EVENT_UPDATE_FASCIA,
EVENT_UPDATE_PREZZO_ZONALE,
EVENT_UPDATE_PREZZO_ZONALE_15MIN,
EVENT_UPDATE_PUN,
WEB_RETRIES_MINUTES,
)
from .interfaces import DEFAULT_ZONA, Fascia, PunData, PunValues, Zona
from .utils import (
add_timedelta_via_utc,
extract_xml,
get_15min_datetime,
get_fascia,
get_hour_datetime,
get_next_date,
Expand Down Expand Up @@ -140,6 +142,9 @@ async def async_restore_default_zona() -> None:
self.prossimo_cambio_fascia: datetime | None = None
self.termine_prossima_fascia: datetime | None = None
self.orario_prezzo: datetime = get_hour_datetime(dt_util.now(time_zone=tz_pun))
self.orario_prezzo_15min: datetime = get_15min_datetime(
dt_util.now(time_zone=tz_pun)
)

_LOGGER.debug(
"Coordinator inizializzato (con 'usa dati reali' = %s).",
Expand Down Expand Up @@ -428,8 +433,25 @@ async def update_prezzo_zonale(self, now=None) -> None:
# Schedula la prossima esecuzione all'ora successiva
# (tenendo conto del cambio ora legale/solare)
next_update_prezzo_zonale: datetime = add_timedelta_via_utc(
dt=dt_util.now(time_zone=tz_pun), hours=1
).replace(minute=0, second=0, microsecond=0)
dt=self.orario_prezzo, hours=1
)
async_track_point_in_time(
self.hass, self.update_prezzo_zonale, next_update_prezzo_zonale
)

async def update_prezzo_zonale_15min(self, now=None) -> None:
"""Aggiorna il prezzo zonale a 15 minuti corrente."""

# Aggiorna il nuovo orario
self.orario_prezzo_15min = get_15min_datetime(dt_util.now(time_zone=tz_pun))

# Notifica che i dati sono stati aggiornati (orario prezzo zonale a 15 minuti)
self.async_set_updated_data({COORD_EVENT: EVENT_UPDATE_PREZZO_ZONALE_15MIN})

# Schedula la prossima esecuzione ai 15 minuti successivi ("spaccati")
next_update_prezzo_zonale_15min: datetime = add_timedelta_via_utc(
dt=self.orario_prezzo_15min, minutes=15
)
async_track_point_in_time(
self.hass, self.update_prezzo_zonale_15min, next_update_prezzo_zonale_15min
)
7 changes: 7 additions & 0 deletions custom_components/pun_sensor/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,17 @@ def __init__(self) -> None:
Fascia.F23: [],
}

# Nome della zona per i prezzi zonali
self.zona: Zona = DEFAULT_ZONA

# Prezzi zonali e PUN orari
self.prezzi_zonali: dict[str, float | None] = {}
self.pun_orari: dict[str, float | None] = {}

# Prezzi zonali e PUN a 15 minuti
self.prezzi_zonali_15min: dict[str, float | None] = {}
self.pun_15min: dict[str, float | None] = {}


class Fascia(Enum):
"""Enumerazione con i tipi di fascia oraria."""
Expand Down
Loading
Loading