Skip to content

Instantly share code, notes, and snippets.

@frazei
Last active June 6, 2025 14:09
Show Gist options
  • Save frazei/0eaac760d20b2278bb0d074a39884d82 to your computer and use it in GitHub Desktop.
Save frazei/0eaac760d20b2278bb0d074a39884d82 to your computer and use it in GitHub Desktop.
ARPAE Air Quality in Home Assistant

Integrare i dati di ARPAE in Home Assistant tramite REST API

L'Agenzia regionale per la prevenzione, l'ambiente e l'energia dell´Emilia-Romagna (Arpae) espone tramite API malamente documentate tutta una serie di dati riguardanti le rilevazioni che vengono fatte in regione da varie centraline sparse sul territorio.

Qui scrivo tutti i modi che ho individuato per importare i dati dentro a Home Assistant sotto forma di sensori che possono poi essere utilizzati per visualizzare grafici e affini sulla dashboard.

L'end point a cui inviare le richieste è sempre https://apps.arpae.it/REST ma espone diversi tipi di estrazioni che non sono tutte documentate, o almeno io non ho trovato un gran che. La cosa migliore è copiare da alcune pagine di Arpae le chiamate e poi andare a sentimento...

Riferimenti utili

Configurazione di Home Assistant

Tutte le configurazioni sotto riportate vanno fatte in /homeassistant/configuration.yaml.

qa_stazioni

Questo sensore raccoglie i dati di PM10, PM2.5, NO2 (diossido di azoto) e O3 (ozono) dalla centralina identificata dall'id "4000022" che si trova a Modena nel Parco Ferrari. La rilevazione viene aggiornata una volta al giorno e pubblicata il giorno successivo quindi uso la funzione now() - timedelta(days = 1)).strftime('%Y%m%d') per ottenere la stringa relativa al giorno precedente all'esecuzione della chiamata. La centralina esporebbe anche altri dati relativi al superamento delle soglie consentite.

rest:
  - resource: "https://apps.arpae.it/REST/qa_stazioni?projection=%7B%22foto%22%3A0%7D&where=%7B%22_id%22%3A%7B%22%24eq%22%3A%224000022%22%7D%7D"
    sensor:
      - name: "ARPAE pm10"
        value_template: "{{ value_json['_items'][0]['dati'][(now() - timedelta(days = 1)).strftime('%Y%m%d')].pm10 }}"
        unit_of_measurement: "µg/m³"
        state_class: measurement
        device_class: pm10
      - name: "ARPAE pm2.5"
        value_template: "{{ value_json['_items'][0]['dati'][(now() - timedelta(days = 1)).strftime('%Y%m%d')].pm25 }}"
        unit_of_measurement: "µg/m³"
        state_class: measurement
        device_class: pm25
      - name: "ARPAE no2"
        value_template: "{{ value_json['_items'][0]['dati'][(now() - timedelta(days = 1)).strftime('%Y%m%d')].no2 }}"
        unit_of_measurement: "µg/m³"
        state_class: measurement
        device_class: nitrous_oxide

Una cosa importante riguarda il fatto che la URL deve essere scritta tra doppie virgolette e che tutti i parametri vanno encodati. In pratica la query che eseguo è ?projection={"foto":0}&where={"_id":{"$eq":"4000022"}}.

Con questi dati ho potuto creare ad esempio questo grafico

chart_type: bar
period: day
type: statistics-graph
entities:
  - sensor.pm10
  - sensor.no2
stat_types:
  - mean
days_to_show: 7
hide_legend: true
title: Livello PM e NO2 ultimi 7 giorni

Un altro modo di importare questa API è quello di filtrare per comune ({"comune":{"$eq":"MODENA"}}) e poi prendere dentro tutte le centraline. Dato che HA non supporta il foreach dentro alla configurazione delle sonde, non ho trovato di meglio che scrivere un blocco di configurazione per ogni centralina (per Modena sono 6).

Quindi il blocco qui sotto andrebbe ripetuto N volte spostandosi nell'array value_json['items']:

