Creare un sensore del prezzo del gas (PSBIL_BUY) in Home Assistant



In questa guida cerco di spiegare passo-passo (diciamo per principianti) come recuperare le informazioni relative a prezzo del gas (nel caso specifico il valore PSBIL_BUY) reperibili sul sito del GME (GME - Gestore dei Mercati Energetici SpA (mercatoelettrico.org)), che normalmente non sono reperibili automaticamente.
Questi dati sono disponibili e "facilmente" consultabili per una persona, ma diventa difficile farlo automaticamente per via delle conferme e dei flag che è necessario "spuntare" per poter acedere alla pagina dei dati.
Come sempre cercherò di scrivere un articolo come piace a me: inserirò le informazioni necessarie senza dilungarmi troppo, senza continue ripetizioni (in stile SEO) e andando al punto, ma inserendo le informazioni che è necessario sapere (per capire cosa si sta facendo).

Come prima cosa, naturalmente, dovete avere un’installazione di Home Assistant funzionante e correttamente configurata.

1. Configurazione tipo (HW/SW)

Nel mio caso mi trovo nella seguente situazione (cioè, se avete la mia stessa configurazione e seguite la guida, vi garantisco che funziona):

  • Raspberry Pi 4 – 8 GB
  • Home Assistant 2022.12.8
    • Supervisor 2022.11.2
    • Operating System 9.4

2. Prerequisiti

 Come già detto dovete avere:

  • Installazione di Home Assistant (qualunque tipologia) funzionante

3. Breve introduzione/spiegazione

Faccio una piccola premessa per spiegare che dato andiamo a prendere e cosa significa. Se non avete una bolletta a prezzo dell'energia fisso (purtroppo ad oggi penso che nessuno abbia più possibilità di avere un contratto del genere), il prezzo della materia prima risulta variabile, e calcolato secondo 2 "indici" o "criteri":
  • PSV - che significa "Punto di Scambio Virtuale" e si basa fondamentalmente su vendite e acquisti fatti tra la rete nazionale e l'estero
  • PSBIL - che corrisponde alla media aritmetica (a livello mensile) dei prezzi di sbilanciamento di acquisto
