Come realizzare un server web per visualizzare i dati di una stazione meteo
Grazie all’avvento di Internet, è diventato ormai semplice poter visualizzare le previsioni meteo e l’attuale situazione meteorologica. Nella rete sono presenti tanti siti web che permettono di visualizzare tali valori e la maggior parte di essere risulta essere attendibile e semplice da usare.
Previsioni meteo, tratti dal sito ilmeteo.it
Tuttavia il detto “chi fa da se fa per tre” mi ha portato a realizzare un servizio web, per trasformare alcuni dispositivi in una stazione meteo professionale. Alla fine dell’installazione di tutti i componenti sarà possibile accedere ad una pagina web, nella quale saranno presenti i valori di temperatura e umidità attuali, giornalieri e alcuni statistiche, come ad esempio la temperatura massima e minima registrata nei vari giorni.
Requisiti per il progetto
Hardware
-
2 Arduino UNO
-
1 x kit di sensori Wireless 433 Mhz
-
1 x DHT22
-
2 x Breadboard per installare i dispositivi
-
Un po’ di cavi flessibili
-
1 x PC come basi di dati e server (consiglio caldamente di utilizzare un Raspberry PI, oppure un UDOO)
Software
-
I miei codici, disponibili nella repo di Github
-
Queste librerie per Arduino DHT22, MYSQL, VirtualWire, SendData
-
MySQL Workbench
-
Tasksel (software che includi ottimi servizi lato server, come PHPMyAdmin, Apache e tanto altro)
Sommario del progetto
Ora vedremo in dettaglio tutti i componenti che sono utilizzati in questo progetto.
Come viene letta la temperatura
Uno dei principali componenti per realizzare una qualsiasi stazione meteo è un trasduttore in grado di leggere la temperatura e l’umidità.
Un trasduttore/sensore non è altro che un dispositivo elettrico in grado di trasformare una grandezza fisica quale la temperatura, in una grandezza elettrica, cioè un valore di tensione, oppure di corrente. La grandezza elettrica, verrà tratta successivamente a seconda che l’uscita del sensore sia analogica, oppure digitale, cioè una corrispondenza di 0 e 1. Facciamo un piccolo esempio;
Dati Numero di bit = 10; Vcc = 5 V GND = 0 V
Se il numero di bit è pari a 10, è possibile rappresentare valori che vanno da 0 a 2^10-1, cioè fino a 1023. Qualora venga letto un valore, per esempio con Arduino, pari a 512, per calcolare la tensione effettiva che riceve il microcontrollore, occorre fare il seguente calcolo:
V_IN = 512/1024 * 5 [V] = 2.5 [V]
Se per esempio, il nostro trasduttore è stato modellizzato in modo tale da fornire un valore di tensione proporzionale alla temperatura, come ad esempio V_OUT = 0.1* temperatura, se ci sono 25 gradi, l’uscita sarà pari a 0.1*25 = 2.5 V e quindi Arduino avrà un valore in lettura pari proprio a 512.
Ovviamente questo esempio semplifica abbastanza le dinamiche di funzionamento di un trasduttore per temperature. Tale trattazione non è troppo importante a fini di realizzare il progetto; serve solo come conoscenza personale.
Come già utilizzato nei progetti precedenti, anche in questo caso verrà utilizzato un trasduttore di temperatura e umidità molto semplice, quale il DHT22. Esso è facilmente acquistabile su Ebay, al costo di qualche Euro.
La modellizzazione del dispositivo è già stata fatta e quindi per poterlo usare all’interno dei nostri codici, è necessario solamente scaricare la relativa libreria.
Come indicato all’interno della documentazione, per poter leggere un valore di temperatura corretto è necessario inserire una resistenza da 10 KOhm in pull up tra l’alimentazione Vcc e il pin di uscita, come riportato il figura.
Come ogni componente presente in un progetto, conviene testare la lettura della temperatura, attraverso questo semplice codice:
// Programma che permette di leggere la temperatura, attraverso un sensore #include "DHT.h" #define DHTPIN 2 // Il pin a cui è collegato il sensore // Togli il commmento al sensore che vuoi usare //#define DHTTYPE DHT11 // DHT 11 #define DHTTYPE DHT22 // DHT 22 (AM2302) //#define DHTTYPE DHT21 // DHT 21 (AM2301) // Connettere il pin 1 (a sinistra) a +5V // Connettere il pin 2 del sensore alla porta 2 // Connettere il pin 4 (a destra) del sensore a GROUND // Connettere una resistenza da 10K tra il pin 2 (data) e il pin 1 (power) del sensore DHT dht(DHTPIN, DHTTYPE); voidsetup() { Serial.begin(9600); Serial.println("DHTxx test!"); dht.begin(); } voidloop() { // Legge la temperatura e l'umidità ogni 250 millisecondi! // Vengono inizializzate le variabili in cui vengono scritti i valori letti floath = dht.readHumidity(); floatt = dht.readTemperature(); // Controlla se la lettura è andata a buon fine if(isnan(t) || isnan(h)) { Serial.println("Failed to read from DHT"); } else{ Serial.print("Humidity: "); Serial.print(h); // Stampa nel seriale la percentuale dell'umidità Serial.print(" %t"); Serial.print("Temperature: "); Serial.print(t); // Stampa nel seriale il valore della temperatura Serial.println(" *C"); } }
Come vengono inviati i valori di temperatura e umidità tra i dispositivi
L’altro aspetto sempre legato alla temperatura, è l’invio dei dati tra l’Arduino che viene collegato all’interno dell’abitazione e quello posto all’esterno. Il fatto di dover utilizzare due dispositivi, è dovuto al semplice fatto che tipicamente non si dispone di una prese Ethernet esterna e una scheda Wireless ha un costo abbastanza elevato. Per questo motivo conviene utilizzare i due dispositivi e farli comunicare tra di loro attraverso un kit wireless, che funziona sulla frequenza 433 Mhz. Tali dispositivi sono già stati trattati in passato e per ulteriori informazioni, vi invito a guardare questo articolo, presente sul mio blog.
Il collegamento dei PIN dei dispositivi wireless è riportato in figura.
Se abbiamo correttamente collegato tutti i dispositivi, potremmo inviare i valori di temperatura e umidità tra l’Arduino posto fuori casa e quello che è presente in casa, nel quale sarà presente una scheda Ethernet Shield, che gli permetterà di collegarsi ad Internet ed inviare i dati letti.
Il programma da caricare sull’Arduino client è:
#include "DataCoder.h" #include "VirtualWire.h" #include "DHT.h" #define DHTPIN 2 #define DHTTYPE DHT22 int transmit_pin = 12; int led_pin = 13; int baudRate = 800; int delayTime = 30000; DHT dht(DHTPIN, DHTTYPE); void setup() { pinMode(led_pin,OUTPUT); Serial.begin(9600); SetupRFDataTxnLink(transmit_pin, baudRate); dht.begin(); } void loop() { float outArray[2]; float h = dht.readHumidity(); float t = dht.readTemperature(); outArray[0] = t; outArray[1] = h; union RFData outDataSeq; EncodeRFData(outArray, outDataSeq); TransmitRFData(outDataSeq); delay(delayTime); }
In questo codice è possibile modificare il tempo che trascorre tra l’invio di dati.
Il programma da caricare sull’Arduino server è:
/* This code allow Arduino to send the value of temperature and humidity to a DB, everty portion of time, setted by the user. The data of temperature come from an Arduino via wireless, so one Arduino can stay outside, and the other one can stay in the home Version 1.0 Author Giacomo Bellazzi Copyright (C) 2014 Giacomo Bellazzi (http://ismanettoneblog.altervista.org/) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <SPI.h> #include <Ethernet.h> #include <sha1.h> #include <mysql.h> #include <avr/dtostrf.h> #include <DataCoder.h> #include <VirtualWire.h> const int rx_pin = 11; // the Pin of the RX const int baudRate = 800; byte mac_addr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress server_addr(192,168,1,20); // MySQL Server IP char user[] = "username"; char password[] = "password"; Connector my_conn; // The Connector/Arduino reference const char INSERT_DATA[] = "INSERT INTO WeatherStation.Data VALUES (1,%s,%s,CURRENT_DATE,CURRENT_TIME)"; void setup(){ Ethernet.begin(mac_addr); //Serial.begin(9600); for DEBUG Serial.println("Connecting..."); SetupRFDataRxnLink(rx_pin, baudRate); if (my_conn.mysql_connect(server_addr, 3306, user, password)) { delay(1000); } else Serial.println("Connection failed."); } void loop(){ uint8_t buf[VW_MAX_MESSAGE_LEN]; uint8_t buflen = VW_MAX_MESSAGE_LEN; union RFData inDataSeq;//To store incoming data float inArray[2];//To store decoded information if(RFLinkDataAvailable(buf, &buflen)) { for(int i =0; i< buflen; i++) { inDataSeq.s[i] = buf[i]; } DecodeRFData(inArray, inDataSeq); float temperature = inArray[0]; float humidity = inArray[1]; //DEBUG //Serial.println("Temperature: "); //Serial.print(temperature); //Serial.print(" ° Humidity: "); //Serial.println(humidity); sendToDB(inArray[0],inArray[1]); } } // This code send the values of the temperature and humidity to the DB void sendToDB(float temperature,float humidity){ char query[64]; char t[6]; char h[6]; dtostrf(temperature, 1, 2, t); dtostrf(humidity, 1, 2, h); sprintf(query, INSERT_DATA, t,h); my_conn.cmd_query(query); }
Sarà necessario inserire/modificare i dati, quali IP, username e password della propria base di dati (vedi pagine successive).
Come vengono salvati i valori registrati
Un aspetto importare in questo progetto è il salvataggio dei dati che vengono letti dall’Arduino, sfruttando il sensore di temperatura DHT22. Infatti, se non fosse presente un dispositivo in grado di poter salvare i dati, non sarebbe possibile recuperare tali valori in futuro.
Per questo motivo, in questo progetto, viene utilizzata come base di dati un server MySQL. Il motivo di utilizzare questo sistema è che esso è relativamente facile da usare ed ad installare.
Facciamo una breve introduzione a MySQL; esso un sistema basato sull’Algebra relazionale, che non è altro che un insieme di regole, che permettono di mettere in relazione tra di loro dati.
Facciamo un breve esempio; per una persona è normale ipotizzare, come dati, il suo nome, cognome, codice fiscale, città di nascita. Quindi si potrebbe rappresentare in questa tabella i dati:
Codice Fiscale |
Nome |
Cognome |
Città di Nascita |
ABCDEFG |
Paolo |
Rossi |
Milano |
Si potrebbe approssimare, per semplicità, che è possibile creare uno schema della propria base di dati, sfruttando questa tabella, mantenendo come attributi, i valori in grassetto. Occorre notare che, per come è stato realizzato il codice fiscale, esso viene definito una chiave primaria nella relazione Persona, dal momento che non esistono due persone diverse, con lo stesso codice fiscale.
Per una trattazione più ampia di MySQL e dell’Algebra relazione, è possibile leggere il seguente articolo.
Come poter visualizzare i dati salvati ed effettuare richieste
Il passo successivo è quello di creare uno schema corretto per il nostro progetto. Questa operazione, richiede di tradurre le notazioni riguardo alla temperatura, in Algebra relazione. Per esempio, quali sono gli attributi relativi alla misura di una temperatura ? Per esempio potrebbero essere il valore della temperatura, dell’umidità, l’ora e la data di registrazione. Se però avessimo più dispositivi, sparsi per esempio in varie città d’Italia, come possiamo fare ? La soluzione più semplice è quella di usare un ID, che identifica ogni stazione meteo.
Ricapitolando avremmo questa relazione, che ho chiamata Data, all’interno dello schema WeatherStation:
ID |
Temperature |
Humidity |
Date |
Time |
Ogni stazione meteo, ha però altre informazioni, più statiche, come ad esempio il luogo in cui è installata. Per questo motivo è necessario creare una seconda relazione, che contiene quelle informazioni.
Per poter creare una base di dati è necessario installare il pacchetto MySQL server su un PC (meglio su UDOO oppure Raspberry ) e un programma client, chiamato MySQL Workbench, poter effettuare query ed impostare lo schema della base di dati.
idDevice |
Town |
Location |
Installazione Tasksel
Spesso si pensa che dover installare programmi specifici su piattaforme Linux sia difficile; in realtà non c’è cosa più semplice !!! Infatti per poter installare il server MySQL, il server Apache server lanciare da terminare, la seguente linea di comando:
|
Ora basterà seguire l’installazione guidata, premendo invio quando richiesto. L’installazione completa è quella del Lamp server, che consiglio di fare. Per trovare la procedura di installazione completa, basta dare un’occhiata alla pagina ufficiale di UDOO
http://www.udoo.org/ProjectsAndTutorials/udoo-web-server/
Una volta completa la procedura, è necessario installare il client di MySQL; esso è disponibile nelle principali piattaforme ed è possibile scaricarle dal seguente link http://www.mysql.it/products/workbench/
Realizzazione basi di dati
Come discusso in precedenza, per salvare i dati è necessario/conveniente usare un DB MySQL. Nel passo precedente è stato installato il server MySQL, sfruttando l’installazione automatica con tasksel. Durante tale installazione è stata impostata una password di root per gestire il DB.
Per poter accedere anche da remoto al server, è necessario effettuare una piccola modifica al file /etc/mysql/my.cnf, in particolare alla riga relativa a bind-address:
bind-address = 0.0.0.0
In questo modo sarà possibile accedere alla base di dati anche da remoto, effettuando il port-forwarding delle porta 3306 sul proprio router.
Per creare lo schema della stazione meteo, come indicato precedente, occorre selezionare la voce
“Create new schema” e chiamarlo con il nome WeatherStation. Da qui sarà necessario creare due tabelle, una con il nome Data e una chiamata Device. La prima e la seconda dovranno avere i seguente attributi, con i relativi tipi:
Ora che abbiamo creato il nostro schema, è possibile effettuare alcune query, che non sono altro che interrogazioni, per visualizzare certi valori, come ad esempio il valore massimo e minimo di temperatura in un certa giornata, i valori di temperatura in certe ore etc…
Ecco alcuni esempi utili:
Ultimo aggiornamento Select * From Data WHERE Hour(Time)=HOUR(Current_TIME) && Minute(Time)=MINUTE(Current_Time)-1 Dati della giornata Select * From WeatherStation.Data Where Date = CURRENT_DATE && Minute(WeatherStation.Data.Time)=00 Order by Time Valori Max e Min per giornata Select Max(Temperature),Min(Temperature), Max(Humidity), Min(Humidity), Date From Data Group by date
Caricamento file PHP sul server
Ultimo passaggio che ci rimane è quello di creare una pagina web, dalla quale sarà possibile visualizzare i valori valori raccolti e le relative interrogazioni che desideriamo.
Per poter interrogare facilmente un DB da una pagina WEB, è necessario utilizzare un linguaggio lato server che si chiama PHP. Esso un linguaggio abbastanza standard da usare e comprendere; l’unica nota utile da fare è che tutte le variabili in PHP sono indicate con $nome_variabile = .
Ho realizzato, per semplice comodità, alcune pagine PHP utili per la stazione meteo.
Sono già pronte all’uso, a patto di modificare il file mysql.php, che contiene i dati d’accesso al database. I file PHP sono reperibili all’interno della cartella PHP, che è presente nella repo di Github.
Le operazioni da fare per il progetto sono:
-
Installare il codice di Arduino per il client, che contiene il DHT22
-
Installare il codice di Arduino per il server, a cui è connessa la scheda Ethernet
-
Installare su PC/Raspberry/UDOO i componenti MySQL server, Apache etc…
-
Creare lo schema del DB
-
Caricare le pagine WEB PHP nella cartella WWW del server