Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Slim Domotisch Kas: Geautomatiseerde Klimaatbesturing met Arduino

Onderdelen en benodigdheden

Onderdeel Aantal
Arduino MKR1000 1
Arduino UNO 1
DHT22 Temperatuursensor 1
Arduino WiFi Shield 101 1
Android-apparaat 1
DC Motor Control Shield met BTN8982 voor Arduino (Infineon) 1

Apps en online diensten

  • Arduino IDE
  • Eclipse

Over dit project

Overzicht

De omgevingsomstandigheden in een kas veranderen continu, waardoor efficiënte monitoring essentieel is. Een automatisch systeem biedt veel voordelen: minder handmatig werk en de mogelijkheid voor gebruikers om hun investeringen thuis via pc of smartphone te controleren.

Een ander belangrijk voordeel is de mogelijkheid om gegevens op te slaan in een database. Dit kan het verschil maken tussen winst of verlies. Bovendien stelt realtime systeembesturing je in staat om direct in te grijpen en problemen met de teelt te voorkomen.

Het automatische monitoringsysteem in kassen bestaat uit sensoren die omgevingsgegevens lezen en actuatoren, de zogenaamde "Slaves". Ze communiceren draadloos met een centraal apparaat, de "Master". De Master stuurt eventuele wijzigingen naar de slaves (zoals drempelwaarden) en verzendt data via WiFi naar de webserver.

1. Hoe werkt het?

Het project kan worden opgesplitst in drie delen:

  • Master
  • Slave
  • Webserver

We hebben een Arduino/Genuino MKR1000 gebruikt voor de Master en een Arduino/Genuino Uno voor de Slave.

De Master communiceert met de webserver via WiFi (geïntegreerde WINC1500). De Slave meet temperatuur en vochtigheid met de DHT22-sensor en stuurt deze gegevens via WiFi (WiFi Shield WINC1500) naar de Master.

2. Master

De Master staat in "Access Point-modus" en wacht op verbinding met de Slave om temperatuur- en vochtigheidsgegevens te ontvangen. Deze worden verwerkt en naar de webserver gestuurd.

De Master controleert of er gegevens beschikbaar zijn. Zo ja, dan wordt een UDP-pakket gemaakt met nieuwe drempelwaarden en een CRC. De Master berekent de CRC die de Slave gebruikt om de ontvangen instellingen te valideren.

Nadat de Master de Access Point-modus verlaat, verbindt het met het WiFi-netwerk om gegevens naar de webserver te sturen, waar ze in een grafiek worden weergegeven.

Slim Domotisch Kas: Geautomatiseerde Klimaatbesturing met Arduino

3. Slave

De Slave meet temperatuur en vochtigheid met de DHT22-sensor en stuurt elke 5 minuten gegevens naar de Master. Ook maakt het een UDP-pakket, verbindt met de Master en verstuurt de data.

Vervolgens wacht het op eventuele nieuwe drempelwaarden. Als die ontvangen worden, berekent de Slave de CRC met de Dallas-Maxim-formule en vergelijkt deze met de CRC van de Master. Als ze overeenkomen, worden de nieuwe instellingen opgeslagen in het EEPROM.

Slim Domotisch Kas: Geautomatiseerde Klimaatbesturing met Arduino

4. Webserver

De webserver slaat alle gegevens op voor historische analyse. Hiervoor wordt een PHP-script gebruikt dat verbindt met de database en de data op twee manieren presenteert:

  • In een grafiek (via een ander PHP-script)
  • In een Android-app, in JSON-formaat (via nog een PHP-script)
Slim Domotisch Kas: Geautomatiseerde Klimaatbesturing met Arduino

5. App

De app maakt het mogelijk om de data in de database te raadplegen. Op het eerste scherm selecteer je het tijdsbereik en druk je op de knop "GRAFIEK". De app haalt de gegevens op via de webservice en toont ze in een grafiek.

