MyLegalPlants | IoT Project | v1

MyLegalPlants è un progetto di Internet delle Cose (IoT) per il controllo dello stato dell’ambiente di coltivazione di piante o per applicazioni in agricoltura in generale.

Il sistema utilizza tecnologie Arduino MKR1000Php e MySQLWeb App e Telegram Bots.
L’ambiente è monitorato da Sensori che ne rilevano le caratteristiche fisiche, come umidità del terrenotemperaturailluminazione, e vengono utilizzati da Arduino per una lettura periodica dei valori. Tali valori vengono memorizzati in modo centralizzato su DataBase MySQL installato sul Server Web.
La visualizzazione di tali valori viene effettuata tramite WebApp oppure possono essere richiesti tramite messaggio Telegram.
Le condizioni ambientali possono essere modificate da un Sistema di IrrigazioneIlluminazione o Riscaldamento controllato dall’MKR1000 e comandato da WebApp o con messaggistica Telegram.

Il sistema è espandibile nella tipologia di caratteristiche controllate e adattabile a qualunque controllo IoT.

Hardware

L’hardware realizzato prevede l’interfacciamento ed il condizionamento dei segnali forniti dai sensori (Temperatura, Umidità, Intensità luminosa), e l’azionamento ed il controllo degli attuatori (Riscaldatore, Irrigatore, Lampada) per la modifica delle condizioni ambientali.
I sensori sono l’LM35 per rilevare la temperatura dell’ambiente, un igrometro Wire TE215 per la misura dell’umidità del terreno e una fotoresistenza per la lettura dell’intensità luminosa presente.
Gli attuatori consistono in una Lampada ad Infrarossi per il riscaldamento, in una Pompa DC per il flusso dell’acqua per l’irrigazione e una lampada Led per l’illuminazione.
Sulla scheda alloggiano due Arduino MKR1000 destinati al controllo del sistema (WebApp, Messaggi Telegram).

 

 

Il Web Server

Sito internet (www.mylegalplants.it) e Database MySQL sul quale vengono memorizzati i valori di sensori ed attuatori in modo centralizzato tra i due Arduino MKR1000, sono installati su Web Server Linux.

I microcontrollori, connessi a Internet tramite scheda WiFi, utilizzano files php per effettuare le query al database attraverso le quali leggere o scrivere i valori dei sensori e attivare gli attuatori.

Tali files utilizzano per la connessione al DB un file db_config.inc.php come include all’interno dei files php, contenente le variabili:
$hostname = “host server”;
$username = “db user”;
$password = “password”;
$db = “db name”;

 

La Web App

Per il controllo del sistema è stata prevista una WebApp che visualizza, attraverso indicatori Gauge realizzati in Javascript, il vaolre delle grandezze fisiche monitorate.

La App incorpora anche i pulsanti per la attivazione degli attuatori, graficamente modificati attraverso CSS.

Compito della WebApp è la visualizzazione e/o la scrittura dei valori dei sensori e lo stato degli attuatori sul Database.
La struttura logica dell’App prevede interrogazioni al DB cicliche (ogni 3 sec) attraverso HttpRequest JS utilizzando i files php. Al risultato delle interrogazioni vengono dinamicamente aggiornati i valori visualizzati dagli indicatori e le immagini dei pulsanti se lo stato dell’attuatore è stato modificato esternamente per altre vie (come Telegram Bots).

 

Telegram Bots

Il progetto prevede l’utilizzo anche della messaggistica Telegram per la gestione della pianta.
Questo è possibile grazie ai Bots messi a disposizione da Telegram LLC, che possono essere utilizzati per passare parametri alle applicazioni che li utilizzano.

Una volta realizzato l’account bot, e ottenuto il Token univoco, attraverso una specifica libreria per Arduino è possibile interagire con esso attraverso messaggi, che vengono inviati attraverso la Telegram.

 

Microcontrollore Arduino

Tutto il sistema si basa sulla funzionalità dell’Arduino MKR1000, che integra una scheda WiFi con la quale può collegarsi alla rete.
Nel progetto sono utilizzate due schede MKR1000, una interfacciata con la WebApp, che ha anche la gestione HW di sensori e attuatori, e la seconda dedicata all’utilizzo del Bot di Telegram.

