virtualdj / pun_sensor

Prezzi PUN del mese - Home Assistant Integration
MIT License
78 stars 13 forks source link

Nuova API sito GME #42

Open moddroid94 opened 2 months ago

moddroid94 commented 2 months ago

Ciao, ho notato che e' online il nuovo sito di GME. Il nuovo sito utilizza un endpoint API per scaricare il file zip, e ho pensato che si potesse semplificare la parte di download dal sito in quanto particolarmente convoluta.

Dopo un po' di tinkering sono riuscito a emulare una request che ci consente di scaricare lo zip senza fare scraping di valori sul sito con BeautifulSoup.

L'endpoint sembra essere di libero accesso, ovvero l'unico parametro che sembra essere importante per la request e' il referrer, che dev'essere la pagina di download del sito GME dov'e' situato il pulsante.

La request con la quale sono riuscito a scaricare lo zip e' la seguente: Su Powershell

Invoke-WebRequest -UseBasicParsing -Uri "https://gme.mercatoelettrico.org/DesktopModules/GmeDownload/API/ExcelDownload/downloadzipfile?DataInizio=20240507&DataFine=20240507&Date=20240506&Mercato=MGP&Settore=Prezzi&FiltroDate=InizioFine" `
-WebSession $session `
-Headers @{
"authority"="gme.mercatoelettrico.org"
  "method"="GET"
  "path"="/DesktopModules/GmeDownload/API/ExcelDownload/downloadzipfile?DataInizio=20240507&DataFine=20240507&Date=20240506&Mercato=MGP&Settore=Prezzi&FiltroDate=InizioFine"
  "scheme"="https"
  "accept"="application/json, text/plain, */*"
  "accept-encoding"="gzip, deflate, br, zstd"
  "accept-language"="en-US,en;q=0.9"
  "cache-control"="no-cache"
  "dnt"="1"
  "moduleid"="12103"
  "pragma"="no-cache"
  "priority"="u=1, i"
  "referer"="https://gme.mercatoelettrico.org/en-us/Home/Results/Electricity/MGP/Download?valore=Prezzi"
  "sec-ch-ua"="`"Not-A.Brand`";v=`"99`", `"Chromium`";v=`"124`""
  "sec-ch-ua-mobile"="?0"
  "sec-ch-ua-platform"="`"Windows`""
  "sec-fetch-dest"="empty"
  "sec-fetch-mode"="cors"
  "sec-fetch-site"="same-origin"
  "tabid"="1749"
  "userid"="-1"
} 

Quando la richiesta viene effettuata dal browser, vi e' un campo aggiuntivo: requestverificationtoken. Ma anche omettendo il token l'API sembra funzionare da terminale o codice.

Con python basta impostare gli headers di una request con i seguenti valori e puntare all'url con i parametri giusti.

Endpoint: "https://gme.mercatoelettrico.org/DesktopModules/GmeDownload/API/ExcelDownload/downloadzipfile?DataInizio=20240507&DataFine=20240507&Date=20240506&Mercato=MGP&Settore=Prezzi&FiltroDate=InizioFine"

headers:

{
    "accept": "application/json, text/plain, */*",
    "accept-language": "en-US,en;q=0.9",
    "cache-control": "no-cache",
    "moduleid": "12103",
    "pragma": "no-cache",
    "priority": "u=1, i",
    "referrer": "https://gme.mercatoelettrico.org/en-us/Home/Results/Electricity/MGP/Download?valore=Prezzi",
    "sec-ch-ua": '"Not-A.Brand";v="99", "Chromium";v="124"',
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": '"Windows"',
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-origin",
    "tabid": "1749",
    "userid": "-1",
}

Non so se e' un problema di auth da parte loro o se e' inteso per essere pubblico, ad ogni modo anche dovessimo recuperare il token dai cookie/response dovrebbe essere decisamente piu' comodo.

PS. Ho forkato la repo e sto facendo un po' di clean up / spostamento di classi nei rispettivi moduli cosi' da seguire meglio le linee guida per le integrazioni di HA e rendere il codice un po' piu' leggibile, e possibilmente rendere piu' semplice l'adattamento ad un cambiamento come quello descritto qua #38