Slim Domotisch Kas: Geautomatiseerde Klimaatbesturing met Arduino
Slim Domotisch Kas: Geautomatiseerde Klimaatbesturing met Arduino

Code

Grafiek aanmaken (PHP)

<?php
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");
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);
$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');
$p1 = new LinePlot($parameter1);
$graph->Add($p1);
$p1->SetColor("#6495ED");
$p1->SetLegend('your_parameter1');
$graph->yscale->SetGrace(0);
$p2 = new LinePlot($parameter2);
$graph->Add($p2);
$p2->SetColor("#B22222");
$p2->SetLegend('your_parameter2');
$graph->yscale->SetGrace(0);
$graph->legend->SetFrameWeight(1);
$graph->Stroke();
?>

Website verbindingsscript (PHP)

<?php
$servername = "localhost";
$username = "user";
$password = "pass";
$dbname = "my_db";
$id = $_GET["name"];
$temp = $_GET["parameter1"];
$umid = $_GET["parameter2"];
echo "name " . $_GET['name']. "
"; echo "parameter1 " . $_GET['parameter1']. "
"; echo "parameter2 " . $_GET['parameter2']. "
"; $conn = mysqli_connect($servername, $username, $password, $dbname); 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 . "
" . mysqli_error($conn); } mysqli_close($conn); ?>

Tabel aanmaken (SQL)

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++)

/* Automation greenhouse project */
/* Autors: Antonio La Mura, Umberto Festa */
/* Date: 03/03/2016 */
/* Master */
#include <SPI.h>
#include <WiFi101.h>
#include <RTCZero.h>
#include <WiFiUDP.h>
/* Variabelen voor verbinding */
char ssid[] = "SSID";
char pass[] = "pass";
int keyIndex = 0;
char ssid_ap[] = "Arduino";
char pass_ap[] = "";
int status = WL_IDLE_STATUS;
unsigned int localPort = 2390;
char server[] = "www.cormaz.altervista.org";
WiFiServer server_ap(80);
WiFiClient client_ap;
WiFiUDP Udp;
RTCZero rtc;
WiFiClient client;
char packetBuffer[255];
char ReplyBuffer[255];
/* Variabelen voor nieuwe drempels */
float humax = 0, humin = 0, tumax = 0, tumin = 0;
boolean flag = false;
boolean threeshold_available = false;

void setup() {
    Serial.begin(9600);
    while (!Serial) { ; }
    Serial.println();
}

void loop() {
    int packetSize;
    double temp, hum;
    int id;
    byte crc;
    String strURL;
    if (WiFi.status() == WL_NO_SHIELD) {
        Serial.println("WiFi shield not present");
        while (true);
    }
    while (status != WL_CONNECTED) {
        Serial.print("Creating Network named: ");
        Serial.println(ssid_ap);
        status = WiFi.beginAP(ssid_ap);
        delay(10000);
        server_ap.begin();
    }
    Serial.println("Connected to wifi");
    Udp.begin(localPort);
    printWifiStatus();
    client_ap = server_ap.available();
    if (client_ap) {
        Serial.println("new client");
        packetSize = Udp.parsePacket();
        if (packetSize) {
            Serial.print("Received packet of size ");
            Serial.println(packetSize);
            IPAddress remoteIp = Udp.remoteIP();
            Serial.print("From ");
            Serial.print(remoteIp);
            Serial.print(", port ");
            Serial.println(Udp.remotePort());
            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) {
                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);
            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);
                Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
                Udp.write(ReplyBuffer);
                Udp.endPacket();
            }
        }
        client_ap.stop();
        Serial.println("client disconnected");
        flag = true;
    }
    if (flag == true) {
        while (status != WL_CONNECTED) {
            Serial.print("Attempting to connect to SSID: ");
            Serial.println(ssid);
            status = WiFi.begin(ssid, pass);
            delay(10000);
        }
        Serial.println("Connected to wifi");
        printWifiStatus();
        strURL = "GET /YourAddress.php?id=";
        strURL += id;
        strURL += "¶meter1=";
        strURL += temp;
        strURL += "¶meter2=";
        strURL += hum;
        strURL += " HTTP/1.1";
        Serial.println("\nStarting connection to server...");
        if (client.connect(server, 80)) {
            Serial.println("connected to server");
            client.println(strURL);
            client.println("Host: www.cormaz.altervista.org");
            client.println("Connection: close");
            client.println();
            client.stop();
            Serial.println("Ok!");
        }
        if (!client.connected()) {
            Serial.println();
            Serial.println("Disconnecting from server.");
            client.stop();
            while (true);
        }
        flag = false;
    }
}

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() {
    Serial.print("SSID: ");
    Serial.println(WiFi.SSID());
    IPAddress ip = WiFi.localIP();
    Serial.print("IP Address: ");
    Serial.println(ip);
    long rssi = WiFi.RSSI();
    Serial.print("signal strength (RSSI):");
    Serial.print(rssi);
    Serial.println(" dBm");
}

