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
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.
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!
Salve,
RispondiEliminaMi 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
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.
EliminaHo capito quello che dici ma non saprei come farlo... Potresti dare qualche indicazione in più per cortesia?
EliminaGrazie
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.
Eliminausing (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;
Ti ringrazio tantissimo!
Elimina