Programma gestione webApp e HW:
La connettività WiFi dell’MR1000 viene utilizzata per realizzare un Client che periodicamente (nel caso 3 sec) fa una richiesta httpRequest al Server al quale invia i valori acquisiti dai sensori e dal quale preleva i valori dello stato degli attuatori settati dalla WebApp o Telegram.


#include 
#include 
#include "floatToString.h"
 
char ssid[] = "ssid_rete"; // network SSID
char pass[] = "password_rete"; // network password

int status = WL_IDLE_STATUS;

// vars sensori T, H, L 
float acq_T = 0.00;
float acq_H = 0.00;
float acq_L = 0.00;
float t_value = 0.00;
float h_value = 0.00;
float l_value = 0.00;
char t_char[5], h_char[5], l_char[5];
String t_string, h_string, l_string;
// pins Attuatori
const int pinAttuatore_T = 10; //led Verde -> Uscita RISCALDATORE
const int pinAttuatore_H = 9; //led Giallo -> Uscita IRRIGATORE
const int pinAttuatore_L = 8; //led Rosso -> Uscita ILLUMINAZIONE

const int LED = 6;

//vars per lettura risposta server
String risposta = "";
int risposta_length;
int int_risposta_T;
int int_risposta_H;
int int_risposta_L;

// server address:
char server[] = "mylegalplants.it";

unsigned long lastConnectionTime = 0;             // ultima volta che ci si è connessi al server, in millisecondi
const unsigned long postingInterval = 3L * 1000L; // ritardo tra le ripetizioni, in millisecondi

unsigned long inizioIrrigazione = 0;               // in millisecondi
const unsigned long tempoIrrigazione = 10L * 1000L; // ritardo durata irrigazione, in millisecondi

// Inizializzazione Wifi client library
WiFiClient client;

void setup() {
  // output
  pinMode(pinAttuatore_T, OUTPUT);
  pinMode(pinAttuatore_H, OUTPUT);
  pinMode(pinAttuatore_L, OUTPUT);

  pinMode(LED, OUTPUT);

  Serial.begin(9600);
  // creazione connessione alla rete
  NetworkConnection();
  // stampa stato connessione
  printWifiStatus();
}

void loop() {
  // lettura Sensori
  acq_T = analogRead(A1); // T
  t_value = (acq_T/1023)*330; // converto il valore di acq_T (0-1023) in °C sapendo che Vref=3,3v -> 330°C
  floatToString(t_char, t_value, 2);
  t_string = t_char;
  acq_H = analogRead(A2); // H
  h_value = (acq_H/1023)*180; // converto il valore di acq_H (0-1023) in %H sapendo che in H2o acq_h=180 -> 100%H
  floatToString(h_char, h_value, 2);
  h_string = h_char;
  acq_L = analogRead(A3); // L
  l_value = (acq_L/1023)*6500; //nverto il valore di acq_L (0-1023) in LUX sapendo che acq_l=740 -> 4700 lux
  floatToString(l_char, l_value, 2);
  l_string = l_char;
  
  // quando ci sono dati provenienti dalla connessione
  while (client.available()) {
    char c = client.read(); //caratteri restituiti dal server
    //-------- Leggo i valori degli Attuatori dalla risposta dell'HTML request
    String txt =  String(c);
    risposta += txt; //faccio il concatenamento dei vari caratteri usciti dal server
    // Length (ha in più il carattere 'null terminator', perciò sottraggo 1)
    risposta_length = risposta.length() - 1;
  }
  if(risposta != "" && (int(risposta[risposta_length-4])-48==1 || int(risposta[risposta_length-4])-48==0)){ 
    //elimino tutte le risposte nulle o che non contengono i valori di T, H e L
    int_risposta_T = int(risposta[risposta_length-4])-48; // sottraiamo 48 per passare da ASCII a intero
    int_risposta_H = int(risposta[risposta_length-2])-48;
    int_risposta_L = int(risposta[risposta_length])-48;

    // Set attuatore T
    if(int_risposta_T==1) digitalWrite(pinAttuatore_T, HIGH);
    if(int_risposta_T==0) digitalWrite(pinAttuatore_T, LOW);
    // Set attuatore H
    if(int_risposta_H==1) temporizza_H();
    if(int_risposta_H==0) digitalWrite(pinAttuatore_H, LOW);
    // Set attuatore L
    if(int_risposta_L==1) digitalWrite(pinAttuatore_L, HIGH);
    if(int_risposta_L==0) digitalWrite(pinAttuatore_L, LOW);
  }
  risposta = "";

  // se sono passati 3 sec dall'ultima connesione,
  // ci riconnettiamo al server per una nuova richiesta
  if (millis() - lastConnectionTime > postingInterval) {
    httpRequest();
  }
  verificaStatoConnessione();
}