- resource: "https://apps.arpae.it/REST/qa_stazioni?projection=%7B%22foto%22%3A0%7D&where=%7B%22comune%22%3A%7B%22%24eq%22%3A%22MODENA%22%7D%7D"
    sensor:
      - name: "ARPAE 0 nome"
        value_template: "{{ value_json['_items'][0].nome }}"
        unique_id: "qa_stazioni0.nome"
      - name: "ARPAE 0 pm10"
        value_template: "{{ value_json['_items'][0]['dati'][(now() - timedelta(days = 1)).strftime('%Y%m%d')].pm10 }}"
        unique_id: "qa_stazioni0.pm10"
        unit_of_measurement: "µg/m³"
        state_class: measurement
        device_class: pm10
      - name: "ARPAE 0 pm2.5"
        value_template: "{{ value_json['_items'][0]['dati'][(now() - timedelta(days = 1)).strftime('%Y%m%d')].pm25 }}"
        unique_id: "qa_stazioni0.pm25"
        unit_of_measurement: "µg/m³"
        state_class: measurement
        device_class: pm25
      - name: "ARPAE 0 no2"
        value_template: "{{ value_json['_items'][0]['dati'][(now() - timedelta(days = 1)).strftime('%Y%m%d')].no2 }}"
        unique_id: "qa_stazioni0.no2"
        unit_of_measurement: "µg/m³"
        state_class: measurement
        device_class: nitrous_oxide
      - name: "ARPAE 1 nome"
        value_template: "{{ value_json['_items'][1].nome }}"
        unique_id: "qa_stazioni1.nome"
      - name: "ARPAE 1 pm10"
        value_template: "{{ value_json['_items'][1]['dati'][(now() - timedelta(days = 1)).strftime('%Y%m%d')].pm10 }}"
        unique_id: "qa_stazioni1.pm10"
        unit_of_measurement: "µg/m³"
        state_class: measurement
        device_class: pm10
      - name: "ARPAE 1 pm2.5"
        value_template: "{{ value_json['_items'][1]['dati'][(now() - timedelta(days = 1)).strftime('%Y%m%d')].pm25 }}"
        unique_id: "qa_stazioni1.pm25"
        unit_of_measurement: "µg/m³"
        state_class: measurement
        device_class: pm25
      - name: "ARPAE 1 no2"
        value_template: "{{ value_json['_items'][1]['dati'][(now() - timedelta(days = 1)).strftime('%Y%m%d')].no2 }}"
        unique_id: "qa_stazioni1.no2"
        unit_of_measurement: "µg/m³"
        state_class: measurement
        device_class: nitrous_oxide

In realtà nel json ci sarebbe scritto che le sonde misurano anche altri valori ma o sono vuoti o non ve n'è traccia nei risultati:

"parametri_misurati": "As (Arsenico); BaP (Benzo(a)pyrene); Black Carbon BC1 (370nm) ; Black Carbon BC10 (950nm); Black Carbon BC2 (430nm); Black Carbon BC3 (470nm); Black Carbon BC4 (525nm); Black Carbon BC5 (565nm); Black Carbon BC6 (590nm); Black Carbon BC7 (660nm); Black Carbon BC8 (700nm); Black Carbon BC9 (880nm); Cd (Cadmio); N Aliquote; Ni (Nickel); NO (Monossido di azoto); NOX (Ossidi di azoto); NO2 (Biossido di azoto); O3 (Ozono); Pb (Piombo); PM1 (aggiuntivo 1); PM1 OPC; PM10; PM10 (aggiuntivo 1); PM10 OPC; PM2.5; PM2.5 OPC; PM4 OPC; PNC OPC; PTS OPC"

Per quanto riguarda l'ozono i dati sono gli stessi che vengono pubblicati in questa pagina ma al momento ho deciso di non leggerli anche perchè non so bene cosa significhino dal punto di vista della salute.

bollettini_qa

Questo sensore raccoglie i bollettini giornalieri riguardanti la qualità dell'aria. I risultati sono gli stessi pubblicati in /qa_stazioni però è diverso il modo in cui è organizzato l'array. Contiene al primo livello i giorni (a partire dal giorno precedente) ed al secondo livello le province. L'ho trovato abbastanza inutile al mio scopo anche perchè è più scomodo da scorrere in json.

qa_mappe_previsione_pm10_concentrazione

Visualizza le previsioni sulla concentrazione di PM 10 (media 24 ore) sulla mappa in questa pagina.

qa_mappe_previsione_iqa

Stessa mappa sopra ma con i valori riguardanti "l'indice di qualità dell'aria".

qa_mappe_previsione_pm25_concentrazione

Stessa mappa sopra ma con i valori riguardanti la concentrazione di PM 24 (media 24 ore).

qa_mappe_previsione_no2_concentrazione

Stessa mappa sopra ma con i valori riguardanti la concentrazione di Biossido di Azoto (media oraria max).

qa_mappe_previsione_o3_concentrazione

Stessa mappa sopra ma con i valori riguardanti la concentrazione di Ozono (media 8 ore max).

qa_mappe_valutazione_pm10_concentrazione

Visualizza delle valutazioni sulla concentrazione di PM 10 (media 24 ore) sulla mappa in questa pagina

pollini_stazioni

Restituisce l'elenco delle stazioni per la rilevazione dei pollini. I filtri da applicare sono:

  • sort=[("ordine",1)]
  • projection={"foto":0} (per escludere le foto delle stazioni dal json)
  • where={"stato":true}

La URL completa così composta è

