Mini stazione

Adoperando la ESP32 TTGO realizziamo una stazione meteo WiFi per leggere sul display TFT le informazioni recuperate da OpenWeatherMap

Dopo aver imparato a conoscere la ESP32 TTGO, possiamo procedere a vederla in azione all’interno di un progetto IoT, sfruttando il display TFT integrato e il WiFi per realizzare una mini stazione meteo in cui mostrare i dati che rileveremo dal sito OpenWeatherMap. Questo progetto richiede una conoscenza di base delle dev-board ESP32; se non avete ancora provveduto a configurare la IDE di Arduino per le ESP32, vi consigliamo di dare uno sguardo alla nostra GUIDA.

Progetto

Dopo aver realizzato diverse stazioni meteo, ci sembrava arrivato il momento di realizzarne una con ESP32 e che fosse anche piccola rispetto a quelle fin ora realizzate. Al fine di non “appesantire” il progetto, abbiamo deciso di non collegare sensori alla nostra mini stazione, ma di sfruttare la connettività WiFi per estrapolarli dalla rete e mostrarli sul suo piccolo display. A tal proposito avremo bisogno di “chiedere” i dati ad un sito web molto apprezzato dai makers: stiamo parlando di OpenWeatherMap, a cui chiederemo di fornire una API per poter ottenere i dati che ci serviranno per la nostra mini stazione meteo.

Mini stazione

Componenti

Il progetto dal punto di vista delle componenti, la nostra mini stazione meteo non richiede molto, se non principalmente la ESP32 TTGO ed, eventualmente, una batteria a litio se vogliamo alimentarla esternamente e senza l’ausilio del cavo USB Type-C. Come abbiamo detto più volte, la ESP32 è una dev-board molto performante e dotata di connessione Bluetooth e WiFi per poterla connettere ad altri device o a Internet.

Vi ricordiamo anche che le ESP32 lavorano con una tensione di 3,3V, per cui la batteria da utilizzare deve essere di circa la stessa tensione. Realizzando una mini stazione meteo, abbiamo scelto una batteria a litio, molto piccola, da 3,7V e 180mAh, non tantissimi ma sufficienti per garantire una buon autonomia.

Mini stazione

Lista componenti su Amazon:

Lista componenti su Aliexpress:

Collegamenti

Gli unici collegamenti da effettuare per la nostra mini stazione meteo sono solamente elettrici. Abbiamo connesso la ESP32 TTGO alla batteria adoperando il connettore in dotazione. Abbiamo operato saldando il cavo rosso al pin centrale di uno switch, mentre il positivo della batteria ad uno dei pin laterali dello switch, saldando infine il cavo nero del connettore al cavo del GND della batteria.

Mini stazione



Codice

Prima di passare al codice da caricare sulla nostra ESP32 TTGO, dobbiamo recarci sul sito www.openweathermap.org per ottenere una API-Key. Una volta registrati, effettuate l’accesso e entrate nella scheda API keys per ottenere la vostra chiave API. Rammentate che è segreta e non dovrete condividerla con nessuno.

Fatto questo, tornate nella Homepage del sito e nella casella di ricerca, cercate la vostra città e cliccate sul risultato di ricerca (esempio: Milano, IT), poi nella barra degli indirizzi del vostro browser apparirà un numero dopo la dicitura city: conservatelo perché servirà a breve.

Siamo ora pronti a dedicarci al nostro codice, scaricabile a questo LINK. Il nostro sketch contempla anche un file denominato weathericons.h che contiene le miniature (icons) che ci serviranno per mostrare lo stato delle condizioni climatiche, quindi assicuratevi di scompattare entrambi i file. Partiamo, come sempre, dalle librerie che ci serviranno per far funzionare la mini stazione meteo. Le librerie SPI.h e WiFi.h sono incluse nella IDE e servono a far comunicare la ESP32 con il display ed a farle adoperare il WiFi, mentre la libreria TFT_eSPI.h è scaricabile tramite il Gestore delle librerie della IDE di Arduino, infine la ArduinoJson.h, scaricabile a questo LINK, ci aiuterà ad elaborare i dati che estrarremo dal sito OpenWeatherMap.


#include <SPI.h>
#include <TFT_eSPI.h>
#include <ArduinoJson.h>
#include <WiFi.h>

Includiamo ora il file che contiene le icone, citato sopra, l’SSID e la password della rete WiFi a cui la ESP32 si connetterà, i dati ottenuti da OpenWeatherMap (API, ID City), l’URL a cui la scheda si collegherà e creiamo una stringa denominata info che ci aiuterà più avanti. Creiamo anche l’oggetto tft con cui gestire il display.


#include "weathericons.h"

WiFiClient client;

TFT_eSPI tft = TFT_eSPI();

const char* ssid = "wifi";
const char* password = "password";

const String city_id = "xxxxxxx";
const String apikey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const String units = "metric";

char url[] = "api.openweathermap.org";

String info = "";



Nel VOID SETUP avviamo il monitor seriale, il display e stampiamo il logo del nostro canale YouTube, poi procediamo alla connessione WiFi. Appena la connessione sarà effettuata, stampiamo la conferma a display.


Serial.begin(9600);

tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);

tft.drawBitmap(70, 0, logo, 100, 100,TFT_RED);
delay(1500);

tft.setTextSize(1);
tft.setTextColor(TFT_YELLOW);
tft.drawString("Connessione a rete WiFi...", 0, 110);

WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println(".");
}

Serial.println("Connesso");
Serial.println("");
Serial.println("IP: ");
Serial.println(WiFi.localIP());

tft.setTextSize(1);
tft.setTextColor(TFT_YELLOW);
tft.drawString("Connesso!", 160, 110);

delay(1000);

tft.fillScreen(TFT_BLACK);

Nel VOID LOOP ci colleghiamo al sito di OpenWeatherMap tramite l’URL dichiarato prima e accedendo con la API e l’ID city. Se la richiesta va a buon fine, il client leggerà i dati e li memorizza sulla stringa info che avevamo creato prima, altrimenti apparirà un messaggio di errore su monitor seriale. Una volta effettuata la lettura, interrompiamo la connessione.


if (client.connect(url, 80))
{ //avvia la connessione del client
client.println("GET /data/2.5/weather?id=" + city_id + "&units=" + units + "&APPID=" + apikey);
client.println("Host: api.openweathermap.org");
client.println("User-Agent: ArduinoWiFi/1.1");
client.println("Connection: close");
client.println();
}
else {
Serial.println("connection failed"); //connessione fallita
Serial.println();
}

while (client.connected() && !client.available()) // attendo mentre il client si è collegato ed è disponibile
delay(1);
while (client.connected() || client.available()) // mentre il client è connesso e disponibile, leggo i dati
{
char reading = client.read();
info = info + reading;
}

client.stop(); // interrompo la connessione del client

Proseguendo nel VOID LOOP, dobbiamo elaborare i dati che abbiamo ricevuto e memorizzati in una sola stringa. Tuttavia, dobbiamo smembrare questa stringa ed estrapolarne solo le informazioni utili. L’intero processo è la deserializzazione della stringa che viene poi trasformata in oggetto. Le informazioni che ci serviranno sono: Città, Paese, Temperatura, Umidità, Pressione, Velocità del vento, meteo e Id icona meteo.


info.replace('[', ' ');
info.replace(']', ' ');
char jsonArray [info.length() + 1];
info.toCharArray(jsonArray, sizeof(jsonArray));
jsonArray[info.length() + 1] = '\0';
StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, jsonArray);

if (error) {
Serial.print(F("deserializeJson() failed with code "));
Serial.println(error.c_str());
return;
}

String location = doc["name"]; // Città
String country = doc["sys"]["country"]; // Paese
int t = doc["main"]["temp"]; // Temperatura
int h = doc["main"]["humidity"]; // Umidità
int p = doc["main"]["pressure"]; // Pressione
String wind = doc["wind"]["speed"]; // Velocità del vento
String weather = doc["weather"]["main"]; // Condizione meteo
String icon = doc["weather"]["icon"]; // ID icona

Serial.println();
Serial.print("Paese: ");
Serial.println(country);
Serial.print("Luogo: ");
Serial.println(location);
Serial.print("Temperatura: ");
Serial.print(t);
Serial.println("°C");
Serial.printf("Umidità: ");
Serial.print(h);
Serial.println("%");
Serial.printf("Pressione: ");
Serial.print(p);
Serial.println(" mBar");
Serial.printf("Vento: ");
Serial.print(wind);
Serial.println(" m/s");
Serial.print("Meteo: ");
Serial.print(weather);
Serial.print(" ");
Serial.println (icon);

