Antonio La MuraUmberto Festa
Published © GPL3+

Domotic Greenhouse

Electronic greenhouse controlled real-time, because the environmental conditions change continuously, so we need an efficient monitoring.

AdvancedFull instructions providedOver 2 days29,036
Domotic Greenhouse

Things used in this project

Story

Read more

Schematics

Arduino uno with DHT22

Connection: Arduino UNO - DHT22 - Relay

Code

Create graphic

PHP
We have used this to create a graphic
<?php // content="text/plain; charset=utf-8"
 
define('__ROOT__', dirname(dirname(__FILE__))); 
require_once ('../jpgraph.php');
require_once ('../jpgraph_line.php');
require_once ('../jpgraph_error.php');
 
$parameter1 = array();
$parameter2 = array();
$time_axis = array();
$i = 0;
 
$con=mysqli_connect("localhost","user","pass","my_db");
// Check connection
if (mysqli_connect_errno()) {
  echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
 
$result = mysqli_query($con,"SELECT your_parameter FROM your_raw");
 
while($row = mysqli_fetch_array($result)) {
$parameter1[$i] =  $row["parameter1"];
$parameter2[$i] = $row["parameter2"];
$time_axis[$i] = $row["date"];
    $i++;
}
     
mysqli_close($con);
 
// Setup the graph
$graph = new Graph(300,250);
$graph->SetScale("textlin");

$theme_class=new UniversalTheme;

$graph->SetTheme($theme_class);
$graph->img->SetAntiAliasing(false);
$graph->title->Set('Title');
$graph->SetBox(false);

$graph->img->SetAntiAliasing();

$graph->yaxis->HideZeroLabel();
$graph->yaxis->HideLine(false);
$graph->yaxis->HideTicks(false,false);

$graph->xgrid->Show();
$graph->xgrid->SetLineStyle("solid");
$graph->xaxis->SetTickLabels($time_axis);
$graph->xgrid->SetColor('#E3E3E3');
$graph->xaxis->SetLabelAngle(90);
$graph->legend->SetPos(0.5,0.08,'center','top');

// Create the first line
$p1 = new LinePlot($parameter1);
$graph->Add($p1);
$p1->SetColor("#6495ED");
$p1->SetLegend('your_parameter1');
$graph->yscale->SetGrace(0);

// Create the second line
$p2 = new LinePlot($parameter2);
$graph->Add($p2);
$p2->SetColor("#B22222");
$p2->SetLegend('your_parameter2');

$graph->yscale->SetGrace(0);

$graph->legend->SetFrameWeight(1);

// Output line
$graph->Stroke();

?>

Script website connect

PHP
We have used this to save data into DB
<?php
$servername = "localhost";
$username = "user";
$password = "pass";
$dbname = "my_db";

$id = $_GET["name"];
$temp = $_GET["parameter1"];
$umid = $_GET["parameter2"];


echo "name ". $_GET['name']. "<br />";
echo "parameter1 ". $_GET['parameter1']. "<br />";
echo "parameter2 ". $_GET['parameter2']. "<br />";


// Create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);
// Check connection
if (!$conn) {
    die("Connection failed: " . mysqli_connect_error());
}

$sql = "INSERT INTO greenhouse (name, parameter1, parameter2)
VALUES ('".$name."', '".$parameter1."', '".$parameter2."')";

if (mysqli_query($conn, $sql)) {
    echo "New record created successfully";
} else {
    echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}

mysqli_close($conn);
?>

Create table

SQL
We have used this script to create the table
CREATE TABLE IF NOT EXISTS `greenhouse` (
  `id` int(11) NOT NULL,
  `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `temp` float NOT NULL,
  `umid` float NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Greenhouse Domotic Master

C/C++
This is the Master's code
/*Automation greenhouse project*/

/*Autors: Antonio La Mura, Umberto Festa*/

/*Date: 03/03/2016*/

/*Our idea is to allow users, who buy fruits and vegetables grown in greenhouses, to know exactly all the plantation steps that products have had,
  such as the use of chemical fertilizers and other similar products.
  A QR code will be put on the sold products that will be read by a specific smartphone app.
  It provides information about environment conditions where products have been grown and the chemical products used.
  The automatic monitoring system in greenhouses is composed of sensors that read environment data and actuators, called Slaves.
  They communicate via Wireless with central device, called Master. The latter sends possible changes to slaves
  (like change of thresholds) and data via WiFi to webserver as well.
  When the product is ready to be sold, QR code generation is requested to the webservice and it will be put on the package.
  The last part of the system is the mobile app that is responsible for the QR codes scanning and shows the relative informations to the user.*/

/*Master*/

/*DEVO AGGIUNGERE SOLO LA PARTE CHE MI SERVE PER RICEVERE LE NUOVE SOGLIE CHE VENGONO INVIATE DALL'APP*/

/*Libraries used*/
#include <SPI.h>
#include <WiFi101.h>
#include <RTCZero.h>
#include <WiFiUDP.h>
#include <RTCZero.h>

/*Variables for connection*/
char ssid[] = "SSID";               /*Your network SSID (name)*/
char pass[] = "pass";     /*Uour network password (use for WPA, or use as key for WEP)*/
int keyIndex = 0;                             /* Your network key Index number (needed only for WEP)*/

char ssid_ap[] = "Arduino";                   /*Created AP name*/
char pass_ap[] = "";                          /*(Not supported yet)*/

int status = WL_IDLE_STATUS;

unsigned int localPort = 2390;                /*Local port to listen on*/

char server[] = "www.cormaz.altervista.org";  /*Name address for Google (using DNS)*/

WiFiServer server_ap(80);
WiFiClient client_ap;
WiFiUDP Udp;
RTCZero rtc;
WiFiClient client;

char packetBuffer[255];                       /*Buffer to hold incoming packet*/
char ReplyBuffer[255];                        /*A string to send back*/

/*Variables for new thresholds*/
float humax = 0;
float humin = 0;
float tumax = 0;
float tumin = 0;
/*Works like Access Point (flag = false), connects to WebServer (flag = true)*/
boolean flag = false;
boolean threeshold_available = false;

void setup() {
  /*Initialize serial and wait for port to open:*/
  Serial.begin(9600);
  while (!Serial) {
    ; /*Wait for serial port to connect. Needed for native USB port only*/
  }

  Serial.println();
}

void loop() {
  int packetSize;
  double temp;
  double hum;
  int id;
  byte crc;
  String strURL;

  //Check for the presence of the shield:
  /**************************************************************************************/
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    /*Don't continue:*/
    while (true);
  }
  /**************************************************************************************/

  //Attempt to connect to WiFi network:
  /**************************************************************************************/
  while (status != WL_CONNECTED) {
    Serial.print("Creating Network named: ");
    Serial.println(ssid_ap);
    /*Connect to WPA/WPA2 network. Change this line if using open or WEP network:*/
    status = WiFi.beginAP(ssid_ap);

    /*Wait 10 seconds for connection:*/
    delay(10000);
    server_ap.begin();
  }
  Serial.println("Connected to wifi");
  /**************************************************************************************/

  //Start UDP communication
  /**************************************************************************************/
  Udp.begin(localPort);
  printWifiStatus();


  client_ap = server_ap.available();

  if (client_ap) {    /*If you get a client*/
    /*I'm waitinf for some information*/
    Serial.println("new client");           /*Print a message out the serial port*/
    /*If there's data available, read a packet*/
    packetSize = Udp.parsePacket();
    if (packetSize) {
      Serial.print("Received packet of size ");
      Serial.println(packetSize);
      Serial.print("From ");
      IPAddress remoteIp = Udp.remoteIP();
      Serial.print(remoteIp);
      Serial.print(", port ");
      Serial.println(Udp.remotePort());

      /*Read the packet into packetBuffer*/
      int len = Udp.read(packetBuffer, 255);
      if (len > 0) packetBuffer[len] = 0;
      Serial.println("Contents:");
      Serial.println(packetBuffer);

      char* command = strtok((char *)packetBuffer, ";");
      int count = 0;
      while (command != 0) {

        /*Divide the information*/
        switch (count) {
          case 0:
            id = atoi(command);
            break;

          case 1:
            temp = atof(command) / 10;
            break;

          case 2:
            hum = atof(command) / 10;
            break;
        }

        command = strtok(0, ";");
        count++;
      }
      Serial.print("Package received from ");
      Serial.print(id);
      Serial.print("  T: ");
      Serial.print(temp, 1);
      Serial.print(" H: ");
      Serial.println(hum, 1);
      /**************************************************************************************/

      delay(20);

      /*Calculate the CRC-8, so create byte array*/
      /********************************************************************************/
      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);
      /********************************************************************************/

      if (threeshold_available == true) {
        snprintf(ReplyBuffer, sizeof(ReplyBuffer), "%d;%d;%d;%d;%d;%d", id, (int)humax, (int)humin, (int)tumax, (int)tumin, (int)crc);

        /*Send a reply, to the IP address and port that sent us the packet we received*/
        Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
        Udp.write(ReplyBuffer);
        Udp.endPacket();
      }
    }                 /*Print it out the serial monitor*/
    /*Close the connection:*/
    client_ap.stop();
    Serial.println("client disconnected");
    flag = true;
  }/*Fine AP*/
  /********************************************************************************/

  /*Connect to the server and send data to DataBase*/
  /********************************************************************************/
  if (flag == true) {
    /*Attempt to connect to Wifi network:*/
    while (status != WL_CONNECTED) {
      Serial.print("Attempting to connect to SSID: ");
      Serial.println(ssid);
      /*Connect to WPA/WPA2 network. Change this line if using open or WEP network:*/
      status = WiFi.begin(ssid, pass);

      /*Wait 10 seconds for connection:*/
      delay(10000);
    }
    Serial.println("Connected to wifi");
    printWifiStatus();

    strURL = "GET /YourAddress.php?id=";
    strURL += id;
    strURL += "&parameter1=";
    strURL += temp;
    strURL += "&parameter2=";
    strURL += hum;
    strURL += " HTTP/1.1";

    Serial.println("\nStarting connection to server...");
    // if you get a connection, report back via serial:
    if (client.connect(server, 80)) {
      Serial.println("connected to server");
      // Make a HTTP request:
      client.println(strURL);
      client.println("Host: www.cormaz.altervista.org");
      client.println("Connection: close");
      client.println();
      client.stop();

      Serial.println("Ok!");
    }

    /*If the server's disconnected, stop the client:*/
    if (!client.connected()) {
      Serial.println();
      Serial.println("Disconnecting from server.");
      client.stop();

      /*Do nothing forevermore:*/
      while (true);
    }
    flag = false;
  }
  /********************************************************************************/
}

/*Calculate algorithm CRC-8 - based on Dallas/Maxim formules*/
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;
}

void printWifiStatus() {
  /*Print the SSID of the network you're attached to:*/
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  /*Print your WiFi shield's IP address:*/
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  /*Print the received signal strength:*/
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Greenhouse Domotic Slave

C/C++
This is the Slave's code
/*Automation greenhouse project*/

/*Autors: Antonio La Mura, Umberto Festa*/

/*Date: 21/03/2016*/

/*Our idea is to allow users, who buy fruits and vegetables grown in greenhouses, to know exactly all the plantation steps that products have had,
  such as the use of chemical fertilizers and other similar products.
  A QR code will be put on the sold products that will be read by a specific smartphone app.
  It provides information about environment conditions where products have been grown and the chemical products used.
  The automatic monitoring system in greenhouses is composed of sensors that read environment data and actuators, called Slaves.
  They communicate via Wireless with central device, called Master. The latter sends possible changes to slaves
  (like change of thresholds) and data via WiFi to webserver as well.
  When the product is ready to be sold, QR code generation is requested to the webservice and it will be put on the package.
  The last part of the system is the mobile app that is responsible for the QR codes scanning and shows the relative informations to the user.*/

/*Slave*/

/*Libraries used*/
#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>
#include <EEPROM.h>
#include <DHT22.h>

//Define all PIN
#define HUMIDIFIER  A4
#define HEATER     A5
#define DHT22_PIN   4
//Define motor
#define  IS_1  0
#define  IS_2  1
#define  IN_1  3
#define  IN_2  11
#define  INH_1 12
#define  INH_2 13

#define TCONST 100	//Delay Time between Steps

//Variable to reset millis()
extern unsigned long timer0_millis;

int status = WL_IDLE_STATUS;
char ssid[] = "Arduino"; //  your network SSID (name)
char pass[] = "";    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

unsigned int localPort = 2390;      // local port to listen on

char packetBuffer[255]; //buffer to hold incoming packet

WiFiUDP Udp;

//Define DHT22
DHT22 myDHT22(DHT22_PIN);

//Variable to send
float hmin = 0;
float hmax = 0;
float tmin = 0;
float tmax = 0;
int duty_motor = 0;
float humidity;
float temperature;

//Variable to send every 10 seconds
unsigned long interval = 600000;

void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  //Initialize PIN (INPUT - OUTPUT)
  pinMode(HEATER, OUTPUT);
  digitalWrite(HEATER, LOW);
  pinMode(HUMIDIFIER, OUTPUT);
  digitalWrite(HUMIDIFIER, LOW);

  //Set the PIN for the fan
  pinMode(IN_1, OUTPUT);
  pinMode(IN_2, OUTPUT);
  pinMode(INH_1, OUTPUT);
  pinMode(INH_2, OUTPUT);
  //Reset
  reset_ports();
  digitalWrite(INH_1, 1);
  digitalWrite(INH_2, 1);

  Serial.println("Beginning ... ");
  delay(2000);
}

void loop() {
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  unsigned long time = millis();
  unsigned long currentMillis = millis();
  DHT22_ERROR_t errorCode;
  int i = 0;
  char name[] = "clie1";
  humidity = myDHT22.getHumidity() * 10;
  temperature = myDHT22.getTemperatureC() * 10;
  char toSend[32];
  errorCode = myDHT22.readData();
  byte crc;
  int crc_ric;

  //Check sensor humidity and temperature DHT22 errors
  /********************************************************************************/
  switch (errorCode)
  {
    case DHT_ERROR_NONE:
      char buf[128];
      sprintf(buf, "Integer-only reading: Temperature %hi.%01hi C, Humidity %i.%01i %% RH",
              myDHT22.getTemperatureCInt() / 10, abs(myDHT22.getTemperatureCInt() % 10),
              myDHT22.getHumidityInt() / 10, myDHT22.getHumidityInt() % 10);
      break;
    case DHT_ERROR_CHECKSUM:
      break;
    case DHT_BUS_HUNG:
      break;
    case DHT_ERROR_NOT_PRESENT:
      break;
    case DHT_ERROR_ACK_TOO_LONG:
      break;
    case DHT_ERROR_SYNC_TIMEOUT:
      break;
    case DHT_ERROR_DATA_TIMEOUT:
      break;
    case DHT_ERROR_TOOQUICK:
      break;
  }
  /********************************************************************************/

  //Print the values, when it changes
  /********************************************************************************/
  if (humidity != myDHT22.getHumidity() * 10 || temperature != myDHT22.getTemperatureC() * 10) {
    Serial.print("T: ");
    Serial.print(myDHT22.getTemperatureC(), 1);
    Serial.print("C");
    Serial.print(" H: ");
    Serial.print(myDHT22.getHumidity(), 1);
    Serial.println("%");
  }
  /********************************************************************************/

  //Send the parameters every 10 minutes
  /********************************************************************************/
  if (millis() > interval) {
    
    //Connection to AP
    /********************************************************************************/
    // check for the presence of the shield:
    if (WiFi.status() == WL_NO_SHIELD) {
      Serial.println("WiFi shield not present");
      // don't continue:
      while (true);
    }

    // attempt to connect to Wifi network:
    while ( status != WL_CONNECTED) {
      Serial.print("Attempting to connect to SSID: ");
      Serial.println(ssid);
      // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
      status = WiFi.begin(ssid);

      // wait 10 seconds for connection:
      delay(10000);
    }
    Serial.println("Connected to wifi");
    /********************************************************************************/
    
    Serial.println("\nStarting connection to server...");
    // if you get a connection, report back via serial:
    Udp.begin(localPort);

    snprintf(toSend, sizeof(toSend), "%s;%d;%d", name, (int)humidity, (int)temperature);
    // send a reply, to the IP address and port that sent us the packet we received
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(toSend);
    Udp.endPacket();

    Serial.println("Finished sending");

    resetMillis();

    while (millis() < 10000) {
      packetSize = Udp.parsePacket();
      if (packetSize) {
        /*Read the packet into packetBuffer*/
        int len = Udp.read(packetBuffer, 255);
        if (len > 0) packetBuffer[len] = 0;
        Serial.println("Contents:");
        Serial.println(packetBuffer);

        char* command = strtok((char *)packetBuffer, ";");
        int count = 0;
        while (command != 0) {

          /*Divide the information*/
          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++;
        }
        Serial.print("Answer: ");
        Serial.print(name);
        Serial.print(";");
        Serial.print(hmax, 1);
        Serial.print(";");
        Serial.print(hmin, 1);
        Serial.print(";");
        Serial.print(tmax, 1);
        Serial.print(";");
        Serial.println(tmin, 1);
        Serial.print("CRC recived: ");
        Serial.println(crc_ric);

        //calculate CRC-8, and I obtain the byte's array
        /********************************************************************************/
        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);
        /********************************************************************************/

        if (crc_ric == (int)crc) {
          //Save in the EEPROM
          EEPROM_writeDouble(0, tmax);
          EEPROM_writeDouble(4, tmin);
          EEPROM_writeInt(8, hmax);
          EEPROM_writeInt(10, hmin);
        }
      }
    }
    delay(10);
  }
  /********************************************************************************/

  WiFi.disconnect(); 

  //Manage the HUMIDIFIER, HEATER and fan according to the sensor's value
  /**************************************************************************************/
  //HEATER
  if (myDHT22.getTemperatureC() >= tmax) {
    digitalWrite(HEATER, HIGH);
  }
  if (myDHT22.getTemperatureC() <= tmin + 1) {
    digitalWrite(HEATER, LOW);
  }

  //HUMIDIFIER
  if ((int)myDHT22.getHumidity() >= hmax) {
    digitalWrite(HUMIDIFIER, HIGH);
  }
  if ((int)myDHT22.getHumidity() <= hmin + 1) {
    digitalWrite(HUMIDIFIER, LOW);
  }

  //Fan, Brushless motor
  if (myDHT22.getTemperatureC() >= tmax + 4) {
    //Rotation of the motor according to with temperature, duty -> 0 per t = tmax+4 and duty -> 100 per t > tmax+10
    //Rotazione del motore al variare della temperatura, duty -> 0 per t = tmax+4 e duty -> 100 per t > tmax+10
    duty_motor = map(i , tmax + 4, tmax + 10, 0, 100);
    if (tmax > tmax + 10) {
      duty_motor = 100;
    }
    analogWrite(IN_2, duty_motor);
    delay(TCONST);
  }
  if (myDHT22.getTemperatureC() <= (tmax + tmin) / 2) {
    reset_ports();
    //Rotation of the motor according to with temperature, duty -> 0 per t = tmax+4 and duty -> 255 per t > tmax+10
    duty_motor = 0;
    analogWrite(IN_2, duty_motor);
    delay(TCONST);
  }
  /**************************************************************************************/

  delay(1000);
}

//Save double in EEPROM
void EEPROM_writeDouble(int ee, double value) {

  byte* p = (byte*)(void*)&value;
  for (int i = 0; i < sizeof(value); i++)
    EEPROM.write(ee++, *p++);
}

//Save int in EEPROM
void EEPROM_writeInt(int ee, int value) {

  byte* p = (byte*)(void*)&value;
  for (int i = 0; i < sizeof(value); i++)
    EEPROM.write(ee++, *p++);
}

//Read double to EEPROM
double EEPROM_readDouble(int ee) {

  double value = 0.0;
  byte* p = (byte*)(void*)&value;
  for (int i = 0; i < 4; i++)
    *p++ = EEPROM.read(ee++);
  return value;
}

//Read int to EEPROM
int EEPROM_readInt(int ee) {

  int value = 0;
  byte* p = (byte*)(void*)&value;
  for (int i = 0; i < 2; i++)
    *p++ = EEPROM.read(ee++);
  return value;
}

//Reset input
void reset_ports()
{
  digitalWrite(IN_1, 0);
  digitalWrite(IN_2, 0);
}

//Algorithm for CRC-8 based on Dallas/Maxim's farmulas
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;
}

//It uses to reset millis()
void resetMillis() {
  cli();
  timer0_millis = 0;
  sei();
}

getdati

PHP
We have used this to connect our app with database
<?php
$username = "root";
$password = "";
$hostname = "localhost"; 

//connection to the database
$dbhandle = mysql_connect($hostname, $username, $password) 
 or die("Unable to connect to MySQL");
//echo "Connected to MySQL<br>";

//select a database to work with
$selected = mysql_select_db("serra",$dbhandle) 
  or die("Could not select examples");
  
$datada = $_GET["datada"];
$dataa = $_GET["dataa"];

//execute the SQL query and return records
$result = mysql_query("SELECT hum,temp,date FROM record WHERE date >= '".$datada."' and date <='".$dataa."'");


$records=array();
//fetch tha data from the database 
while ($row = mysql_fetch_array($result)) {
	$tmp = array("hum"=>$row{'hum'}, "temp"=>$row{'temp'}, "date"=>$row{'date'});
	array_push($records,$tmp);
	//echo "HUM:".$row{'hum'}." TEMP:".$row{'temp'}."Date: ". //display the results
	$row{'date'}."<br>";
}

echo json_encode($records);

//close the connection
mysql_close($dbhandle);
?>

App GrenHouse

In the first page you have to set the date using two DatePicker. When you press the button "GRAPHIC", it makes an HTTP GET call to the PHP script "getdati" sending the parameters and date that you have chosen. Then it receives the JSON and decodes that, after it creates the graphic using the library GraphView

Credits

Antonio La Mura

Antonio La Mura

1 project • 23 followers
I’ve always been into electronics. For this reason I have never had any doubt about my choice to study electronic engineering. As I also have a particular inter
Umberto Festa

Umberto Festa

1 project • 13 followers

Comments