Una delle inegrazioni più diffuse nelle implementazioni di Home Assistant è quella dei dati meteo. Esistono numerosi provider di dati meteorologici facilmente integrabili via Hacs, che forniscono indicazioni sul meteo corrente e previsioni per i prossimi giorni. Ma quanto sono rappresentativi della situazione reale di casa nostra?
Cosa vogliamo fare
Obiettivo di questo package è quello di recuperare e rendere disponibili in HA i dati di una stazione meteo che sia prossima a casa nostra e quindi rappresentativa della situazione meteo nella nostra area, senza disporre di una stazione meteo privata, che può essere anche molto costosa. In questo modo, potremo usare questi dati in modo efficace per scatenare automazioni utili, come ad esempio chiudere le tende da sole se piove o tira vento.
Cosa ci serve
Il servizio che fa al caso nostro si chiama Meteonetwork. Riprendiamo direttamente dal sito la descrizione del progetto:
Con i servizi di Livemap, i modelli, il forum e le sue collaborazioni con enti di ricerca, Meteonetwork dà un contributo fondamentale alla divulgazione scientifica sulla meteorologia e la climatologia. L’associazione possiede la più grande rete italiana di stazioni di rilevamento.
E ancora:
L’associazione MeteoNetwork è stata fondata da amici e meteo appassionati come associazione non registrata il 6 aprile 2002 a Seregno (MB). Quasi un anno dopo, il 5 aprile 2003, l’associazione viene registrata ufficialmente a Mantova, dov’è la sua sede legale. MeteoNetwork è un’organizzazione senza scopo di lucro con il compito di diffondere la conoscenza nel campo della meteorologia e della climatologia.
Meteonetwork è perfetto per il nostro scopo, in quanto offre delle API pubbliche e gratuite, attraverso le quali recuperare le info di una delle centinaia di stazioni che aderiscono al progetto ed appartengono dunque alla meteonetwork. La descrizione delle API è disponibile sul sito.
Per poter utilizzare le API è necessario registrarsi gratuitamente al sito. Una volta completata la registrazione, utilizzeremo le credenziali di accesso (email/password) per generare il nostro token unico con cui autenticarci nelle chiamate rest. Questo passaggio preliminare va eseguito una volta soltanto, tenendo poi traccia del token generato nel nostro file ‘secret.yaml’.
Generiamo il token di accesso
Come detto, le generazione del token è una operazione preliminare una-tantum. Abbiamo almeno due modi per farlo:
Nel primo caso, inviamo la chiamata POST come in figura:
Se invece vogliamo usare il metodo mediante riga di comando, è sufficiente utilizzare il seguente comando ‘shell’:
curl --location --request POST 'https://api.meteonetwork.it/v3/login?email=EMAIL@mail.it&password=MY_PASSWORD'
In entrambi i casi, se tutto è andato bene, avremo una risposta positiva dall’endpoint chiamato per la login (codice 200) e potremo recuperare dal body della risposta il valore del nostro access_token
{
"status_code": 200,
"access_token": "1234|questoeilmiotokenunicoperaccedereameteonetworkapigratuitamente",
"token_type": "Bearer",
"message": "The token will never expires. Save it because you can generate a new one in 1 hour."
}
che andremo a scrivere nel file ‘secret.yaml’:
#
# secret.yaml
#
meteonetwork_token: '1234|questoeilmiotokenunicoperaccedereameteonetworkapigratuitamente'
Se necessario, qui trovi un refresh su come organizzare al meglio la configurazione di HA.
I dati meteo in tempo reale
utilizzando ancora uno dei due metodi sopra elencati, procediamo con il test della chiamata API per la lettura dei dati meteo in tempo reale. Prima di tutto, individuiamo la stazione meteo più vicina a noi, che sia quindi la più rappresentativa della situazione meteo di casa nostra. A tale scopo, navighiamo sulla pagina con la mappa delle stazioni ed selezioniamo quella di nostro interesse, cliccando sul puntino giallo corrispondente.
Si aprirà la pagina di dettaglio della stazione, dal cui indirizzo andremo a recuperare il codice stazione ad esempio:
https://meteonetwork.eu/it/weather-station/lmb254-stazione-meteorologica-di-milano-maxwell
Nel nostro esempio, il codice stazione è lmb254, il comando ‘curl’ è:
curl --location --request GET 'https://api.meteonetwork.it/v3/data-realtime/lmb254' \
--header 'Authorization: Bearer 1234|questoeilmiotokenunicoperaccedereameteonetworkapigratuitamente'
E la risposta:
[
{
"observation_time_local": "2022-01-03 13:12:00",
"observation_time_utc": "2022-01-03 12:12:00",
"station_code": "lmb254",
"place": "Milano",
"area": "Milano - Maxwell",
"latitude": "45.498165533605",
"longitude": "9.24053192138672",
"altitude": 138,
"country": "IT",
"region_name": "Lombardia",
"temperature": "5.3",
"smlp": "1021.0",
"rh": "95",
"wind_speed": "1.60",
"wind_direction": "ESE",
"wind_gust": "9.70",
"rain_rate": null,
"daily_rain": null,
"dew_point": "4.4",
"rad": null,
"uv": null,
"current_tmin": "1.7",
"current_tmed": "3.2",
"current_tmax": "6.8",
"current_rhmin": "89",
"current_rhmed": "95",
"current_rhmax": "96",
"current_wgustmax": "9.7",
"current_wspeedmax": "6.4",
"current_wspeedmed": "0.1",
"current_uvmed": null,
"current_uvmax": null,
"current_radmed": null,
"current_radmax": null,
"name": "Milano - Milano - Maxwell"
}
]
Bene, il servizio risponde come atteso e la stazione è attiva: abbiamo tutto quello che ci serve per implementare il nostro package.
Scriviamo il file yaml
Come al solito, in testa al nostro package posizioniamo la sezione di personalizzazione:
#
# Package: pkg_meteonetwork.yaml
#
homeassistant:
customize:
sensor.meteonetwork:
friendly_name: Stazione Meteonetwork
icon: mdi:cloud-braces
Sensore principale
Continuiamo con il sensore che conterrà i dati in tempo reale che ci interessa ricevere dalla stazione meteo selezionata, tra quelli disponibili:
#
# Sensore principale meteonetwork
#
sensor:
- platform: rest
name: meteonetwork
json_attributes:
- observation_time_local
- station_code
- place
- region_name
- country
- latitude
- longitude
- altitude
- temperature
- smlp
- rh
- wind_speed
- wind_direction
- rain_rate
- dew_point
- current_tmin
- current_tmax
- daily_rain
resource: https://api.meteonetwork.it/v3/data-realtime/lmb254 # sostituire qui il codice della stazione di interesse
value_template: "{{ value_json[0].area }}"
verify_ssl: false
scan_interval: 300
headers:
Authorization: !secret meteonetwork_token
Non esageriamo con la frequenza di aggiornamento: in primo luogo, le API sono utilizzabili gratuitamente a patto (tra le altre cose) di non superare la quota di una chiamata al secondo; inoltre, è praticamente inutile aggiornare questo sensore con una frequenza superiore a quella della stazione stessa; infine, trattandosi di dati meteo, non subiscono variazioni così repentine e significative. Nel nostro esempio abbiamo impostato un periodo di aggiornamento di 5 minuti.
Sensori con le letture singole
Il sensore creato nella sezione precedente, avrà tanti attributi quante sono le prorietà, ovvero le misure, che abbiamo deciso di recuperare mediante la nostra chiamata rest. A questo punto, per comodità, estraiamo questi attributi e li storicizziamo in altrettanti singoli sensori, mediante la piattaforma ‘template’:
# sensor:
# continua sezione già iniziata in precedenza, non è necessario ripetere
- platform: template
sensors:
meteonetwork_last_update:
friendly_name: "Ultimo aggiornamento"
value_template: "{{ state_attr('sensor.meteonetwork', 'observation_time_local') }}"
icon_template: mdi:clock-outline
meteonetwork_temp:
friendly_name: "Temperatura"
value_template: "{{ state_attr('sensor.meteonetwork', 'temperature') | float | round(1) }}"
unit_of_measurement: "°C"
meteonetwork_rh:
friendly_name: "Umidita relativa"
value_template: "{{ state_attr('sensor.meteonetwork', 'rh') | int }}"
unit_of_measurement: "%"
icon_template: mdi:water-percent
meteonetwork_press:
friendly_name: "Pressione"
value_template: "{{ state_attr('sensor.meteonetwork', 'smlp') | float | round(1) }}"
unit_of_measurement: "hPa"
icon_template: mdi:gauge
meteonetwork_wind:
friendly_name: "Vento"
value_template: "{{ state_attr('sensor.meteonetwork', 'wind_speed') | int }} ({{state_attr('sensor.meteonetwork', 'wind_direction') }})"
unit_of_measurement: "Km/h"
icon_template: mdi:weather-windy
meteonetwork_rain:
friendly_name: "Pioggia"
value_template: "{{ state_attr('sensor.meteonetwork', 'rain_rate') | int }}"
unit_of_measurement: "mm/h"
icon_template: mdi:weather-pouring
meteonetwork_dew_point:
friendly_name: "Temperatura rugiada"
value_template: "{{ state_attr('sensor.meteonetwork', 'dew_point') | float | round(1) }}"
unit_of_measurement: "°C"
icon_template: mdi:water
Automazioni
Come accennato in precedenza, lutilità di questi sensori è poterli utilizzare come trigger o come condizioni per delle automazioni, ad esempio: chiudere una tenda da sole in caso di vento forte, abbassare le tapparelle in caso di pioggia, non attivare l’irrigazione se ha piovuto da poco. Banalmente, possiamo iniziare a farci notificare queste situazioni:
automation:
# Notifica su app di pioggia
- alias: "Meteo__Notifica_pioggia"
trigger:
platform: numeric_state
entity_id: sensor.meteonetwork_rain
above: 1
for: '00:10:00'
condition: []
action:
service: notify.mobile_app
data_template:
title: "Meteo"
message: "Pioggia persistente a {{ trigger.to_state.state }} mm/h"
# Notifica su app di vento forte
- alias: "Meteo__Notifica_vento"
trigger:
platform: numeric_state
entity_id: sensor.meteonetwork_wind
above: 1
for: '00:10:00'
condition: []
action:
service: notify.mobile_app
data_template:
title: "Meteo"
message: "Vento forte a {{ trigger.to_state.state }} kmh"
Risultato finale
Una volta definiti tutti i sensori e le automazioni, possiamo utilizzare queste entità come meglio crediamo nelle nostre dashboard. Qui ci limitiamo a mostrare in una card ‘entities’ il riepilogo di quanto creato:
type: entities
entities:
- entity: sensor.meteonetwork
- entity: sensor.meteonetwork_last_update
- entity: sensor.meteonetwork_temp
- entity: sensor.meteonetwork_rh
- entity: sensor.meteonetwork_wind
- entity: sensor.meteonetwork_rain
- entity: sensor.meteonetwork_press
- entity: sensor.meteonetwork_dew_point
title: Meteonetwork
Ed ecco il riepilogo:
Il package è pronto. Il codice completo è disponibilie qui.
Enjoy!