// connessione alla rete WIFI
void NetworkConnection() {
// attesa per la connessione Wifi
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
    // ritardo di 10 sec per permettere la connessione iniziale alla rete Wifi:
    delay(10000);
  }
}

// verifica stato connessione WIFI
void verificaStatoConnessione() {
  if(WiFi.status() == WL_CONNECTED){
    //Serial.println("WL_CONNECTED");
  }
  else if(WiFi.status() == WL_CONNECTION_LOST){
    //Serial.println("WL_CONNECTION_LOST");
    NetworkConnection();
  }
  else if(WiFi.status() == WL_DISCONNECTED){
    //Serial.println("WL_DISCONNECTED");
    NetworkConnection();
  }
  else {
    Serial.print("Status = ");
    Serial.println(WiFi.status());
  }
}

// Print Stato WIFI 
void printWifiStatus() {
  // stampa SSID della rete Wifi
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // stampa IP della scheda Wifi dell'Arduino MKR1000
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // stampa il valore dell'intensità del segnale Wifi
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

// questo metodo crea una connessione al server tramite httpRequest
void httpRequest() {
  // chiudiamo le precedenti connessioni e creiamo la nuova
  // liberando il socket nel WiFi
  client.stop();
  digitalWrite(LED, LOW);

  // se la connessione ha successo
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    digitalWrite(LED, HIGH);
    // invio HTTP request al file http://www.mylegalplants.it/web_app/inserisci_valori.php?...
    client.print("GET /web_app/inserisci_valori.php?");
    client.print("T=");
    client.print(t_string);
    client.print("&H=");
    client.print(h_string);
    client.print("&L=");
    client.print(l_string);
    client.println(" HTTP/1.0");
    client.println("Host: mylegalplants.it");
    client.println("Connection: close");
    client.println();

    // memorizziamo il momento della connessione
    lastConnectionTime = millis();
  }
  else {
    // se la connessione fallisce
    Serial.println("connection failed");
    digitalWrite(LED, LOW);
    // ripetiamo l'accesso alla rete
    //NetworkConnection();
  }
}

// Temporizzazione dell'irrigazione
void temporizza_H(){
  Serial.println("temporizza_H");
  // setto l'inizio dell'irrigazione
  inizioIrrigazione = millis();
  digitalWrite(pinAttuatore_H, HIGH);
  while(millis() - inizioIrrigazione < tempoIrrigazione){
    ;
  }
  digitalWrite(pinAttuatore_H, LOW);
  httpRequest_H("0");
 
}
void httpRequest_H(String H) {
  // chiudiamo le precedenti connessioni e creiamo la nuova
  // liberando il socket nel WiFi
  client.stop();
  digitalWrite(LED, LOW);

  // se la connessione ha successo
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    digitalWrite(LED, HIGH);
    // invio HTTP request al file http://www.mylegalplants.it/web_app/attiva_H.php?...
    client.print("GET /web_app/attiva_H.php?");
    client.print("&H=");
    client.print(H);
    client.println(" HTTP/1.0");
    client.println("Host: mylegalplants.it");
    client.println("Connection: close");
    client.println();

    // memorizziamo il momento della connessione
    lastConnectionTime = millis();
  }
  else {
    // se la connessione fallisce
    Serial.println("connection failed");
    digitalWrite(LED, LOW);
    // ripetiamo l'accesso alla rete
    //NetworkConnection();
  }
}