A seconda del vostro gestore, potrebbe essere applicato un indice piuttosto che l'altro. nel mio caso il mio gestore usa il PSBIL, per cui sono andato a recuperare questo dato specifico.
Ora, il calcolo di questo valore è piuttosto complicato, e soprattutto si appoggia a dati che non sono reperibili se non dal GME. Inoltre il costo mensile si può sapere solo una volta che il mese è concluso (media aritmetica dei valori giornalieri), e per ogni giorno non basta prendere il prezzo medio ponderato, ma (se c'è) bisogna prendere il prezzo massimo di acquisto SRG.
Capite quindi che è un problema insormontabile.
Abbiamo perciò 2 possibilità:
  • Prendere il PSBIL_buy del mese precedente (facilmente fattibile con un sensore scrape), che però ha un grosso vantaggio in caso di prezzi molto aleatori come in questo periodo: sarà molto poco preciso.
  • Prendere il valore giornaliero, contando sul fatto che il nostro consumo giornaliero sia in qualche modo simile tra un giorno e l'altro, e quindi a fine mese avremmo una valorizzazione simile a quella della bolletta.
Un metodo migliore sarebbe quello di aggiornare una media mensile, andando a cambiare i dati della plancia Energia, ma non credo sia fattibile ad ora.
Per cui ho deciso di adottare il secondo metodo, cioè di prendere il dato giornaliero e confidare nella maggiore accuratezza teorica.

4. Reperire i dati

Per sapere che dati prendere, c'è da girare un po' sul sito del GME e impazzire cercando di capire quali siano i valori da utilizzare. Dopo molti scervellamenti e calcoli sono riuscito a trovare questa pagina, che fa al caso nostro: GME - Esiti dei mercati - - Dati funzionali alla      determinazione del prezzo     di sbilanciamento (mercatoelettrico.org)


Qui sorge un altro problema: da HA direttamente non si riesce ad arrivare a recuperare questi dati. Vediamo come ho "risolto" la cosa.

5. Il Proxy

Per ovviare al problema ho prima di tutto verificato (grazie a Postman) che fosse possibile simulare la navigazione tramite browser sul sito del GME. Infatti in caso contrario non sarebbe stato possibile farlo in alcun modo.
Un volta appurata la fattibilità della cosa, si trattava di scegliere una strada:
  • fare un'integrazione di HA che recupera i dati
  • creare una sorta di "proxy" che prenda i dati dal sito del GME e li "converta" in JSON, per usarli con un sensore REST
La prima strada (nel mio caso specifico) presentava qualche "contro": non conosco python, me lo sarei dovuto studiare (e non ne ho il tempo); non ho mai creato un'integrazione di HA, quindi mi sarei dovuto studiare come realizzarne una; il debug è rognoso.

La seconda strada, d'altronde, per me ha diversi punti a favore: possedevo già uno spazio in hosting con DB, supporto ASP.NET/Classic e PHP; ne ho già fatti e so come realizzarli (conosco diversi metodi per farlo); il debug è molto comodo.

Tutto ciò per dire che la decisione è stata quasi obbligata, ed ho realizzato un sistema che giornalmente recupera le informazioni dal GME, le salva in un database e le rende fruibili in JSON tramite un URL: https://www.andreafumi.it/Utilities/GMEDataParser.ashx?type=gas

Vediamo ora come inserire il sensore in HA.

6. Aggiungere i sensori in HA

Come già detto altre volte, do per scontato che abbiate un editor testuale installato e configurato in HA (File editor o Filebrowser) e che quindi li sappiate usare. Se avete anche abilitato la cartella Packages, vi consiglio di creare un file .yaml dedicato ai sensori dei costi dell'energia (per pulizia e ordine io preferisco fare così).
Andiamo quindi ad aggiungere al file configuration.yaml (o ad un altro file *.yaml nella cartella Packages) il seguente codice:
rest:
  - resource: https://www.andreafumi.it/Utilities/GMEDataParser.ashx?type=gas
    scan_interval: 3600
    headers:
      Content-Type: application/json
    sensor:
      - name: PSBIL_BUY Gas Yesterday
        unit_of_measurement: €
        value_template: "{{ value_json.PrezzoGiornalieroM3 }}"
che si occuperà di richiedere (con frequenza oraria) il costo aggiornato dell'energia (riferito al giorno precedente).

Andiamo quindi in "Strumenti per sviluppatori"


Clicchiamo su "VERIFICA CONFIGURAZIONE" (per accertarci di aver indentato tutto correttamente

Quindi clicchiamo su "ENTITA' REST E SERVIZI DI NOTIFICA REST" per far caricare il nostro nuovo sensore.


A questo punto spostiamoci sul tab "STATI"


Filtriamo per il nome del nostro sensore e verifichiamo che sia stato caricato correttamente

Ora, questo valore è già corretto, ma non è quello che vedremo in bolletta. Infatti oltre a questo costo puro, ci sono i ricarichi applicati dal gestore, le spese di trasporto, le accise, le tasse, ecc.
Perciò normalmente creo un altro sensore che va ad applicare i ricarichi al costo dell'energia, in modo da avere un costo stimato della bolletta il più realistico possibile.

Aggiungiamo al file configuration.yaml (o ad un altro file *.yaml nella cartella Packages) il seguente codice:
sensor:    
  - platform: template
    sensors:
      psbil_buy_actual_daily:
        friendly_name: "PSBIL_BUY actual daily"
        unit_of_measurement: EUR/m³
        value_template:  >
            {{ (float(states('sensor.psbil_buy_gas_yesterday')) * 1.02688993 + 0.045 + 0.055133 + 0.16047282 + 0.17 + 0.0309874) * 1.05 }}
ATTENZIONE! questi sono i dati del mio contratto, nel vostro caso potrebbero essere diversi. Controllate sull'ultima bolletta i vostri costi.

Torniamo su "Strumenti per sviluppatori"

Verifichiamo di nuovo la correttezza della configurazione


Infine su "ENTITA' MODELLO" per caricare il nuovo sensore.
Poi andiamo sul tab "STATI"

e controlliamo che il sensore sia valorizzato correttamente

FINE!
Adesso possiamo usare "sensor.psbil_buy_actual_daily" come entità di costo del gas nella plancia Energia!

Commenti

  1. Salve,
    Mi piacerebbe sapere come ha fatto a bypassare la schermata delle "CONDIZIONI GENERALI DI UTILIZZO DEL SITO INTERNET". Non sono molto abile con Postman ma facendo una banale query mi appare il codice HTML di quella schermata e non so come saltarla.
    Grazie

    RispondiElimina
    Risposte
    1. Mi spiace ma non mi arrivano le notifiche dei commenti (c'è lo zampino di Google come sempre). Non puoi bypassare quella schermata, quello che occorre fare è una "doppia chiamata", la prima si vedrà restituire quella pagina di "Condizioni generali", la seconda simulerà il click sul bottone di accettazione delle condizioni. In pratica fa finta che sia l'utente ad aver cliccato e quindi viene restituita la pagina finale con i dati desiderati.

      Elimina
    2. Ho capito quello che dici ma non saprei come farlo... Potresti dare qualche indicazione in più per cortesia?
      Grazie

      Elimina
    3. Questo è il codice che uso io per la doppia chiamata (è in c#, ma dovrebbe essere facilmente comprensibile). Da qui vedi tutti i parametri che uso per fare la prima chiamata e quelli che prendo per poter poi fare la seconda.



      using (WebClient client = new WebClient())
      {
      //Aggiungo gli header necessari
      client.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8");
      client.Headers.Add("Accept-Language", "it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3");
      client.Headers.Add("Host", "www.mercatoelettrico.org");
      client.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0");
      client.QueryString.Add("ReturnUrl", "/It/Esiti/MGS/EsitiPrezzoSbilanciamento.aspx");
      //Faccio la chiamata (richiedo la pagina dei consensi)
      html = client.DownloadString("https://www.mercatoelettrico.org/It/Tools/Accessodati.aspx");

      //Prendo l'header di risposta "Set-Cookie" (parte del valore mi serve per la prossima chiamata)
      sessionId = client.ResponseHeaders["Set-Cookie"];
      sessionId = sessionId.Substring(0, sessionId.IndexOf(';'));

      //Vado a prendermi i parametri necessari nel contenuto della pagina (sono nel value di questi campi)
      //Ignoro tutti i parametri NON necessari (ho visto che bastano questi per funzionare)
      int idxVSStart = html.IndexOf("id=\"__VIEWSTATE\" value=\"");
      idxVSStart = idxVSStart + "id=\"__VIEWSTATE\" value=\"".Length;
      viewstate = html.Substring(idxVSStart, html.IndexOf("\"", idxVSStart) - idxVSStart);

      idxVSStart = html.IndexOf("id=\"__VIEWSTATEGENERATOR\" value=\"");
      idxVSStart = idxVSStart + "id=\"__VIEWSTATEGENERATOR\" value=\"".Length;
      viewstateGenerator = html.Substring(idxVSStart, html.IndexOf("\"", idxVSStart) - idxVSStart);

      idxVSStart = html.IndexOf("id=\"__PREVIOUSPAGE\" value=\"");
      idxVSStart = idxVSStart + "id=\"__PREVIOUSPAGE\" value=\"".Length;
      previousPage = html.Substring(idxVSStart, html.IndexOf("\"", idxVSStart) - idxVSStart);

      idxVSStart = html.IndexOf("id=\"__EVENTVALIDATION\" value=\"");
      idxVSStart = idxVSStart + "id=\"__EVENTVALIDATION\" value=\"".Length;
      eventValidation = html.Substring(idxVSStart, html.IndexOf("\"", idxVSStart) - idxVSStart);
      }

      //Compongo l'url della prossima chiamata
      string url = "https://www.mercatoelettrico.org/It/Tools/Accessodati.aspx?ReturnUrl=%2fIt%2fWebServerDataStore%2fMGP_Prezzi%2f"
      + refDate.ToString("yyyyMMdd", CultureInfo.InvariantCulture) + "MGPPrezzi.xml";

      //Qui devo usare un altro metodo, perchè con il WebClient non funziona (ho problemi con il keepalive). Ho creato un'altra classe apposta che fa questo
      html2 = GMEWebClientGlobal.getXML(url, viewstate, viewstateGenerator, previousPage, eventValidation, sessionId).Result;

      Elimina

Posta un commento

Post popolari in questo blog

Creare un sensore weather (previsioni del tempo) da Meteo & Radar in Home Assistant

Home Assistant - Recuperare informazioni aggiuntive da Netatmo (termostato)

Installare Frigate su Raspberry Pi con HAssOS

Installare Portainer su NAS Synology

Esporre UPS da NAS Synology verso Home Assistant (NUT)

Ricevere la posizione GPS quando si parcheggia l'automobile (con Home Assistant)

Creare MQTT Server (broker) in Home Assistant (HASSIO)

Tasmota (via OTA) su BlitzWolf BW-SHP10 (e su Tuya ESP in generale)

JC vs Khaby Lame