Se vuoi intanto dare un occhiata puoi trovarla tra le mie repo, non appena avro' testato le modifiche faccio una draft per una PR cosi da poter vedere insieme i cambiamenti.

virtualdj commented 2 months ago

Ciao, ho notato che e' online il nuovo sito di GME.

Ciao, non l'avevo notato... certo che sono riusciti a fare uno pure peggio del precedente....

Il nuovo sito utilizza un endpoint API per scaricare il file zip, e ho pensato che si potesse semplificare la parte di download dal sito in quanto particolarmente convoluta.

Almeno questo sì è migliorato.

Dopo un po' di tinkering sono riuscito a emulare una request che ci consente di scaricare lo zip senza fare scraping di valori sul sito con BeautifulSoup.

Molto bene, di là (sul vecchio) non c'ero riuscito.

Quando la richiesta viene effettuata dal browser, vi e' un campo aggiuntivo: requestverificationtoken. Ma anche omettendo il token l'API sembra funzionare da terminale o codice.

Da browser c'ho messo un bel po' a ritrovare il link (QUESTO) da dove scaricare lo ZIP. Per fortuna non hanno cambiato il formato interno.

PS. Ho forkato la repo e sto facendo un po' di clean up / spostamento di classi nei rispettivi moduli cosi' da seguire meglio le linee guida per le integrazioni di HA e rendere il codice un po' piu' leggibile,

Ho visto, purtroppo io non sono del mestiere 😉 ma più un hobbista, quindi mi sono arrangiato un po' con Google per risolvere il problema (no IA).

I match case ad esempio li avevo evitati perché mi sembravano meno leggibili... 😮 però effettivamente mi pare che la tua versione vada molto bene. Il chaining degli operatori ((a and b) > 0) invece ignoravo proprio esistesse!

Vabbè, sono qui per imparare!

e possibilmente rendere piu' semplice l'adattamento ad un cambiamento come quello descritto qua #38

Intendi il discorso che facevo sotto del calcolo del totale della bolletta (sperando che nel frattempo non ci cambino il PUN)?

non appena avro' testato le modifiche faccio una draft per una PR cosi da poter vedere insieme i cambiamenti.

Certamente, grazie!

moddroid94 commented 2 months ago

Ciao @virtualdj ,

Per quanto riguarda le API si avevo provato anche io con la tua repo in locale ma era troppo complicato usare bs4, per quanto hobbista hai escogitato un metodo non banale per emulare quel download! 👌

Ad ogni modo si i match li ho usati con parsimonia perche' comunque prediligo la leggibilita' del codice alla pura performance, ma dove si puo 😁

Per il futuro intendevo sia l'integrazione della bolletta, che ho "simulato" anche io con helper & Co. e vorrei aiutare a integrare, e sia per quanto riguarda la questione delle zonali, che sul sito nuovo sembra oltretutto essere gia' disponibile, anche se non ho capito assolutamente nulla di come funzioni 😂

Comunque ho testato il fork e sembra funzionare, magari proviamo a farlo girare un paio di giorni, magari anche su qualche altra istanza giusto per sicurezza, ho fatto altre due modifiche che ora committo e per ora lo sto facendo girare su docker e ha recuperato zip e settato tutto correttamente.

virtualdj commented 2 months ago

Comunque giusto per provare ho buttato su sulla seconda istanza Docker il tuo fork e c'è qualcosa che non va sul calcolo delle fasce.

Dal log vedo questo:

2024-05-07 23:28:22.988 WARNING (SyncWorker_3) [homeassistant.loader] We found a custom integration pun_sensor which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you experience issues with Home Assistant
2024-05-07 23:28:30.576 DEBUG (MainThread) [custom_components.pun_sensor.coordinator] Coordinator inizializzato (con 'usa dati reali' = False).
2024-05-07 23:28:30.577 DEBUG (MainThread) [custom_components.pun_sensor.coordinator] Ora corrente sistema: Tue 07/05/2024 23:28:30 +0200
2024-05-07 23:28:30.577 DEBUG (MainThread) [custom_components.pun_sensor.coordinator] Ora corrente fuso orario italiano: Tue 07/05/2024 23:28:30 +0200
2024-05-07 23:28:30.579 INFO (MainThread) [custom_components.pun_sensor.coordinator] Nuova fascia corrente: F1 (prossima: Tue 07/05/2024 19:00:00 +0200)
2024-05-07 23:28:30.579 DEBUG (MainThread) [custom_components.pun_sensor.coordinator] Manually updated pun_sensor data
2024-05-07 23:28:30.579 DEBUG (MainThread) [custom_components.pun_sensor.coordinator] Ora corrente sistema: Tue 07/05/2024 23:28:30 +0200
2024-05-07 23:28:30.580 DEBUG (MainThread) [custom_components.pun_sensor.coordinator] Ora corrente fuso orario italiano: Tue 07/05/2024 23:28:30 +0200
2024-05-07 23:28:30.581 INFO (MainThread) [custom_components.pun_sensor.coordinator] Nuova fascia corrente: F1 (prossima: Tue 07/05/2024 19:00:00 +0200)
2024-05-07 23:28:30.581 DEBUG (MainThread) [custom_components.pun_sensor.coordinator] Manually updated pun_sensor data
2024-05-07 23:28:30.582 DEBUG (MainThread) [custom_components.pun_sensor.coordinator] Ora corrente sistema: Tue 07/05/2024 23:28:30 +0200
2024-05-07 23:28:30.582 DEBUG (MainThread) [custom_components.pun_sensor.coordinator] Ora corrente fuso orario italiano: Tue 07/05/2024 23:28:30 +0200
2024-05-07 23:28:30.583 INFO (MainThread) [custom_components.pun_sensor.coordinator] Nuova fascia corrente: F1 (prossima: Tue 07/05/2024 19:00:00 +0200)
...

Come vedi sbaglia a calcolare la prossima fascia (la mette nel passato) e questo causa un loop continuo che blocca tutto. Ora però non riesco a fare il debug, sono troppo stanco dalla giornata 😪

moddroid94 commented 2 months ago

Si avevo notato 😂

Mi era fatto prendere la mano con quei comparison e ne ho messo uno che non poteva ritornare vero nemmeno se pregavo 🤣

In teoria ho fixato tutto, quando poi hai tempo puoi provare ad aggiornarlo da hacs :)

g1za commented 2 months ago

Scusate se mi intrometto ma vorrei seguire la discussione perché avendomi fatto scoprire che il sito è cambiato ho paura che prima o poi dovrò rimettere mano al codice per scaricare i prezzi zonali, che avevo realizzato con il componente multiscrape, e in questa discussione vedo la possibilità di trarre spunti utili.

Se posso dare il mio piccolo contributo (ne so mooooolto meno di voi), se utile e non indiscreto, credo che l'endpoint per accedere ai prezzi zonali in XML sia il seguente https://gme.mercatoelettrico.org/DesktopModules/GmeEsitiPrezziME/API/item/GetMEPrezzi?DataInizio=20240509&DataFine=20240509&Granularita=h&Mercato=MGP&Zona=NORD&Tipologia=PrezziZonali

