
Le condizioni in una serra sono in continua evoluzione, ciò comporta la necessità di un attento monitoraggio. La crescita delle colture è determinata dai fattori ambientali all'interno della serra, che devono essere tenuti costanti tutto il giorno. I benefici di un sistema completamente automatizzato sono molti. Ovviamente, ci sarà una riduzione del lavoro manuale, ma molto più importante, si avrà la certezza di un miglioramento della qualità dei prodotti e possibilità di avere un database nel quale saranno raccolte molte informazioni. Ciò può fare la differenza tra guadagnare o subire perdite.Una serra domotica permette oltre all'automazione dell'ambiente, l'automazione della somministrazione di fertilizzanti e l'automazione di irrigazione. Inoltre, monitorando i fattori ambientali in modo real-time c'è la possibilità di avere un intervento immediato, evitando problemi alle colture. Ultima e non trascurabile caratteristica è quella di avere la possibilità di controllare tutto da casa dal proprio PC o Smartphone.
1. Dispositivi utilizzati
Facendo una prima overview del progetto è possibile dividere il tutto in tre parti fondamentali Master, Slave e Web Server, meglio descritte successivamente. Per quanto riguarda il Master è stato realizzato utilizzando un Arduino Uno, un modulo di trasmissione wireless 2.4GHz NRF24L01 e una shield wifi CC3000. Lo Slave invece utilizza lo stesso modulo di trasmissione NRF24L01, un sensore di umidità e temperatura DHT22 e la shield per il controllo di un motore brushed della Infineon.
Infine il Master comunica tramite wifi con un web Server dedicato al quale è possibile accedere tramite una app realizzata per Android.
1.1. Arduino UNO
Attualmente il progetto è ancora in fase di prototipazione, pertanto si è deciso di iniziare a sviluppare il tutto con il classico Arduino Uno. Il prossimo step sarà di utilizzare per gli Slave degli Arduino Nano o Mini e per il Master un Arduino Galileo che abbiamo a disposizione. La scelta di utilizzare Galileo è dovuta sia al fatto di poter disporre di una elevata potenza della scheda, che per gestire più Slave è necessaria, sia al vantaggio di poter utilizzare Linux. Pertanto Il progetto presentato qui è un primo step di controllo domotico di una serra, che poi andrà inevitabilmente potenziato.
1.2. Shield per controllo motore in DC Infineon
Grazie all’iniziativa di EMCelettronica ci è stato possibile utilizzare anche questa comodissima shield della Infineon per il controllo di un motore DC. In questa fase è stato utilizzato un motore recuperato da una vecchia stampante, quest’ultimo ci serve per aprire e chiudere una finestra della serra quando la temperatura è troppo elevata.
1.3. Misura temperatura e umidità ambientale
Per il controllo dei parametri ambientali è stato utilizzato un DHT22, che ci permette di avere una misura sia dell’umidità e sia della temperatura. Parametri che poi saranno trasmessi al Master che li invierà al Web Server. Non è stata effettuata una vera taratura di questa misura, ma semplicemente un confronto tra i valori ottenuti dal sensore e quelli ottenuti da un termometro e da un igrostato, essendo questi molto simili non è stata effettuata alcuna compensazione.
1.4. NRF24L01
Infine sono stati utilizzati due moduli NRF per la comunicazione wireless tra Master e Slave, per trasmettere le informazioni lette dal sensore (Slave to Master) e per trasmettere le nuove impostazioni fornite dall’utente (Master to Slave).
È stato formulato un semplice protocollo di comunicazione, per assicurare che i dati trasmessi fossero consegnati. Quanto detto avviene tramite un controllo effettuato sia dal Master che dallo Slave, ciò permette una elevata efficienza di comunicazione e comunque un basso costo computazionale.
2. Master
Di seguito è riportato il Flow Chart del programma:
Il Master è sempre in ascolto, appena ci sono dati disponibili li acquisisce e li stampa a video. Intanto verifica se sono presenti nuovi settaggi delle impostazioni da inviare allo Slave.
NB: il master invia le nuove impostazioni solo quando lo Slave gli invia le letture del sensore. Infatti, secondo il nostro protocollo è sempre lo Slave ad avviare la comunicazione.
Se sono presenti nuovi settaggi in lista, ne calcola prima il CRC a 8 bit, poi allega in coda alle impostazioni anche quest’ultimo, che servirà allo Slave per verificare se i dati ricevuti sono corretti o meno.
Fatto ciò il Master aspetta un’altra risposta dallo Slave per confermare la corretta ricezione dei dati. Se ciò non fosse, i dati non vengono cancellati ma restano in memoria e saranno inviati successivamente al prossimo contatto da parte dello Slave.
Infine ritorna nello stato iniziale di ascolto, per ricominciare un nuovo ciclo.
La funzione che calcola il CRC a 8 bit è un algoritmo basato sulle formule di Dallas – Maxim.
2.1. Comunicazione lato Master
Vediamo ora un po’ di codice, in questo paragrafo descriviamo i processi controllati dal Master:
while(!Mirf.dataReady()){
//Aspetto qualche informazione
}
Mirf.getData(data);
Serial.print("RAW DATA: ");
Serial.println((char*)data);
char* command = strtok((char *)data, ";");
int count = 0;
while (command != 0){
//Divido le informazioni
switch (count){
case 0:
snprintf(name, sizeof(name), "%s", command);
break;
case 1:
temp = atof(command)/10;
break;
case 2:
hum = atof(command)/10;
break;
}
command = strtok(0, ";");
count++;
}
Il while alla prima riga mette il Master in attesa, appena arriva un dato lo sketch prosegue. Con il Mirf.getData(data) acquisiamo il dato e lo salviamo in data, che è un vettore di tipo byte. Il dato ricevuto ha la seguente struttura “nome;temperatura;umidità”, lo salviamo in un puntatore a char e sfruttiamo alcune funzioni delle stringhe. Quella usata qua è stringtokenizer che ci permette di dividere il vettore ricevuto quando incontriamo appunto un token, nel nostro caso “;”. Il comando atof(x), ascii to float, ci permette di convertire x in un float. Il primo parametro ricevuto è il nome dello Slave che sta trasmettendo, gli altri due sono temperatura e umidità lette nella serra.
if(Serial.read() == 'k'){
Serial.println("Inserisci umidità max");
while (Serial.available() == 0);
humax = Serial.parseFloat();
Serial.flush();
Serial.println("Inserisci umididà min");
while (Serial.available() == 0);
humin = Serial.parseFloat();
Serial.flush();
Serial.println("Inserisci la temperatura max");
while (Serial.available() == 0);
tumax = Serial.parseFloat();
Serial.flush();
Serial.println("Inserisci la temperatura min");
while (Serial.available() == 0);
tumin = Serial.parseFloat();
Serial.print("Letto: ");
Serial.println(tumin);
Serial.flush();
}
E ancora:
Mirf.setTADDR((byte *)name);
snprintf(threshold, sizeof(toSend), "%s;%d;%d;%d;%d;%d", name, (int)humax, (int)humin, (int)tumax, (int)tumin, (int)crc);
Serial.print("Soglie: ");
Serial.println(threshold);
Mirf.send((byte *)threshold);
//Imposto un timeout oltre il quale stoppa la trasmissione
while(Mirf.isSending()){
}
Serial.println("Finished sending");
delay(10);
time = millis();
while(!Mirf.dataReady()){
if ( ( millis() - time ) > 1000 ) {
Serial.println("Timeout Setting parametri");
return;
}
}
Nella prima parte quando viene scritto il carattere “k” sulla seriale, il programma ci chiederà di inserire le nuove soglie minime e massime di umidità e temperatura che poi saranno inviate allo Slave.
Mentre nella seconda parte col comando snprintf(threshold, sizeof(toSend), "%s;%d;%d;%d;%d;%d", name, (int)humax, (int)humin, (int)tumax, (int)tumin, (int)crc) creiamo un vettore da inviare allo Slave, formato da il nome di chi trasmette, le soglie impostate e il CRC calcolato dal Master. Per comodità tutti parametri trasmessi sono trasformati in interi.
Nell’ultima parte è impostato un timeout per stoppare la trasmissione dopo un certo tempo.
2.2. Processi Master
Un controllo che effettua il Master è che la trasmissione sia andata a buon fine per fare ciò calcola il CRC.
Generalmente per verificare la bontà dei dati ricevuti si ricorre alle somme di controllo, quelle più semplici sono quelle algebriche che però hanno alcuni limiti. Pertanto si utilizzano algoritmi appositi, conosciuti con l’acronimo di CRC (Cyclic Redundancy Check). Questo sfrutta una rete logica, all’interno della quale vengono introdotti i dati che scorrono in un registro. Durante lo scorrimento, vengono prelevati e combinati fra loro dei bit da determinate posizioni del registro: il risultato di questa operazione viene combinato con il bit in ingresso. In questo caso è stato utilizzato un CRC8, ovvero si ha in uscita una somma ad 8 bit. Il codice è il seguente:
//Calcolo il CRC-8, mi creo quindi un array di byte
byte bhmax = (byte)humax;
byte bhmin = (byte)humin;
byte btmax = (byte)tumax;
byte btmin = (byte)tumin;
byte crc32_str[4] = {
bhmax, bhmin, btmax, btmin };
crc = CRC8(crc32_str);
Serial.println("CRC: ");
Serial.println(crc);
E ancora:
//Calcolo CRC-8 - algoritmo basato sulle formule di CRC-8 di Dallas/Maxim
byte CRC8(const byte *data) {
byte crc = 0x00;
while (*data) {
byte extract = *data++;
for (byte tempI = 8; tempI; tempI--) {
byte sum = (crc ^ extract) & 0x01;
crc >>= 1;
if (sum) {
crc ^= 0x8C;
}
extract >>= 1;
}
}
return crc;
}
3. Slave
Di seguito è riportato il Flow Chart del programma:
Inizialmente vengono effettuate tutte le inizializzazioni sia per i sensori sia per la comunicazione. Inizia quindi, l’acquisizione di umidità e temperatura del DHT22, ed inizia il timer per l’invio dei dati misurati. Non avendo una necessita di real time inviamo i dati ogni 10 secondi.
Pertanto verrà avviata la conversazione con il Master, una volta inviati i parametri lo Slave si mette in ascolto per ricevere eventuali impostazioni. Se così fosse acquisisce questo pacchetto, ne estrae le informazioni di cui ha bisogno e si calcola il CRC e verifica se è uguale a quello ricevuto dal Master. Se così fosse risponde con “OK”, altrimenti da “Errore”.
Intanto il microcontrollore continua a verificare se i parametri letti siano o meno all’interno delle soglie massime e minime. Agendo di conseguenza sugli attuatori, che in questo caso sono un motore che apre e chiude una finestra, una pompa per l’irrigazione ed un riscaldatore.
3.1. Processi Slave
Vediamo ora un po’ di codice, in questa paragrafo descriviamo i processi controllati dal Master:
//Gestisco l'umidificatore, il riscaldatore e la ventola in funzione delle soglie e dei valori letti
//Riscaldatore
if(myDHT22.getTemperatureC() >= tmax-1){
digitalWrite(RISCALDATORE, HIGH);
}
if(myDHT22.getTemperatureC() <= tmin+1){
digitalWrite(RISCALDATORE, LOW);
}
//Umidificatore
if((int)myDHT22.getHumidity() >= hmax-1){
digitalWrite(UMIDIFICATORE, HIGH);
}
if((int)myDHT22.getHumidity() <= hmin+1){
digitalWrite(UMIDIFICATORE, LOW);
}
//Aprire finestra
if(myDHT22.getTemperatureC() >= tmax+4){
duty_motor = 20;
analogWrite(IN_2, duty_motor);
delay(TCONST);
}
if(myDHT22.getTemperatureC() <= (tmax+tmin)/2 || finecorsa == LOW){
reset_ports();
duty_motor = 0;
analogWrite(IN_2, duty_motor);
delay(TCONST);
}
Controllo i parametri in serra e attivo o disattivo i vari attuatori, l'ultimo if mi attiva il motore con un duty del 20%. Dato che devo aprire e chiudere una finestra non ho bisogno di elevata velocità, ma di elevata coppia pertanto lavoro a duty fisso e basso.
Poi controllo che i dati vengano inviati ogni 10 secondi:
//Invio i parametri ogni 10 secondi
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
Mirf.setTADDR((byte *)"server");
snprintf(toSend, sizeof(toSend), "%s;%d;%d", name, (int)humidity, (int)temperature);
Serial.println(toSend);
Mirf.send((byte *)toSend);
//Imposto un timeout oltre il quale stoppa la trasmissione
while(Mirf.isSending()){
}
Serial.println("Finished sending");
delay(10);
while(!Mirf.dataReady()){
if ( ( millis() - time ) > 1000 ) {
return;
}
}
}
Ed infine controllo che il CRC ricevuto sia uguale a quello che mi calcolo ora:
Mirf.getData(data);
char* command = strtok((char *)data, ";");
int count = 0;
while (command != 0){
//Divido le informazioni
switch (count){
case 0:
snprintf(name, sizeof(name), "%s", command);
break;
case 1:
hmax = atof(command)/10; //atof(char* ) mi converte un tipo char* in double
break;
case 2:
hmin = atof(command)/10;
break;
case 3:
tmax = atof(command)/10;
break;
case 4:
tmin = atof(command)/10;
break;
case 5:
crc_ric = atoi(command);
break;
}
command = strtok(0, ";");
count++;
}
//Calcolo il CRC-8, mi creo quindi un array di byte
/********************************************************************************/
byte bhmax = (byte)hmax;
byte bhmin = (byte)hmin;
byte btmax = (byte)tmax;
byte btmin = (byte)tmin;
byte crc32_str[4] = {bhmax, bhmin, btmax, btmin};
crc = CRC8(crc32_str);
Serial.println("CRC: ");
Serial.println(crc);
/********************************************************************************/
//Controllo i dati ricevuti
/********************************************************************************/
if((byte)crc_ric == crc){
Serial.println("CONTROLLO DATI OK!");
Mirf.setTADDR((byte *)name);
Mirf.send((byte *)"OK");
}
else {
Serial.println("CONTROLLO DATI ERRORE!");
Mirf.setTADDR((byte *)name);
Mirf.send((byte *)"Errore");
}
/********************************************************************************/
Utilizzando il CRC si riesce con due sole trasmissioni a validare la bontà dei dati ricevuti.
3.2. Comunicazione lato Slave
La comunicazione lato Slave è molto semplice infatti quest'ultimo non fa altro che inviare le letture dei dati ogni 10 secondi e aspettare se il Master ha qualche impostazione da inviare.
//Invio i parametri ogni 10 secondi
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
Mirf.setTADDR((byte *)"server");
snprintf(toSend, sizeof(toSend), "%s;%d;%d", name, (int)humidity, (int)temperature);
Serial.println(toSend);
Mirf.send((byte *)toSend);
//Imposto un timeout oltre il quale stoppa la trasmissione
while(Mirf.isSending()){
}
Serial.println("Finished sending");
delay(10);
while(!Mirf.dataReady()){
if ( ( millis() - time ) > 1000 ) {
return;
}
}
}
while(!Mirf.dataReady()){
if ( ( millis() - time ) > 1000 ) {
return;
}
}
L'intera comunicazione dello Slave avviene in questa parte dello sketch.
4. Server
La componente Server del nostro progetto si occupa di ricevere ed immagazzinare le rilevazioni temporaneamente memorizzate sul dispositivo Master e di comunicare a quest’ultimo eventuali cambi di configurazione inoltrati dall’utente tramite App Mobile (Cap. 5). Si compone di una componente software Java e di un database di tipo MySQL.
Il server viene lanciato su una macchina dedicata e si predispone a ricevere pacchetti in entrata sia dal Master che da App Mobile. All’arrivo di un package per prima cosa ne analizza l’integrità tramite controllo CRC, poi ne analizza il mittente: se proviene da App Utente, quindi si tratta di un set di comandi da inviare al Master, lo aggiunge alla coda dei pacchetti in uscita e il flusso continua; se invece si tratta di un pacchetto in arrivo dal Master, viene estratta la parte delle rilevazioni e viene salvata in due tabelle del DB, una contenente i dati in formato ROW per eventuali analisi e un’altra contenente i dati strutturati tramite un parser dedicato pronti per la visualizzazione. Viene inviata poi una risposta al Master che indica l’avvenuta ricezione e che può quindi procedere a cancellare i suoi dati temporanei. Al termine della memorizzazione viene anche controllato se nella coda di pacchetti in uscita è presente un set di comandi da inviare al Master che ha appena comunicato, in tal caso invece della risposta OK viene inoltrato al Master il set di comandi, aspettando poi un OK da quest’ultimo per concludere il processo di comunicazione.
4.1 Comunicazione Server
Il Server riceve e inoltra pacchetti su protocollo TCP/IP istanziando un oggetto ServerSocket, secondo il seguente esempio:
String clientSentence;
String capitalizedSentence;
ServerSocket welcomeSocket = new ServerSocket(6789);
while(true)
{
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient =
new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
clientSentence = inFromClient.readLine();
System.out.println("Received: " + clientSentence);
…………………………..
}
Dopo aver costruito la risposta, viene inoltrata al mittente nel seguente modo
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
outToClient.writeBytes(response);
5. App Mobile
L’app mobile è l’interfaccia dell’utente per consultare i dati memorizzati sul Server ed effettuare eventuali cambi di configurazione al Master (soglie di umidità e temperatura, timeout, …..). Si compone di una app Android scritta in linguaggio Java.
L’App al suo avvio, mostra un menù tramite il quale è possibile visualizzare le rilevazioni memorizzate sul Server, indicando un range temporale o di sensori che si vuole visualizzare. Il risultato appare come grafico e mostra l’andamento temporale delle rilevazioni.
E’ inoltre possibile scegliere dal menu di effettuare il cambio dei parametri, in questo caso vengono mostrati a video le configurazioni attuali, al salvataggio viene inoltrato un pacchetto al Server che provvederà ad instradarlo al dispositivo Master.
5.1 Comunicazione App Mobile
La comunicazione della App Mobile verso il Server avviene su protocollo TCP/IP, con un meccanismo analogo a quello del server.
Conclusioni
Manca da sviluppare solo la comunicazione tra Master e Server.
L’idea che c’è dietro a questo progetto è quella di riportare l’agricoltura alla portata di tutti. Infatti disporre di un sistema di questo tipo, significa poter coltivare a casa tutto quello che si vuole riducendo di molto il tempo e la fatica da dedicarci.
Questo per ora è solo un prototipo semplice dell’idea che vogliamo sviluppare, ma la nostra intenzione era quella di trasmettere la nostra visione di agricoltura.
È possibile, con un sistema ben sviluppato risparmiare anche più del 30% delle risorse naturali, ciò consente sia di abbattere i costi e sia di ridurre l’impatto ambientale.
Antonio La Mura & Umberto Festa