Programma gestione Telegram Bots e DB:
Questo secondo Arduino MKR1000 si occupa della messaggistica Telegram, rispondendo, a richiesta, sul valore dei valori acquisiti dai sensori e modificando sul server lo stato degli attuatori di controllo delle condizioni ambientali, se riceve messaggi di modifica.

I messaggi accettati sono:
– “Sensori” -> Risponde con il valore di tutti i sensori
– “T” -> Risponde con il valore della Temperatura
– “H” -> Risponde con il valore dell’Umidità del terreno
– “L” -> Risponde con il valore della Intensità luminosa
– “Accendi Riscaldatore” -> Attiva Riscaldatore
– “Spegni Riscaldatore” -> Disattiva Riscaldatore
– “Accendi Irrigazione” -> Attiva Pompa irrigazione
– “Spegni Irrigazione” -> Disattiva Pompa irrigazione
– “Accendi Luce” -> Attiva Lampada di illuminazione
– “Spegni Luce” -> Disattiva Lampada di illuminazione


#include 
#include   
#include 
#include "floatToString.h"

char ssid[] = "ssid_rete"; // network SSID
char pass[] = "password_rete"; // network password

// Initialize Telegram BOT
const char BotToken[] = "bot_token"; 

int status = WL_IDLE_STATUS;

// vars sensori T, H, L 
float acq_T = 0.00;
float acq_H = 0.00;
float acq_L = 0.00;
float t_value = 0.00;
float h_value = 0.00;
float l_value = 0.00;
char t_char[5], h_char[5], l_char[5];
String t_string, h_string, l_string;

int LED_connection = 6;

// server address:
char server[] = "url_server";

WiFiClient client; // per inviare richieste DB da modifiche Telegram
WiFiSSLClient clientBot;
TelegramBot bot(BotToken, clientBot);

void setup() {
  Serial.begin(9600);
  // creazione connessione alla rete
  NetworkConnection();
  // stampa stato connessione
  printWifiStatus();
  // Telegram connection
  bot.begin();

  // output
  pinMode(LED_connection, OUTPUT); // LED test connessione
}

void loop() {

  // lettura Sensori e conversioni valori
  // ---------------------------------------
  acq_T = analogRead(A1); // T
  t_value = (acq_T/1023)*330; // converto il valore di acq_T (0-1023) in °C sapendo che Vref=3,3v -> 330°C
  floatToString(t_char, t_value, 2);
  t_string = t_char;
  acq_H = analogRead(A2); // H
  h_value = (acq_H/1023)*180; // converto il valore di acq_H (0-1023) in %H sapendo che in H2o acq_h=180 -> 100%H
  floatToString(h_char, h_value, 2);
  h_string = h_char;
  acq_L = analogRead(A3); // L
  l_value = (acq_L/1023)*6500; //nverto il valore di acq_L (0-1023) in LUX sapendo che acq_l=740 -> 4700 lux
  floatToString(l_char, l_value, 2);
  l_string = l_char;


// Gestione Telegram Bots 
// ---------------------------------------
  message m = bot.getUpdates(); // Read new messages  
  if (m.text.equals("T")) {       // leggo T
    Serial.print("T = ");  
    Serial.println(t_value); 
    bot.sendMessage(m.chat_id, "T = "+t_string+"°C");  
  }  
  else if (m.text.equals("H")) {  // leggo H
    Serial.print("H = ");  
    Serial.println(h_value); 
    bot.sendMessage(m.chat_id, "H = "+h_string+"%");  
  }
  else if (m.text.equals("L")) {  // leggo L
    Serial.print("L = ");  
    Serial.println(l_value); 
    bot.sendMessage(m.chat_id, "L = "+l_string+"lux");  
  }
  else if (m.text.equals("Sensori")) {   // leggo tutti i sensori
    Serial.print("T = ");  
    Serial.println(t_value); 
    Serial.print("H = ");  
    Serial.println(h_value);
    Serial.print("L = ");  
    Serial.println(l_value);
    bot.sendMessage(m.chat_id, "T="+t_string+"°C - H="+h_string+"% - L="+l_string+"lux");  
  }
  else if (m.text.equals("Accendi riscaldatore")) {   // attivo riscaldatore
    httpRequestBotT(1);
    bot.sendMessage(m.chat_id, "Riscaldatore attivato");  
  }
  else if (m.text.equals("Spegni riscaldatore")) {   // disattivo riscaldatore
    httpRequestBotT(0);
    bot.sendMessage(m.chat_id, "Riscaldatore disattivato");  
  }
  else if (m.text.equals("Accendi irrigazione")) {   // attivo irrigazione
    httpRequestBotH(1);
    bot.sendMessage(m.chat_id, "Irrigazione attivata");  
  }
  else if (m.text.equals("Spegni irrigazione")) {   // disattivo irrigazione
    httpRequestBotH(0);
    bot.sendMessage(m.chat_id, "Irrigazione disattivata");  
  }
  else if (m.text.equals("Accendi luce")) {   // attivo illuminazione
    httpRequestBotL(1);
    bot.sendMessage(m.chat_id, "Illuminazione attivata");  
  }
  else if (m.text.equals("Spegni luce")) {   // disattivo illuminazione
    httpRequestBotL(0);
    bot.sendMessage(m.chat_id, "Illuminazione disattivata");  
  }
  else {
    Serial.println("no new message");
  } 
  verificaStatoConnessione();
}