Ovviamente usato così nudo e crudo non funziona, restituisce un errore, ma non se se è una problematica di referrer come menzionato sopra, o di cookie (tramite l'accettazione delle condizioni di uso nella videata che ora è un pop-up).

Pagina web con i prezzi zonali: https://gme.mercatoelettrico.org/it-it/Home/Esiti/Elettricita/MGP/Esiti/PrezziZonali#IntestazioneGrafico

virtualdj commented 2 months ago

Se posso dare il mio piccolo contributo (ne so mooooolto meno di voi), se utile e non indiscreto, credo che l'endpoint per accedere ai prezzi zonali in XML sia il seguente https://gme.mercatoelettrico.org/DesktopModules/GmeEsitiPrezziME/API/item/GetMEPrezzi?DataInizio=20240509&DataFine=20240509&Granularita=h&Mercato=MGP&Zona=NORD&Tipologia=PrezziZonali

Domanda, visto che non me ne intendo invece di prezzi zonali... ma questi non sono dentro nel file XML che scarica già l'integrazione come ZIP (uno XML per ogni giorno)?

Ogni ora dell'XML ha questi dati:

  <Prezzi>
    <Data>20240509</Data>
    <Mercato>MGP</Mercato>
    <Ora>1</Ora>
    <PUN>94,320000</PUN>
    <NAT>94,320000</NAT>
    <CALA>94,320000</CALA>
    <CNOR>94,320000</CNOR>
    <CSUD>94,320000</CSUD>
    <NORD>94,320000</NORD>
    <SARD>94,320000</SARD>
    <SICI>94,320000</SICI>
    <SUD>94,320000</SUD>
    <AUST>94,320000</AUST>
    <COAC>94,320000</COAC>
    <COUP>94,320000</COUP>
    <CORS>94,320000</CORS>
    <FRAN>94,320000</FRAN>
    <GREC>94,320000</GREC>
    <SLOV>94,320000</SLOV>
    <SVIZ>94,320000</SVIZ>
    <BSP>94,320000</BSP>
    <MALT>94,320000</MALT>
    <XAUS>94,320000</XAUS>
    <XFRA>94,320000</XFRA>
    <MONT>94,320000</MONT>
    <XGRE>94,320000</XGRE>
  </Prezzi>

E noi di questi prendiamo solo il <PUN>94,320000</PUN>. A te quali servono? Immagino siano già qui...

moddroid94 commented 1 month ago

Se posso dare il mio piccolo contributo (ne so mooooolto meno di voi), se utile e non indiscreto, credo che l'endpoint per accedere ai prezzi zonali in XML sia il seguente https://gme.mercatoelettrico.org/DesktopModules/GmeEsitiPrezziME/API/item/GetMEPrezzi?DataInizio=20240509&DataFine=20240509&Granularita=h&Mercato=MGP&Zona=NORD&Tipologia=PrezziZonali

Ovviamente usato così nudo e crudo non funziona, restituisce un errore, ma non se se è una problematica di referrer come menzionato sopra, o di cookie (tramite l'accettazione delle condizioni di uso nella videata che ora è un pop-up).

Ho testato la API e non funziona nemmeno con il referrer, pero' penso che potrebbe essere un API interna del sito, quell'item mi sembra una route di react. dove l'hai trovata? 😂

In compenso il pulsante che scarica l'excel con i dati sembra essere un endpoint pubblico, regolando la granularita' penso che si possano ottenere dati di un mese o piu', per l'estrazione dei dati probabilmente un excel e' anche meglio di un XML👌 https://gme.mercatoelettrico.org/DesktopModules/GmeEsitiPrezziME/API/ExcelDownload/download?DataInizio=20240509&DataFine=20240509&Granularita=h&Mercato=MGP&Zona=Nord&Tipologia=PrezziZonali

g1za commented 1 month ago

Domanda, visto che non me ne intendo invece di prezzi zonali... ma questi non sono dentro nel file XML che scarica già l'integrazione come ZIP (uno XML per ogni giorno)?

Ogni ora dell'XML ha questi dati:

  <Prezzi>
    <Data>20240509</Data>
    <Mercato>MGP</Mercato>
    <Ora>1</Ora>
    <PUN>94,320000</PUN>
    <NAT>94,320000</NAT>
    <CALA>94,320000</CALA>
    <CNOR>94,320000</CNOR>
    <CSUD>94,320000</CSUD>
    <NORD>94,320000</NORD>
    <SARD>94,320000</SARD>
    <SICI>94,320000</SICI>
    <SUD>94,320000</SUD>
    <AUST>94,320000</AUST>
    <COAC>94,320000</COAC>
    <COUP>94,320000</COUP>
    <CORS>94,320000</CORS>
    <FRAN>94,320000</FRAN>
    <GREC>94,320000</GREC>
    <SLOV>94,320000</SLOV>
    <SVIZ>94,320000</SVIZ>
    <BSP>94,320000</BSP>
    <MALT>94,320000</MALT>
    <XAUS>94,320000</XAUS>
    <XFRA>94,320000</XFRA>
    <MONT>94,320000</MONT>
    <XGRE>94,320000</XGRE>
  </Prezzi>

E noi di questi prendiamo solo il <PUN>94,320000</PUN>. A te quali servono? Immagino siano già qui...

Sono loro, allora il file zippato contiene già tutto. Io utilizzo i prezzi zonali NORD, ma possono variare a seconda della zona geografica in cui ti trovi. Per vostra informazione i dati zonali di un giorno vengono resi disponibili nel primo pomeriggio del giorno precedente, generalmente entro le 14-15. (per necessità mie io mi scarico sia quelli di oggi che quelli di domani - fintanto che quelli di domani mancano li sostituisco con quelli di oggi)

g1za commented 1 month ago

Ho testato la API e non funziona nemmeno con il referrer, pero' penso che potrebbe essere un API interna del sito, quell'item mi sembra una route di react. dove l'hai trovata? 😂

Con Firefox, analizzando la pagina, con l'inspector, nella sezione "rete" mostra le chiamate che vengono effettuate. Selezionando poi questa chiamata GET specifica mostra pure l'header della chiamata e risposta. Magari copiando i paramentri dal browser riesci a replicarla con Powershell e capire se è un endpoint pubblico o meno.

In compenso il pulsante che scarica l'excel con i dati sembra essere un endpoint pubblico, regolando la granularita' penso che si possano ottenere dati di un mese o piu', per l'estrazione dei dati probabilmente un excel e' anche meglio di un XML👌 https://gme.mercatoelettrico.org/DesktopModules/GmeEsitiPrezziME/API/ExcelDownload/download?DataInizio=20240509&DataFine=20240509&Granularita=h&Mercato=MGP&Zona=Nord&Tipologia=PrezziZonali

Ho sempre cercato di non dover scaricare file in locale, ma probabilmente l'approccio è diverso/la necessità è differente quando si sviluppa un component per homeassistant.

Mannaggia a loro che nel vecchio sito hanno il pulsante per ottenere l'XML direttamente e qui invece è stato tolto :|

moddroid94 commented 1 month ago

Ho testato la API e non funziona nemmeno con il referrer, pero' penso che potrebbe essere un API interna del sito, quell'item mi sembra una route di react. dove l'hai trovata? 😂

Con Firefox, analizzando la pagina, con l'inspector, nella sezione "rete" mostra le chiamate che vengono effettuate. Selezionando poi questa chiamata GET specifica mostra pure l'header della chiamata e risposta. Magari copiando i paramentri dal browser riesci a replicarla con Powershell e capire se è un endpoint pubblico o meno.

In compenso il pulsante che scarica l'excel con i dati sembra essere un endpoint pubblico, regolando la granularita' penso che si possano ottenere dati di un mese o piu', per l'estrazione dei dati probabilmente un excel e' anche meglio di un XML👌 https://gme.mercatoelettrico.org/DesktopModules/GmeEsitiPrezziME/API/ExcelDownload/download?DataInizio=20240509&DataFine=20240509&Granularita=h&Mercato=MGP&Zona=Nord&Tipologia=PrezziZonali

Ho sempre cercato di non dover scaricare file in locale, ma probabilmente l'approccio è diverso/la necessità è differente quando si sviluppa un component per homeassistant.

Mannaggia a loro che nel vecchio sito hanno il pulsante per ottenere l'XML direttamente e qui invece è stato tolto :|

sisi ma ho provato da powershell con referrer e mi restituisce errore di auth, per quello penso sia interna, sicuramente non e' pubblica 😂 In ogni caso se nel file attuale abbiamo gia' i valori non penso che questa serva

l'excel in realta' si potrebbe caricare in memoria direttamente quindi non sarebbe comunque un problema :)

virtualdj commented 1 month ago

l'excel in realta' si potrebbe caricare in memoria direttamente quindi non sarebbe comunque un problema :)

Ma è già così, in memoria, mica fa un file... https://github.com/virtualdj/pun_sensor/blob/master/custom_components%2Fpun_sensor%2F__init__.py#L209-L211

moddroid94 commented 1 month ago

l'excel in realta' si potrebbe caricare in memoria direttamente quindi non sarebbe comunque un problema :)

Ma è già così, in memoria, mica fa un file... https://github.com/virtualdj/pun_sensor/blob/master/custom_components%2Fpun_sensor%2F__init__.py#L209-L211

sisi lo so, era in risposta al commento di @g1za 😂

Ho sempre cercato di non dover scaricare file in locale, ma probabilmente l'approccio è diverso/la necessità è differente quando si sviluppa un component per homeassistant.

virtualdj commented 1 month ago

@moddroid94 Ah ok, il potrebbe mi ha tratto in inganno...