https://apps.arpae.it/REST/pollini_stazioni?sort=%5B(%22ordine%22,1)%5D&projection=%7B%22foto%22%3A0%7D&where=%7B%22stato%22%3Atrue%7D

Le stazioni sono:

id città
4176 Piacenza
4177 Parma
4178 Reggio Emilia
4179 Modena
4181 Bologna
4189 San Giovanni Persiceto
4190 San Pietro Capofiume
4182 Ferrara
4185 Ravenna
4184 Faenza
4186 Forlì
4187 Cesena
4188 Rimini

Quindi una query per vedere i risultati di una sola stazione, ad esempio Modena è:

  • where={"_id":{"$eq":"4179"}}
https://apps.arpae.it/REST/pollini_stazioni?sort=%5B(%22ordine%22,1)%5D&projection=%7B%22foto%22%3A0%7D&where=%7B%22_id%22%3A%7B%22%24eq%22%3A%224179%22%7D%7D

bollettini_pollini

Questa richiesta restituisce un bollettino settimanale (descritto nel campo intervallo_validita) composto dalla media regionale dei valori dei pollini rilevati nelle varie stazioni.

Si può richiedere l'elenco di tutti i bollettini di uno specifico anno:

  • sort=[("anno",-1)]
  • projection={"anno":1}
https://apps.arpae.it/REST/bollettini_pollini?sort=%5B(%22anno%22,-1)%5D&projection=%7B%22anno%22%3A1%7D

Per avere l'ultimo bollettino (più aggiornato) vanno usati i filtri:

  • sort=[("_id",-1)]
  • embedded={"stazioni":0} (per escludere le immagini dal json)
https://apps.arpae.it/REST/bollettini_pollini?embedded=%7B%22stazioni%22%3A0%7D&sort=%5B(%22_id%22,-1)%5D

A questo punto i dati interessanti sono:

  • $[_items][0][commento] che contiene una serie di campi testuali con la situazione e le previsioni
  • $[_items][0][letture] che contiene le letture fatte dalle varie stazioni sui seguenti pollini:
Polline Pianta
GRAMINACEE
BETULACEE Alnus, Betula, Ambrosia
COMPOSITEE Artemisia, indistinte
CORILACEE Nocciolo
FAGACEE Castagno, Faggio, Quercia
OLEACEE Ulivo, Frassini, Indistinte
PLANTAGINACEE
URTICACEE
CUPRESSACEE/TAXACEE
AMARANTACEE
POLYGONACEE
EUFORBIACEEE
MIRTACEE
ULMACEE Indistinte
PLATANACEE
ACERACEE
PINACEE
SALICACEE Salice, Pioppo
CIPERACEE
IUGLANDACEE
IPPOCASTANACEE
SPORE Alternaria, Stemphilium
Altri pollini
Non identificati
CANNABACEE
UMBELLIFERE
CORILACEE Carpino, Ostria
MORACEE Broussonetia, Morus

Per ogni tipologia è presente una "tendenza", i dati divisi per ogni giorno e, solo per alcune tipoligie di pollini anche la classe di concentrazione (alta, media, bassa, assente), la media ed il massimo valore.

Ovviamente non ho la minima idea di cosa abbia senso analizzare, mi baso sul fatto che in questo grafico ci hanno messo solo: FAGACEE - Quercia, GRAMINACEE, OLEACEE - Frassini, OLEACEE - Ulivo, PINACEE, PLANTAGINACEE, URTICACEE, SPORE - Alternaria. E infatti solo le uniche che hanno anche il valore della classe di concentrazione e la media.

@frazei
Copy link
Author

frazei commented Jun 4, 2025

Ciao @sandrinoz600 domanda interessante... non riesco però a trovare una fonte aggiornata di dati.
La URL che hai postato mi sembra che fornisca solo alcuni vecchi bollettini.
Ho trovato altre risorse tipo questa e anche questa ma rimandano al download di files quindi sembra che le API siano in manutenzione o qualcosa del genere.

@frazei
Copy link
Author

frazei commented Jun 4, 2025

Ciao @sandrinoz600 domanda interessante... non riesco però a trovare una fonte aggiornata di dati. La URL che hai postato mi sembra che fornisca solo alcuni vecchi bollettini. Ho trovato altre risorse tipo questa e anche questa ma rimandano al download di files quindi sembra che le API siano in manutenzione o qualcosa del genere.

Come non detto, forse ho trovato qualcosa... questi dell'Arpae sono terribili con la documentazione ma guardando le chiamate che fa questa pagina direi che si possano estrarre dei dati utili e aggiornati

@sandrinoz600
Copy link

Ciao, anch'io avevo visto la data vecchia ma, visto che i dati sono pubblicati nella pagina che hai trovato, pensavo (visto che non ne so nulla di queste chiamate) che fossero nascosti nei dati (tutti quei simboli e lettere alla rinfusa).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment