Skip to Content

Stazione Meteo Internet Semplice con ESP32

Stazione Meteo Internet Semplice con ESP32

In questo tutorial imparerai le basi per costruire una stazione meteo internet utilizzando un ESP32.

Scaricheremo i dati meteo da OpenWeather, analizzeremo i dati JSON usando ArduinoJson per estrarre temperatura, umidità, posizione e descrizione del meteo e mostreremo queste informazioni su un display OLED.

Iniziamo!

Componenti necessari

Qui sotto trovi i componenti necessari per questo progetto. Per questo progetto sto usando una vecchia scheda ESP32 (ESP32 lite), che è stata deprecata ma puoi ancora trovarla. È quella elencata qui sotto. Esiste un modello successivo con specifiche migliorate, che puoi trovare here . Ma qualsiasi altro ESP32, ESP8266 o Arduino con Wi-Fi andrà bene lo stesso.

ESP32 lite Lolin32

ESP32 lite

USB data cable

Cavo dati USB

Dupont wire set

Set di cavi Dupont

Half_breadboard56a

Breadboard

OLED display

Display OLED

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

OpenWeather

Per la nostra stazione meteo internet ovviamente avremo bisogno di scaricare i dati meteo da internet. Ci sono vari modi per farlo ma il più semplice è usare OpenWeather .

OpenWeather è un servizio che fornisce dati meteo attuali e previsioni tramite un’API che gli sviluppatori possono usare nei loro progetti. Hanno un piano gratuito plan che permette di fare 1000 chiamate API al giorno. Ovvero una chiamata API ogni 60* 60* 24/1000 = 86,4 secondi ed è più che sufficiente, visto che aggiornare il meteo ogni 5 o 10 minuti è più che abbastanza.

Inoltre, anche solo il piano gratuito fornisce informazioni su Current Weather , 3-hour Forecast 5 days , Basic weather maps , Air Pollution e Geocoding . Più che sufficiente per la maggior parte delle applicazioni hobbistiche.

Creare un account OpenWeather

Prima di poter usare qualsiasi API di OpenWeather, ti serve una API-key e per ottenerla devi creare un account. Per creare un account vai alla pagina sign-up e inserisci i tuoi dati lì.

Sign-up page at OpenWeather
Pagina di registrazione su OpenWeather

Crea una API-key OpenWeather

Una volta che hai un account e hai effettuato l’accesso vai alla pagina di creazione api-key e crea una API-key. La API-key è quella lunga stringa “sdfd87fakeby6apikeysf4z” che vedi nello screenshot qui sotto. La tua chiave sarà diversa dalla mia, e quella mostrata ovviamente è una chiave finta ; )

Create API-key at OpenWeather
Crea API-key su OpenWeather

Puoi dare un nome alla chiave ma non è obbligatorio. I nomi sono utili se hai più applicazioni che usano chiavi diverse e vuoi tenerle separate.

Scaricare i dati meteo da OpenWeather

Con la tua API-key ora puoi recuperare i dati meteo dalle varie API costruendo l’URL corrispondente. Ad esempio, se vai alla Current Weather API, la documentazione ti dice che l’URL dovrebbe essere così:

https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={API key}

Quindi, dovresti conoscere la latitudine e la longitudine della tua posizione, e la tua API-key e sostituire i segnaposto tra parentesi graffe ( {lat} , {lon} , {API key} ) con i valori reali. Funziona, ma trovare latitudine e longitudine per varie città di interesse è un po’ scomodo.

Per fortuna, c’è la Geocoding API che ci permette di ottenere i dati meteo più facilmente fornendo una stringa con il nome della città e il codice del paese. Il pattern dell’URL è così:

https://api.openweathermap.org/data/2.5/weather?q={city name},{country code}&appid={API key}

Ad esempio, per ottenere il meteo a Melbourne, Australia (AU), dove vivo, scriveresti:

http://api.openweathermap.org/data/2.5/weather?q=Melbourne,AU&APPID=sdfd87fakeby6apikeysf4z

Se incolli questo URL nella barra di ricerca del browser vedrai il seguente output. Assicurati di spuntare la casella “Pretty print” in alto.

Weather data in Kelvin
Dati meteo in Kelvin

Se guardi la temperatura noterai un valore altissimo. Nell’esempio sopra il valore di temperatura riportato è 283.38. Questo perché di default OpenWeather restituisce le temperature in Kelvin. Se vuoi unità metriche (Celsius) o imperiali (Fahrenheit), puoi specificarlo nell’URL.

Ad esempio, per avere le temperature in Celsius devi usare:

https://api.openweathermap.org/data/2.5/weather?q={city name},{country code}&appid={API key}&units=metric

e per Fahrenheit scriveresti units=imperial . Per maggiori informazioni dai un’occhiata alla documentazione di OpenWeather per units of measurement .

Questo è tutto quello che ti serve sapere per iniziare con OpenWeather. Ma ti consiglio di esplorare anche le altre API menzionate sopra. Ci sono un sacco di dati interessanti che puoi usare per rendere la tua stazione meteo davvero utile.

Analizzare dati JSON con ArduinoJson

Di default OpenWeather restituisce i dati in formato JSON . JSON è un formato di testo strutturato che dobbiamo analizzare per estrarre i dati che ci interessano. Farlo a mano è piuttosto complicato, quindi usiamo l’ottima libreria ArduinoJson .

Documento JSON

Ma prima di tutto vediamo quali informazioni vogliamo estrarre dai dati meteo. Lo screenshot qui sotto mostra tutti i dati che ottengo chiedendo a OpenWeather il meteo di Melbourne.

JSON data for Melbourne weather
Dati JSON per il meteo di Melbourne

Per la nostra semplice stazione meteo internet, estrarrò quattro informazioni: la breve descrizione del meteo sotto weather -> main ( "Clouds" ), la temperatura attuale sotto main -> temp ( 10.29 ), l’umidità relativa attuale sotto main -> humidity ( 82 ), e il nome della località sotto name ( "Melbourne" ).

Estrazione dei dati con ArduinoJson

Uno snippet di codice che usa ArduinoJson per estrarre questi quattro valori meteo sarebbe così:

StaticJsonDocument<4096> doc;

String json = http.getString();
deserializeJson(doc, json);

const char* name = doc["name"];
const char* weather = doc["weather"][0]["main"];
float temp = doc["main"]["temp"];
int hum = doc["main"]["humidity"];

Per prima cosa devi riservare un po’ di memoria dove caricare i dati JSON. La riga StaticJsonDocument<4096> doc; riserva 4KB di memoria. Se scarichi più dati meteo, come le previsioni, potresti dover aumentare questo valore.

Poi scarichiamo i dati meteo e li scriviamo (deserializziamo) nel documento. Lo snippet di codice non mostra il client HTTP che usiamo per il download ma lo troverai nel codice completo qui sotto.

String json = http.getString();
deserializeJson(doc, json);

Se i dati JSON restituiti da OpenWeather fossero sintatticamente errati (parentesi mancanti, …), la deserializzazione fallirà.

Deserializzare significa semplicemente che il testo semplice della stringa json viene analizzato e convertito in una struttura dati che ci permette di accedere più facilmente ai campi e ai valori del documento JSON doc . Per maggiori dettagli sulla deserializzazione dai un’occhiata all’ottima ArduinoJson tutorial on deserialization .

Le seguenti quattro righe di codice estraggono le informazioni che ci servono dal doc che contiene la stringa json deserializzata.

const char* name = doc["name"];
const char* weather = doc["weather"][0]["main"];
float temp = doc["main"]["temp"];
int hum = doc["main"]["humidity"];

La prima riga estrae il nome della località meteo ( "Melbourne" ), che è memorizzato sotto doc["name"] . Poiché è una stringa (vedi le virgolette), dobbiamo salvarla in una variabile di tipo const char* name .

La breve descrizione del meteo ( "Clouds" ) è memorizzata sotto doc["weather"][0]["main"] . Nota che sotto doc["weather"] , abbiamo una lista [] e ci interessa il primo (e unico) elemento di quella lista. Quindi dobbiamo scrivere doc["weather"][0] . Poi otteniamo la descrizione sotto main , e il percorso completo è doc["weather"][0]["main"] . Anche qui viene restituita una stringa e va salvata in una variabile di tipo const char* weather .

La temperatura attuale è un valore floating point (10.29), che si trova sotto doc["main"]["temp"] . Essendo un valore floating point va salvato in una variabile di tipo float .

Infine, estraiamo l’umidità attuale ( 82 ) da doc["main"]["humidity"] e la salviamo in una variabile di tipo int .

Devi fare molta attenzione a far corrispondere i tipi di dato dei valori con quelli usati nel documento JSON e a usare i percorsi corretti per estrarre quei valori. Altrimenti rischi errori di memoria molto difficili da individuare. Se vuoi estrarre valori diversi, procedi con calma e aggiungi nuovi valori uno alla volta, così saprai subito quando qualcosa non va.

Collegare ESP32 e OLED

Collegare l’ESP32 all’OLED è molto semplice perché l’OLED ha un’interfaccia I2C. Prima collega il ground (G) dell’ESP32 al GND dell’OLED. Poi collega il 3V dell’ESP32 al VCC dell’OLED.

Connecting ESP32 to OLED
Collegamento ESP32 a OLED

Poi dobbiamo collegare SCL e SDA. Qualsiasi pin va bene ma i pin I2C di default su ESP32-lite sono 23 per SCL e 19 per SDA. Quindi colleghiamo i pin corrispondenti dell’OLED a questi. L’immagine sopra mostra il cablaggio completo. Se hai difficoltà, guarda il tutorial How to Interface the SSD1306 I2C OLED Graphic Display With Arduino

Se non sai quali sono i pin I2C di default per il tuo ESP32, non preoccuparti. È facile scoprirlo. Basta eseguire il seguente codice e il tuo ESP32 te lo dirà.

void print(const char* name, int pin) {
  Serial.print(name);
  Serial.println(pin);
}
void setup() {
  Serial.begin(9600);
}
void loop() {
  print("SDA:  ", SDA);
  print("SCL:  ", SCL);
  delay(5000);
}

Per maggiori informazioni leggi il nostro post su come Find I2C and SPI default pins . In alternativa, puoi definire tu i pin che vuoi usare. Il codice nelle sezioni seguenti ti mostra come fare.

Codice per la Stazione Meteo Internet

In questa sezione scriveremo il codice per scaricare i dati meteo da OpenWeather, estrarre posizione, temperatura, umidità e descrizione del meteo dai dati e mostrarli su un OLED. Dai un’occhiata al codice completo qui sotto e poi ne discuteremo i dettagli.

#include "WiFi.h"
#include "HTTPClient.h"
#include "ArduinoJson.h"
#include "Adafruit_SSD1306.h"

#define WIFI_SSID "YOURSSID"
#define WIFI_PASSWORD "YOURPASSWORD"
#define URL "http://api.openweathermap.org/data/2.5/weather?q=Melbourne,AU&APPID=YOURAPIKEY&units=metric"

HTTPClient http;
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
StaticJsonDocument<4096> doc;

void downloadWeather() {  
  http.begin(URL);
  if (http.GET() > 0) {
    String json = http.getString();
    auto err = deserializeJson(doc, json);
    if (err) {
      Serial.printf("Deserializion error: %s\n", err.f_str());
    }
  } else {
     Serial.println("Could not get data!");
  }
  http.end();
}

void displayWeather() {
  const char* name = doc["name"];
  const char* weather = doc["weather"][0]["main"];
  float temp = doc["main"]["temp"];
  int hum = doc["main"]["humidity"];

  oled.clearDisplay();
  oled.setCursor(0, 0);
  oled.printf(" %s\n", name);
  oled.printf(" %s\n", weather);
  oled.printf(" T: %.1f C\n", temp);
  oled.printf(" H: %d %%\n", hum);
  oled.display();
}

void oled_init() {
  Wire.begin(19, 23);  // sda, scl
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.clearDisplay();
  oled.setTextSize(2);
  oled.setTextColor(WHITE);
}

void wifi_init() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED)
    delay(500);
}

void setup(void) {
  Serial.begin(115200);
  oled_init();
  wifi_init();      
}

void loop() {
  downloadWeather();
  displayWeather();
  delay(10*60*1000); // 10min
}

Librerie

Il codice inizia includendo le librerie necessarie. WiFi.h per l’accesso WiFi, HTTPClient.h per scaricare dati via HTTP, ArduinoJson.h per analizzare i dati scaricati e Adafruit_SSD1306.h per mostrare i dati sull’OLED.

WiFi.h e HTTPClient.h sono librerie standard ma ArduinoJson.h e Adafruit_SSD1306.h dovrai installarle tramite il Library Manager.

Costanti

Poi definiamo alcune costanti. In particolare le credenziali WiFi e l’URL dell’API OpenWeather da cui scarichiamo i dati meteo. Puoi cambiare l’URL per ottenere i dati di un’altra località o in un’altra unità, ma non dimenticare di usare la tua API-key.

#define WIFI_SSID "YOURSSID"
#define WIFI_PASSWORD "YOURPASSWORD"
#define URL "http://api.openweathermap.org/data/2.5/weather?q=Melbourne,AU&APPID=YOURAPIKEY&units=metric"

Dai un’occhiata alla documentazione API per Current Weather , che mostra tutti i modi diversi in cui puoi costruire un URL. Guarda anche la Geocoding API , che semplifica l’uso delle località.

Oggetti

Per il resto del codice ci serviranno tre oggetti. Un HTTPClient che ci permette di scaricare dati da un sito web, un StaticJsonDocument per memorizzare i dati deserializzati e un oggetto oled per mostrare i dati sull’OLED.

HTTPClient http;
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
StaticJsonDocument<4096> doc;