Sarebbe interessante implementare questo splendido progetto con una Raspberry.
Ciao, infatti il passaggio successivo sarà proprio questo. Vogliamo portare il Master su Raspberry oppure su BeagleBone.
Bellissima idea e nobile filosofia che ne stà alla base ( e che condivido al 100%).
Concordo con Michele, il passo successivo è l’evoluzione su Raspberry ( o sistema embedded equivalente es. BeagleBone Black). A prima vista non sembra conveniente: una scheda che costa di più e che, essendo molto più performante, consuma più energia.
Analizzando il sistema però: con una scheda leggermente più costosa ma molto più potente, integreresti sia il master che il server web e senza fare stime da ragioniere avesti un sistema di pari consumo se non minore. Altro aspetto positivo, con il sistema così dimensionato, è la possibilità di arricchirlo di molte funzionalità solo con aggiunta di codice ( es. valutare e agire in base alle condizioni meteo reali o alle previsioni del tempo) e altre con la facile integrazione di altri sensori e periferiche ( pensiamo anche ad un monitor LCD per aver, all’occorrenza, le info sulla serra stessa, in tempo reale, visualizzate li, su ” campo ” ( battuta : ) ). Concludendo bella idea e con prospettive solo in crescita. Bravi!!!
Grazie mille per le belle parole, fa sempre piacere quando il proprio lavoro viene apprezzato e condiviso. Comunque questo è solo un prototipo noi stiamo continuando a lavorarci, speriamo di realizzare qualcosa di professionale.
Saluti,
Antonio
Curiosità …. può essere adatto per fare una incubatrice per uova avicole ?…volendo il motore è molto comodo come volta uova e se si aggiungono un paio di relè per riscaldatori e ventilazione … Credo proprio sia un’ ottima cosa per molti appassionati !!!
Saluti a tutti !
Grazie per gli spunti !!!
Ciao noi abbiamo lavorato ad una cosa del genere. Se sei interessato mi puoi contattare in privato. Grazie per l’interesse.
Grazie , si poiché in giro esistono molte incubatrici, ma hanno costi che non vorrei assumere…considerato che schede e sensori ne ho….mi sembra quasi d’obbligo applicarmi a modo… se mi potete o puoi aiutarmi, grazie SI , accolgo di buon grado !!
Se mi mandi il tuo contatto replico a breve !!!
Grazie !!!
Saluti a tutti !!!
La mia mail è [email protected] ?
Comunque stiamo continuando con la serra, abbiamo aggiunto un altro pezzo. Puoi vedere qui:
http://cormaz.altervista.org/index.php/blog-fire-garden/11-greenhouse
Caspita !!! Complimentissimi !! il mio orto a confronto è Una Cassetta della verdura…. ;-)) cmq… il progetto che avete avviato mi interessa ,poiché è versatile e permette di avere una cronologia de gli eventi che da dei feedback utili e adeguatamente precisi…
saluti !!!
Bellissimo progetto! Si potrebbe pensare ad una qualche integrazione con il nostro framework domotico open source freedomotic.com in modo da eseguire delle automazioni in base ai parametri letti dai sensori tipo: se la temperatura/umidità è maggiore/minore di una certa soglia esegui una certa azione e cose del genere anche interagendo con altri sistemi.
Grazie per la condivisione.
Ciao, potremmo sentirci in privato.
Ho lasciato la mia mail in qualche commento precedente 🙂
Comunque noi abbiamo continuato a migliorare il nostro progetto, partecipano anche al contest “World’s Largest Arduino Maker Challenge” indetto da Arduino in collaborazione con Microsoft.
Ti posto il progetto che abbiamo presentato:
https://www.hackster.io/cormaz/domotic-greenhouse-71573f
Spero di non violare nessuna regola.
Avevo visto e “rispettato” il progetto su hackster. Volevo lasciare un commento in quella sede ma credo che siano disabilitati.
Comunque posso mandarti una mail in privato.
Grazie
Ok, con piacere allora a presto!
Ciao Antonio, giusto per dirti che ti ho mandato un paio di mail (una più di un mese fa) senza ricevere risposta. Forse l’indirizzo riportato nel commento è sbagliato.