// connessione alla rete WIFI
void NetworkConnection() {
// attesa per la connessione Wifi
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
    // ritardo di 10 sec per permettere la connessione iniziale alla rete Wifi:
    delay(10000);
    digitalWrite(LED_connection, HIGH);
  }
}

// verifica stato connessione WIFI
void verificaStatoConnessione() {
  if(WiFi.status() == WL_CONNECTED){
    //Serial.println("WL_CONNECTED");
  }
  else if(WiFi.status() == WL_CONNECTION_LOST){
    //Serial.println("WL_CONNECTION_LOST");
    NetworkConnection();
  }
  else if(WiFi.status() == WL_DISCONNECTED){
    //Serial.println("WL_DISCONNECTED");
    NetworkConnection();
  }
  else {
    Serial.print("Status = ");
    Serial.println(WiFi.status());
  }
}

// Print Stato WIFI 
void printWifiStatus() {
  // stampa SSID della rete Wifi
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // stampa IP della scheda Wifi dell'Arduino MKR1000
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // stampa il valore dell'intensità del segnale Wifi
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

// questo metodo crea una connessione al server tramite httpRequest
void httpRequestBotT(int T) {
  // chiudiamo le precedenti connessioni e creiamo la nuova
  // liberando il socket nel WiFi
  client.stop();
  digitalWrite(LED_connection, LOW);
  // se la connessione ha successo
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    digitalWrite(LED_connection, HIGH);
    client.print("GET /web_app/attiva_T.php?");
    client.print("T=");
    client.print(T);
    client.println(" HTTP/1.0");
    client.println("Host: mylegalplants.it");
    client.println("Connection: close");
    client.println();
  }
  else {
    // se la connessione fallisce
    Serial.println("connection failed");
  }
}

void httpRequestBotH(int H) {
  // chiudiamo le precedenti connessioni e creiamo la nuova
  // liberando il socket nel WiFi
  client.stop();
  digitalWrite(LED_connection, LOW);
  // se la connessione ha successo
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    digitalWrite(LED_connection, HIGH);
    client.print("GET /web_app/attiva_H.php?");
    client.print("H=");
    client.print(H);
    client.println(" HTTP/1.0");
    client.println("Host: mylegalplants.it");
    client.println("Connection: close");
    client.println();
  }
  else {
    // se la connessione fallisce
    Serial.println("connection failed");
  }
}

void httpRequestBotL(int L) {
  // chiudiamo le precedenti connessioni e creiamo la nuova
  // liberando il socket nel WiFi
  client.stop();
  digitalWrite(LED_connection, LOW);
  // se la connessione ha successo
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    digitalWrite(LED_connection, HIGH);
    client.print("GET /web_app/attiva_L.php?");
    client.print("L=");
    client.print(L);
    client.println(" HTTP/1.0");
    client.println("Host: mylegalplants.it");
    client.println("Connection: close");
    client.println();
  }
  else {
    // se la connessione fallisce
    Serial.println("connection failed");
  }
}

Lascia un commento