Per l’OLED devi specificare le dimensioni, nel mio caso sono 128×64 pixel, e per il documento JSON dobbiamo riservare la quantità massima di memoria che potenzialmente ci serve. Ho riservato generosamente 4kB (4069 Byte), che bastano per i dati meteo attuali. Se scarichi le previsioni, che sono più grandi, potresti dover riservare più spazio.

downloadWeather

La funzione downloadWeather scarica i dati meteo da OpenWeather tramite http.GET() , li deserializza e li salva nel StaticJsonDocument tramite deserializeJson ().

void downloadWeather() {  
  http.begin(URL);
  if (http.GET() > 0) {
    String json = http.getString();
    auto err = deserializeJson(doc, json);
    if (err) {
      Serial.printf("Deserializion error: %s\n", err.f_str());
    }
  } else {
     Serial.println("Could not get data!");
  }
  http.end();
}

Se qualcosa va storto, stampiamo un messaggio di errore sul Serial Monitor.

displayWeather

Per mostrare il meteo prima estraiamo le quattro informazioni meteo dal doc come descritto sopra. Poi puliamo il display, impostiamo il cursore e semplicemente stampiamo il nome della località, la breve descrizione del meteo, la temperatura attuale e l’umidità relativa.

void displayWeather() {
  const char* name = doc["name"];
  const char* weather = doc["weather"][0]["main"];
  float temp = doc["main"]["temp"];
  int hum = doc["main"]["humidity"];

  oled.clearDisplay();
  oled.setCursor(0, 0);
  oled.printf(" %s\n", name);
  oled.printf(" %s\n", weather);
  oled.printf(" T: %.1f C\n", temp);
  oled.printf(" H: %d %%\n", hum);
  oled.display();
}

Sull’OLED le informazioni meteo verranno visualizzate come mostrato nell’immagine qui sotto.

Weather data on OLED
Dati meteo su OLED

oledInit

Prima di poter usare l’OLED dobbiamo inizializzarlo. La cosa più importante è specificare i pin usati per l’interfaccia I2C (SDA, SCL) e l’indirizzo I2C del display.

Se usi i pin I2C di default per il tuo microcontrollore, non serve chiamare Wire.begin(), altrimenti sì.

L’indirizzo I2C dell’OLED che sto usando è 0x3C, che è comune, ma il tuo potrebbe essere diverso. Dai un’occhiata al tutorial How to Interface the SSD1306 I2C OLED Graphic Display With Arduino , se hai difficoltà.

void oled_init() {
  Wire.begin(19, 23);  // sda, scl
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.clearDisplay();
  oled.setTextSize(2);
  oled.setTextColor(WHITE);
}

A parte questo, basta pulire il display e impostare la dimensione e il colore del testo.

wifiInit

Allo stesso modo dell’OLED dobbiamo anche inizializzare la connessione WiFi. Assicurati di usare il ssid e la password corretti, altrimenti il client WiFi non si connetterà.

void wifi_init() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED)
    delay(500);
}

setup

Con le funzioni di supporto sopra la funzione setup è diventata molto semplice. Basta inizializzare la comunicazione seriale, l’OLED e il WiFi e il gioco è fatto.

void setup(void) {
  Serial.begin(115200);
  oled_init();
  wifi_init();      
}

loop

Anche la funzione loop è semplice. Scarichiamo i dati meteo, li mostriamo sull’OLED e poi aspettiamo 10 minuti prima di ripetere il processo.

void loop() {
  downloadWeather();
  displayWeather();
  delay(10*60*1000); // 10min
}

Durante l’implementazione e i test assicurati di avere un ritardo abbastanza lungo quando scarichi i dati meteo. Se superi le 1000 chiamate al giorno verrai bloccato per quel giorno.

Altrimenti, è tutto qui! Ora hai una bella stazione meteo internet!

Conclusione

In questo tutorial hai imparato come costruire una stazione meteo internet. Anche se è molto basilare, è un ottimo punto di partenza per una stazione meteo molto più avanzata.

Esplora le altre API che OpenWeather offre e vedi quali dati vuoi estrarre. I dati restituiti da OpenWeather includono anche gli id delle icone che puoi usare per mostrare le icone meteo.

Potresti voler passare a un display più grande rispetto al piccolo OLED che abbiamo usato qui. Alcuni display Elecrow con ESP32 integrato e touch screen potrebbero essere una buona scelta. Vedi la CrowPanel 2.8″ ESP32 Display : Easy Setup Guide su come usarne uno.

Oltre ai dati meteo da internet puoi anche raccogliere dati meteo locali usando sensori di temperatura, umidità e qualità dell’aria.

Infine, reagire attivamente alle condizioni meteo cambianti e accendere irrigatori, chiudere finestre o attivare il condizionatore sono progetti divertenti.

Divertiti ; )