Greenhouse Domotic Slave (C/C++)

/* Slave */
#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>
#include <EEPROM.h>
#include <DHT22.h>
#define HUMIDIFIER A4
#define HEATER A5
#define DHT22_PIN 4
#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
extern unsigned long timer0_millis;
int status = WL_IDLE_STATUS;
char ssid[] = "Arduino";
char pass[] = "";
int keyIndex = 0;
unsigned int localPort = 2390;
char packetBuffer[255];
WiFiUDP Udp;
DHT22 myDHT22(DHT22_PIN);
float hmin = 0, hmax = 0, tmin = 0, tmax = 0;
int duty_motor = 0;
float humidity, temperature;
unsigned long interval = 600000;

void setup() {
    Serial.begin(9600);
    while (!Serial) { ; }
    pinMode(HEATER, OUTPUT); digitalWrite(HEATER, LOW);
    pinMode(HUMIDIFIER, OUTPUT); digitalWrite(HUMIDIFIER, LOW);
    pinMode(IN_1, OUTPUT); pinMode(IN_2, OUTPUT);
    pinMode(INH_1, OUTPUT); pinMode(INH_2, OUTPUT);
    reset_ports();
    digitalWrite(INH_1, 1); digitalWrite(INH_2, 1);
    Serial.println("Beginning ... ");
    delay(2000);
}

void loop() {
    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;
    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;
    }
    if (humidity != myDHT22.getHumidity() * 10 || temperature != myDHT22.getTemperatureC() * 10) {
        Serial.print("T: ");
        Serial.print(myDHT22.getTemperatureC(), 1);
        Serial.print("C H: ");
        Serial.print(myDHT22.getHumidity(), 1);
        Serial.println("%");
    }
    if (millis() > interval) {
        if (WiFi.status() == WL_NO_SHIELD) {
            Serial.println("WiFi shield not present");
            while (true);
        }
        while (status != WL_CONNECTED) {
            Serial.print("Attempting to connect to SSID: ");
            Serial.println(ssid);
            status = WiFi.begin(ssid);
            delay(10000);
        }
        Serial.println("Connected to wifi");
        Serial.println("\nStarting connection to server...");
        Udp.begin(localPort);
        snprintf(toSend, sizeof(toSend), "%s;%d;%d", name, (int)humidity, (int)temperature);
        Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
        Udp.write(toSend);
        Udp.endPacket();
        Serial.println("Finished sending");
        resetMillis();
        while (millis() < 10000) {
            packetSize = Udp.parsePacket();
            if (packetSize) {
                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) {
                    switch (count) {
                        case 0: snprintf(name, sizeof(name), "%s", command); break;
                        case 1: hmax = atof(command) / 10; 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);
                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) {
                    EEPROM_writeDouble(0, tmax);
                    EEPROM_writeDouble(4, tmin);
                    EEPROM_writeInt(8, hmax);
                    EEPROM_writeInt(10, hmin);
                }
            }
            delay(10);
        }
        WiFi.disconnect();
    }
    if (myDHT22.getTemperatureC() >= tmax) digitalWrite(HEATER, HIGH);
    if (myDHT22.getTemperatureC() <= tmin + 1) digitalWrite(HEATER, LOW);
    if ((int)myDHT22.getHumidity() >= hmax) digitalWrite(HUMIDIFIER, HIGH);
    if ((int)myDHT22.getHumidity() <= hmin + 1) digitalWrite(HUMIDIFIER, LOW);
    if (myDHT22.getTemperatureC() >= tmax + 4) {
        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();
        duty_motor = 0;
        analogWrite(IN_2, duty_motor);
        delay(TCONST);
    }
    delay(1000);
}