Stampiamo sul display tutti i dati ottenuti e l’indirizzo IP locale della ESP32.


// Stampo IP, città, Paese
tft.setTextSize(1);
tft.setTextColor(TFT_YELLOW);
tft.drawString(WiFi.localIP().toString().c_str(), 3, 10);
tft.drawString(country, 220, 10);
tft.drawString(location, 175, 10);
tft.fillRect (0, 25, 320, 2, TFT_YELLOW);
// Stampo Temperatura e umidità
tft.setTextSize(2);
tft.setTextColor(TFT_CYAN, TFT_BLACK);
tft.drawNumber(t, 60, 45);
tft.drawString("C - ", 90, 45);
tft.drawNumber(h, 135, 45);
tft.drawString("%", 162, 45);
// Stampo pressione in millibar
tft.setTextSize(2);
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.drawNumber(p, 60, 65);
tft.drawString("mBar", 115, 65);
// Stampo velocità del vento e relativa icona
tft.setTextSize(2);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.drawString(wind, 60, 103);
tft.drawString("m/s", 120, 103);
tft.drawBitmap(0, 93, windicon, 50, 38,TFT_GREEN);



Per ultimo, stampiamo l’icona relativa alla condizione meteo. Useremo gli ID Icona che abbiamo ricavato dalla deserializzazione per richiamare la relativa icona contenuta nel file weathericons.h da stampare sul display. L’icona cambia in base al tempo previsto.


if (icon == "01d" || icon == "01n"){
tft.fillRect (0, 45, 52, 52, TFT_BLACK);
tft.drawBitmap(0, 45, sunny , 43, 43,TFT_WHITE); // soleggiato

}
else if (icon == "02d" || icon == "02n"){
tft.fillRect (0, 45, 52, 52, TFT_BLACK);
tft.drawBitmap(0, 45, partlysunny ,52, 36,TFT_WHITE); // parzialmente soleggiato

}
else if (icon == "03d" || icon == "03n"){
tft.fillRect (0, 45, 52, 52, TFT_BLACK);
tft.drawBitmap(0, 45, partlycloudy ,52, 34,TFT_WHITE); // parzialmente nuvoloso

}
else if (icon == "04d" || icon == "04n"){
tft.fillRect (0, 45, 52, 52, TFT_BLACK);
tft.drawBitmap(0, 45, cloudy ,47, 29,TFT_WHITE); // nuvoloso


}
else if (icon == "09d" || icon == "09n"){
tft.fillRect (0, 45, 52, 52, TFT_BLACK);
tft.drawBitmap(0, 45, rain ,46, 42,TFT_WHITE); // piovoso

}
else if (icon == "10d" || icon == "10n"){
tft.fillRect (0, 45, 52, 52, TFT_BLACK);
tft.drawBitmap(0, 45, rain ,46, 42,TFT_WHITE); // piovoso

}
else if (icon == "11d" || icon == "11n"){
tft.fillRect (0, 45, 52, 52, TFT_BLACK);
tft.drawBitmap(0, 45, tstorms ,46, 44,TFT_WHITE); // temporale

}
else if (icon == "13d" || icon == "13n"){
tft.fillRect (0, 45, 52, 52, TFT_BLACK);
tft.drawBitmap(0, 45, snow ,49, 39,TFT_WHITE); // nevoso

}
else if (icon == "50d" || icon == "50n"){
tft.fillRect (0, 45, 52, 52, TFT_BLACK);
tft.drawBitmap(0, 45, fog , 35, 32, TFT_WHITE); // nebbioso

}
else {
tft.fillRect (0, 45, 52, 52, TFT_BLACK);
tft.drawBitmap(0, 45, unknown, 32, 32, TFT_WHITE); // sconosciuto
}

Carichiamo lo sketch sulla ESP32 TTGO, selezionando la scheda TTGO LoRA32-OLED V1 dall’elenco delle schede. A questo punto apparirà la schermata con riportati in alto il nome della città e del Paese, l’indirizzo IP della scheda, al centro invece la temperatura, umidità, pressione, velocità del vento (con la sua icona) e le icone delle condizioni meteo (soleggiato, parzialmente soleggiato, parzialmente nuvoloso, nuvoloso, piovoso, nevoso, nebbioso, temperale e sconosciuto).

  • Mini stazione