void EEPROM_writeDouble(int ee, double value) {
    byte* p = (byte*)(void*)&value;
    for (int i = 0; i < sizeof(value); i++) EEPROM.write(ee++, *p++);
}
void EEPROM_writeInt(int ee, int value) {
    byte* p = (byte*)(void*)&value;
    for (int i = 0; i < sizeof(value); i++) EEPROM.write(ee++, *p++);
}
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;
}
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;
}
void reset_ports() {
    digitalWrite(IN_1, 0); digitalWrite(IN_2, 0);
}
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 resetMillis() {
    cli(); timer0_millis = 0; sei();
}

getdati (PHP)

<?php
$username = "root"; $password = ""; $hostname = "localhost";
$dbhandle = mysql_connect($hostname, $username, $password) or die("Unable to connect to MySQL");
$selected = mysql_select_db("serra",$dbhandle) or die("Could not select examples");
$datada = $_GET["datada"]; $dataa = $_GET["dataa"];
$result = mysql_query("SELECT hum,temp,date FROM record WHERE date >= '".$datada."' and date <='".$dataa."'");
$records = array();
while ($row = mysql_fetch_array($result)) {
    $tmp = array("hum"=>$row{'hum'}, "temp"=>$row{'temp'}, "date"=>$row{'date'});
    array_push($records,$tmp);
}
echo json_encode($records);
mysql_close($dbhandle);
?>

App Greenhouse

In het eerste scherm stel je de datum in met twee DatePickers. Bij druk op de knop "GRAFIEK" wordt een HTTP GET-aanroep gedaan naar het PHP-script "getdati" met de gekozen parameters en datums. De ontvangen JSON wordt gedecodeerd en de grafiek wordt gegenereerd met de bibliotheek GraphView.

Schema's

Aansluiting: Arduino UNO - DHT22 - Relais

Slim Domotisch Kas: Geautomatiseerde Klimaatbesturing met Arduino

Productieproces

  1. Professionele gids voor bitmap-animatie op de ILI9341 2,4″ TFT Touchscreen Shield
  2. Web-gestuurd DMX-verlichtingssysteem – Arduino Master Controller
  3. Bluetooth-gecontroleerde Arduino Spybot bouwen
  4. FlickMote: Gebarengecontroleerde IR-afstandsbediening voor Slimme Huizen
  5. DIY Arduino TV-B-Gone: Universele TV-uit-schakelaar
  6. Bouw een Aangepaste LED Hoofdklok met Alarm – Zichtbaar vanaf 12 Meter
  7. HSV-klok: Levendige, aanpasbare klok voor Arduino-liefhebbers
  8. Bouw een Android-bestuurd extern voertuig met Raspberry Pi Motor Shield
  9. Find Me: Slimme Item Locator met Arduino en Bluetooth
  10. Geoptimaliseerde Voedingsoplossingen voor Arduino Projecten
  11. Draadloze Arduino Programmeer Shield met HC-05 Bluetooth – Geen USB Nodig