Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Kräuterbox-Ökosystem

Komponenten und Verbrauchsmaterialien

Amazon Alexa Echo Dot
× 1
Arduino UNO
× 1
Espressif ESP8266 ESP-01
× 1
Arduino Proto Shield
× 1
Arduino 4 Relais Schild
× 1
Aquapumpe
× 2
Pflanzenzuchtlampe
× 1
220-V-DC-Netzteil
× 1
12-V-DC-Netzteil
× 1
USB-Netzstecker + Kabel
× 1
Luftschlauch
× 1
Jumper (generisch)
× 1

Apps und Onlinedienste

Arduino-IDE
Amazon Alexa Alexa Skills Kit
Amazon Web Services AWS Lambda
php-Webserver

Über dieses Projekt

Da meine Pflanzen immer unter zu viel oder zu wenig Wasser leiden und ich gerne viele Kräuter in mein Geschirr gebe, habe ich mich für ein individuelles Bewässerungssystem entschieden. Die Box für meine Kräuter sollte konfigurierbar sein und automatisch oder manuell funktionieren. Daher existiert eine Schnittstelle zu einer Website, um ein Setup zu ermöglichen und die Luftfeuchtigkeit in einem schönen Diagramm anzuzeigen. Der letzte Schritt war die Integration der Sprachsteuerung, um Amazon Alexa nach Feuchtigkeit zu fragen, eine Pflanzenlampe ein-/auszuschalten und die Bewässerung zu starten, wenn die Automatisierung deaktiviert ist. Klicken Sie hier, um das Ergebnis zu finden.

Ich begann mit dem technischen Teil des Projekts und kaufte einen Arduino. Nach einigen Tutorials war ich fest mit der Software und der Steuerung des Arduino. Ich bestellte einen WLAN-Controller, einige Feuchtigkeitssensoren, Pumpen, eine Pflanzenlampe und zusätzlich benötigte Hardware (Relaisschild zum Trennen der Stromkreise für Lampe und Pumpen vom Arduino, einige Drähte und Buchenholz für den Rahmen). Der Arduino-Code des Ergebnisses wird in diesem Tutorial bereitgestellt, neben einigen Informationen zur Verwendung der Komponenten in Ihren Projekten. Der Website-/Api-Code wird nicht bereitgestellt (es sei denn, die Nachfrage ist sehr groß;) ).

Schritt 1:Feuchtigkeitssensor

Der erste Meilenstein war das Auslesen der Luftfeuchtigkeit mit meinem Arduino. Der Feuchtigkeitssensor YL-69 war einfach mit dem Arduino zu verbinden. Sie müssen den VCC-Pin mit einem GPIO-Pin (in meinem Beispiel Pin 06), Masse mit Masse und den A0 mit einem analogen Pin (in meinem Beispiel Pin A1) des Arduino verbinden.

Tutorial:Bodenfeuchtesensor

byte vccPin =6;byte dataPin =A1;void setup () { pinMode (vccPin, OUTPUT); digitalWrite (vccPin, LOW); Serial.begin (9600); while (!Serial);}int readHumidity() { digitalWrite (vccPin, HIGH); Verzögerung (500); // Sie müssen testen, wie lange Sie vor der Messung vorschalten Int value =analogRead (dataPin); digitalWrite (vccPin, LOW); Rückgabe 1023 - Wert;}void loop () { Serial.print ( "HumidityLevel (0-1023):"); Serial.println (readHumidity()); Verzögerung(10000);} 

Schritt 2:Relais für Pumpen und Lampe

Das nächste Ziel war die Installation einer Relaisabschirmung (4 Relais) zur Trennung der Stromkreise von Lampe, Pumpen und Arduino. Der Arduino läuft mit 5V, die Pumpen mit 12V und die Pflanzenlampe mit 230V. Die Abschirmung muss mit den 5V- und Ground-Pins des Arduino verbunden werden. Jedes Relais benötigt außerdem einen GPIO-Pin Ihrer Wahl zum Ein- und Ausschalten. Schließlich können Sie einen Jumper für VCC JC zu VCC auf dem Schild verwenden oder eine zusätzliche Batterie verwenden (was am besten wäre, aber ich habe noch keine Batterie in meinem Projekt).

Es ist wichtig zu verstehen, dass mein Schild mit "LOW" auf dem Pin "On" schaltet. Sobald mein Pin als OUTPUT definiert ist, wird er automatisch auf aktiv geschaltet. Im Code sollten Sie immer auf INPUT und LOW umschalten, wenn Sie möchten, dass das Relais ausgeschaltet ist. Standardmäßig sind die Arduino-Pins INPUT und LOW.

Tutorial:Relaisschild

Information:Warum Relais OUTPUT + LOW =Aktiv?

byte pump1 =11;byte pump2 =10;void setup() { Serial.begin(9600); while (!Seriell); pinMode (Pumpe1, AUSGANG); // Variante Low/High DigitalWrite (Pumpe2, LOW); // Variante Input/Output}void loop () { DigitalWrite (Pumpe1, HIGH); // Pumpe1 deaktiviert PinMode (Pumpe2, INPUT); // Pumpe2 Deaktivierungsverzögerung (1000); digitalWrite (Pumpe1, LOW); // Pumpe1 aktiviert PinMode (Pumpe2, AUSGANG); // Pumpe2 aktivierte Verzögerung (1000);} 

Schritt 3:WLAN mit ESP-01

Das Anschließen des ESP8266 ESP-01 an den Arduino für WiFi war der schwierigste Teil. Ich habe Stunden gebraucht, um das WLAN in meinem Skript zum Laufen zu bringen.

Der ESP ist angeschlossen an:VCC =3.3V, GND =GND, CH_PD =3.3V, TX =Pin 02, RX =Pin 03. Für den produktiven Einsatz sollten Sie mindestens einen Pegelwandler von 5V auf 3.3V für den Pin verwenden 02 und Pin 03 auch. In meinem Fall hat es gut funktioniert.

Ähnlich wie beim Arduino ist der ESP-01 ein weiterer Mikrocontroller. Wenn Sie möchten, dass beide Controller kommunizieren, müssen Sie die serielle Kommunikation verwenden. Das Arduino UNO verwendet standardmäßig die Pins 01 und 02 für RX und TX. Sie werden jedoch auch für das USB-Debugging verwendet und daher wird empfohlen, SoftwareSerial.h einzubinden und benutzerdefinierte Pins zu definieren.

#include SoftwareSerial espSerial(3,2); // RX, TXvoid setup () { Serial.begin (9600); espSerial.begin(115200); // zu 9600 wechseln nach AT+UART_DEF=9600,8,1,0,0 while (!Serial);}void loop() { if (espSerial.available()) { Serial.write(espSerial.read()); aufrechtzuerhalten. Wenn (Serial.available ()) { espSerial.write (Serial.read ()); }} 

Wenn Sie das obige Skript ausführen, können Sie AT-Befehle in den seriellen Monitor eingeben und die Ergebnisse anzeigen. Die serielle Kommunikation ist fehleranfällig, daher habe ich die vom ESP verwendete Kommunikationsbaudrate von 115200 auf 9600 gesenkt.

Tutorial:ESP8266 + Arduino | Tutorial:Allgemeines ESP8266 (deutsch)

  • Eine nützliche Hilfsklasse (aber verbraucht zu viel Speicher):Bibliothek:WiFiEsp
  • Speicherprüftool:Bibliothek:MemoryFree

Das Skript verwendet HTTP 1.0, da bei HTTP 1.1 die Bytes Teil der Antwort sind. Es ist wichtig, auf die Zeilenumbrüche zu achten, damit der Befehl nach AT+CIPSEND gesendet wird. Wenn sie falsch sind, erhalten Sie einen Byte-Sendefehler.

#include SoftwareSerial espSerial(3,2); // RX, TXconst char* ssid ="";const char* pass ="";void setup() { Serial.begin(9600); espSerial.begin(9600); while(!Seriell); while(!connectToWiFi()); // Website anfordern und Ergebnis drucken if (httpRequest("my.server.com", "/site/subsite/index.php")) { while (espSerial.available ()) { Serial.write (espSerial.read () ); aufrechtzuerhalten. aufrechtzuerhalten. aufrechtzuerhalten. Wenn (Serial.available ()) { espSerial.write (Serial.read ()); }}bool connectToWiFi() { delay(2000;) espSerial.setTimeout(3000); while (espSerial.available ()) Serial.write (espSerial.read ()); Serial.println (F("[ESP] Verbindung mit WiFi")); espSerial.println(F("AT+CIPSTATUS=2")); if (!espSerial.find("OK")) { espSerial.setTimeout(10000); Serial.println (F ("[ESP] Reset-Modul")); espSerial.println(F("AT+RST")); if (!espSerial.find("ready")) {Serial.println(F("[ESP] Reset fehlgeschlagen")); falsch zurückgeben; } Serial.println (F ("[ESP] CWMode einstellen")); espSerial.println(F("AT+CWMODE=1")); if (!espSerial.find("OK")) {Serial.println(F("[ESP] Modus fehlgeschlagen")); falsch zurückgeben; } Serial.println (F ("[ESP] Mit Router verbinden")); espSerial.print(F("AT+CWJAP=\"")); espSerial.print(ssid); espSerial.print(F("\",\"")); espSerial.print(pass); espSerial.println ("\""); if (!espSerial.find("OK")) {Serial.println(F("[ESP] WiFi-Verbindung fehlgeschlagen")); falsch zurückgeben; } } espSerial.setTimeout(3000); Serial.println (F ("[ESP] WiFi ist verbunden")); return true;}bool httpRequest(String-Server, String-Site) { String cmd =""; cmd +="GET" + Site + " HTTP/1.0\r\n"; cmd +="Host:" + Server + "\r\n"; cmd +="Verbindung:schließen"; int cmdLength =cmd.length() + 4; // Serial.println (cmd); espSerial.print(F("AT+CIPSTART=\"TCP\",\"")); espSerial.print(Server); espSerial.println(F("\",80")); if (!espSerial.find("OK")) {Serial.println(F("[ESP] TCP-Verbindungsfehler")); falsch zurückgeben; } espSerial.print(F("AT+CIPSEND=")); espSerial.println(cmdLength); if (!espSerial.find(findGT)) {Serial.println (F("[ESP] Send State Error")); falsch zurückgeben; } espSerial.print(F("GET")); espSerial.print(Site); espSerial.print(F("HTTP/1.0\r\n")); espSerial.print(F("Host:")); espSerial.print(Server); espSerial.print(F("\r\n")); espSerial.print(F("Verbindung:schließen\r\n")); espSerial.println(); if (!espSerial.find(":")) { Serial.println(F("Bytes nicht gesendet")); espSerial.print(F("AT+CIPCLOSE")); falsch zurückgeben; } Zeichenstatus[32] ={0}; espSerial.readBytesUntil('\r', status, sizeof(status)); if (strcmp(status, "HTTP/1.1 200 OK") !=0) {Serial.print(F("[ESP] Unerwartete Antwort:")); Serial.println (Status); falsch zurückgeben; } if (!espSerial.find("\r\n\r\n")) {Serial.println(F("[ESP] Ungültige Antwort")); falsch zurückgeben; } // HTTP-Header überspringen // if (!espSerial.find(\r\n)) { Serial.println(F("[ESP] Bytes not found")); Rückkehr; } // Byte überspringen (für http 1.1) return true;i} 

Schritt 4:Die Holzkiste

Der Rahmen war geplant, um die gesamte Elektronik und drei Kräutertöpfe aus dem Supermarkt zu verstauen. Ich habe die Größen aller Komponenten gemessen und die Positionen strukturiert. Vier Feuchtigkeitssensoren, zwei Pumpen, das Arduino + Shield, ein 4x Relais Shield und ein USB-Stecker und einige Kabel müssen in die Box passen. Es wurde aus Buchenholz gefertigt, um es ohne zusätzliche Lasur stark und haltbar zu machen.

Die Kreise wurden mit einer Stichsäge auf einem selbstgebauten Stichsägentisch ausgesägt. Die Pflanzenhalterungen werden mit Heißkleber in die Kreise geklebt. Die Seiten der Box sind mit Holzleim (D3 für Wasserbeständigkeit) verklebt. Außer der Elektronik habe ich neben der unteren Verkleidungsbefestigung keine Schrauben oder Nägel verwendet.

Ich habe alle Stromkreise, Kabel und Wasserschläuche in die Box gelegt, die Sensoren herausgezogen und die Schläuche für den zusätzlichen Wassertank. Vor dem Schließen der Box habe ich Untertassen hinzugefügt, um das Ertrinken von Wasser in der Box zu verhindern, um die Elektronik zu schützen.

Schritt fünf:Die Website-API

Die API und die Website basieren auf jQuery, Bootstrap, X-editable (für Inline-Ajax-Formulare) und Chart.js (für das Feuchtigkeitsdiagramm), codiert in PHP. Auf der Website können Sie die Einstellungen für den Arduino definieren (z. B. Sensorpins, Feuchte-Check-Intervall, Pumpen pro Pflanze, Pumpen-VCC-Pins, Licht-VCC-Pin) und die aktuelle Luftfeuchtigkeit + Diagramm ermitteln.

Die Konfiguration wird von JSON für den Arduino bereitgestellt. Nach dem Start und in regelmäßigen Abständen prüft die Kräuterbox auf neue Einstellungen. Zum Parsen des JSON mit dem Arduino habe ich die Bibliothek ArduinoJson verwendet. Für das Abfrageintervall habe ich StensTimer verwendet.

Bibliothek:ArduinoJson | Bibliothek:StensTimer

Schritt Sechs:Alexa-Integration

Die Website bietet eine API für die Alexa-Kommunikation. Es dient als Hub, um das Request-JSON von Alexa zu empfangen und übersetzt es in ein benutzerdefiniertes JSON, das vom Arduino verwendet wird (z.B. Lampe an, Anlage 1 bewässern, ...). Der Arduino fragt nach neuen Aktionen und führt sie aus.

Da die Sprachanfragen mehr als nur an/aus sind, habe ich einen Alexa Skill implementiert und kein Alexa Smart Home. AWS Lampda leitet die JSON-Anfrage an meine API weiter, die die Absichten analysiert.

var https =require('https');exports.handler =(Ereignis, Kontext, Rückruf) => { var postData =JSON.stringify(Ereignis); var options ={ host:'', path:'', port:443, method:'POST', headers:{ 'Content-Type':'application/json' , 'Inhaltslänge':postData.length, } }; // Anfrage einrichten var postRequest =https.request(options, function(res) { res.setEncoding('utf8'); res.on('data', function (chunk) { console.log('Response:' + Chunk); // console.log(chunk); callback(null, JSON.parse(chunk)); }); }); // die Daten postRequest.write(postData); postRequest.end();}; 

Ein Auszug der Intents, die ich von meinem Skill verwendet habe:

  • ReadHumidityIntent Wie geht es meinen Pflanzen
  • ReadHumidityIntent Wie geht es meinem {plantName}
  • BewässernPlantIntent Bewässere meine Pflanzen
  • IrrigatePlantIntent Bewässere meine {plantName} für {durationSeconds} Sekunden
  • SwitchIntent Schalte die Lampe {switchState}
  • ReadIrrigateIntent Welche Pflanzen brauchen Wasser
  • ReadLastIrrigationIntent Wann war die letzte Bewässerung meiner {plantName}

Zu guter Letzt habe ich Locale-Unterstützung für die deutsche und englische Verwendung hinzugefügt.

Das Ergebnis

Als Ergebnis habe ich eine Holzkiste, um Supermarkt-Kräutertöpfe hineinzustellen, Wasserschläuche und Feuchtigkeitssensoren in die Erde und die Schläuche in einen externen Wassertank zu nehmen. Mit Alexa-Integration kann ich folgende Sätze sagen:

  • "Alexa, frag Kräuterkiste, wie es meinen Pflanzen geht " - Antwort:"Anlage 1 ist in Ordnung, Anlage 2 ist trocken, ..."
  • "Alexa, sage Kräuterkiste, dass sie mein Basilikum 5 Sekunden lang bewässern soll " - Antwort:"Basilikum 5 Sekunden lang bewässern"
  • "Alexa, frag Kräuterkiste welche Pflanzen bewässert werden müssen " - Antwort:"Werk 1 ist trocken, Werk 3 ist trocken, ..."
  • "Alexa, frag Kräuterkiste wann die letzte Bewässerung von mein Basilikum " - Antwort:"Die letzte Bewässerung von Basilikum war vor 36 Stunden"
  • "Alexa, sag Kräuterbox, dass sie die Lampe einschalten soll " - Antwort:"Pflanzenlampe eingeschaltet"

Alexa nach der Luftfeuchtigkeit meiner Pflanze fragen und anschließend bewässern:

Bitten Sie Alexa, die Pflanzenwachstumslampe einzuschalten:

GIFs, die das Ergebnis ohne die Videos zeigen:

Geplante Funktionen

Die folgenden Funktionen sind noch nicht implementiert, aber für die Zukunft geplant:

  • Energiesparmodus für den Arduino-Quellcode
  • Fügen Sie externe Arduino Nanos mit drahtloser Kommunikation (2,4 GHz) zur Feuchtigkeitsmessung anderer Pflanzen im Haus hinzu (die Box ist der Hub für WiFi) - nur mit Batterien
  • API für mehrere Instanzen der Kräuterkiste erweitern, für Freunde (und wen auch immer, wenn Sie interessiert sind?!)
  • Schaltfläche zum Bewässern und Umschalten der Lampe auf der Box ohne Website oder Alexa hinzufügen
  • Alexa-Bilder (Karte in Fertigkeitsantwort)

Update 23.03.2018

Ich habe zwei neue Absichten hinzugefügt. Einer davon ist wichtig für das geplante Feature von externen Adruino Nanos, die nur die Luftfeuchtigkeit aufzeichnen.

  • Welche Pflanzen sind trocken
  • Wann war die letzte Bewässerung

Code

  • EcoActionBuffer.h
  • EcoActionBuffer.cpp
  • Plant.cpp
  • Werk.h
  • WhiteWalnut.ino
  • WhiteWalnutApi.cpp
  • WhiteWalnutApi.h
EcoActionBuffer.hArduino
#ifndef ECOACTIONBUFFER_H#define ECOACTIONBUFFER_H#include "Arduino.h"#include "StensTimer.h"struct EcoActionBuffer :public IStensTimerListener { long entryNo; int Aktion; int-Pin; lange Dauer; void timerCallback (Timer* Timer); void switchPin(int pin, bool value); void readStack(); Void-Prozess(); void toSerial(); void reset();};#endif
EcoActionBuffer.cppArduino
#include "EcoActionBuffer.h"#include "StensTimer.h"#include "WhiteWalnutApi.h"#define ACTION_ECOACTION_READ 1#define ACTION_ECOACTION_HIGH 2#define ACTION_ECOACTION_LOW 3void EcoActionBuffer::();readStack() { reset(); WhiteWalnutApi::receiveActionFromStack(*this); if (entryNo !=0) { process(); // WhiteWalnutApi::updateActionOnStack(*this); // aus Performancegründen deaktiviert }}void EcoActionBuffer::process() { toSerial(); PinMode (Pin, AUSGANG); digitalWrite (Stift, HIGH); switch (action) { case ACTION_ECOACTION_HIGH:switchPin (pin, true); brechen; Fall ACTION_ECOACTION_LOW:switchPin(pin, false); brechen; } if (Dauer !=0) { StensTimer::getInstance()->setTimer(this, -pin, Dauer); }}void EcoActionBuffer::timerCallback(Timer* timer) { switch (timer->getAction()) { case ACTION_ECOACTION_READ:readStack(); brechen; } if (timer->getAction() <0) { switchPin(abs(timer->getAction()), false); }}void EcoActionBuffer::switchPin (int pin, bool value) { switch (value) { case true:digitalWrite (pin, LOW); brechen; case false:digitalWrite (pin, HIGH); brechen; } WhiteWalnutApi::switchPin(pin, value);}void EcoActionBuffer::reset() { entryNo =0; Aktion =0; Stift =0; Dauer =0;} EcoActionBuffer::toSerial() ungültig {Serial.print(entryNo); Serial.print (F ( " - Aktion:")); Serial.print (Aktion); Serial.print (F (, Pin:")); Serial.print (Stift); Serial.print (F (, Dauer:")); Serial.print (Dauer); Serial.println();}
Plant.cppArduino
#include "Plant.h"#include "StensTimer.h"#include "WhiteWalnutApi.h"#define ACTION_PLANT_CHECKHUMIDITY 2#define PIN_HUMIDITY_VCC 12void Plant::checkHumidity() { if (humidityDataPin !=0) { Serial.print (Code); Serial.print (F ( " - Luftfeuchtigkeit prüfen ...")); digitalWrite (PIN_HUMIDITY_VCC, HOCH); Verzögerung (200); // TODO int Luftfeuchtigkeit =1023 - analogRead (humidityDataPin); digitalWrite (PIN_HUMIDITY_VCC, NIEDRIG); Serial.println (Luftfeuchtigkeit); WhiteWalnutApi::sendHumidity(*this, Luftfeuchtigkeit); if (humidityCheckInterval ==0) FeuchtigkeitCheckInterval =60000; StensTimer::getInstance()->setTimer(dies, ACTION_PLANT_CHECKHUMIDITY, FeuchtigkeitCheckInterval); } else StensTimer::getInstance()->setTimer(this, ACTION_PLANT_CHECKHUMIDITY, 60000);}void Plant::updateApi() { WhiteWalnutApi::updatePlant(*this); // WhiteWalnutApi::sendHeartbeat(*this); // für Performance deaktiviert pinMode(PIN_HUMIDITY_VCC, OUTPUT); toSerial();}void Plant::timerCallback(Timer* timer) { switch (timer->getAction()) { case ACTION_PLANT_CHECKHUMIDITY:checkHumidity(); brechen; }}void Plant::toSerial() {Serial.print (Code); Serial.print (F ( " - DataPin:")); Serial.print (humidityDataPin); Serial.print (F (, Intervall:")); Serial.print (humidityCheckInterval); Serial.println();}
Plant.hArduino
#ifndef PLANT_H#define PLANT_H#include "Arduino.h"#include "StensTimer.h"struct Plant :public IStensTimerListener { const char* code; int FeuchteDataPin; langes FeuchtigkeitsCheckInterval; void checkHumidity(); void timerCallback (Timer* Timer); void toSerial(); void updateApi();};#endif
WhiteWalnut.inoArduino
#include "EcoActionBuffer.h"#include "Plant.h"#include "StensTimer.h"#include "WhiteWalnutApi.h"struct TimerHelper :public IStensTimerListener { public:void updateApi(); void timerCallback(Timer* timer);};StensTimer* stensTimer;TimerHelper apiTimer;Plant leftPlant;Plant centerPlant;Plant rightPlant;Plant externalPlant;EcoActionBuffer actionBuffer;#define ACTION_PLANT_UPDATE 1#define ACTION_ECOACTION_UPDATE 1#define ACTION_ECOACTION_UPDATE 1#define ACTION_ECOACTION_0; while (!Seriell); stensTimer =StensTimer::getInstance(); leftPlant.code ="LINKS"; centerPlant.code ="ZENTRUM"; rightPlant.code ="RECHTS"; externalPlant.code ="EXTERNAL"; while(!WhiteWalnutApi::connectToWiFi()) delay(2000); WhiteWalnutApi::switchPin(0, false); apiTimer.updateApi(); leftPlant.checkHumidity(); centerPlant.checkHumidity(); rightPlant.checkHumidity(); externalPlant.checkHumidity(); actionBuffer.readStack(); StensTimer::getInstance()->setInterval(&apiTimer, ACTION_PLANT_UPDATE, 60000); StensTimer::getInstance()->setInterval(&actionBuffer, ACTION_ECOACTION_READ, 1000);}void loop() { stensTimer->run();}void TimerHelper::updateApi() { leftPlant.updateApi(); centerPlant.updateApi(); rightPlant.updateApi(); externalPlant.updateApi();}void TimerHelper::timerCallback(Timer* timer){ switch (timer->getAction()) { case ACTION_PLANT_UPDATE:updateApi(); brechen; }}
WhiteWalnutApi.cppArduino
Sie müssen Ihre WLAN- und API-Einstellungen hinzufügen
#include "Arduino.h"#include "ArduinoJson.h"#include "EcoActionBuffer.h"#include "MemoryFree.h"#include "Plant.h"#include " SoftwareSerial.h"#include "WhiteWalnutApi.h"SoftwareSerial espSerial(3, 2);const char* ssid ="";const char* pass ="";const char* API_SERVER ="";const char* API_PLANT ="";const char* API_ACTION ="";char* findOK ="OK";char* findRY ="ready";char* findGT =">";char* findDP =":";char* findHD ="\r\n\r\n";char* findBT ="\r\n"; bool WhiteWalnutApi::connectToWiFi() { espSerial.begin(9600); espSerial.setTimeout(3000); while (espSerial.available ()) Serial.write (espSerial.read ()); Serial.println (F("[ESP] Verbindung mit WiFi")); espSerial.println(F("AT+CIPSTATUS=2")); if (!espSerial.find(findOK)) { espSerial.setTimeout (10000); Serial.println (F ("[ESP] Reset-Modul")); espSerial.println(F("AT+RST")); if (!espSerial.find(findRY)) {Serial.println (F("[ESP] Reset fehlgeschlagen")); falsch zurückgeben; } Serial.println (F ("[ESP] CWMode einstellen")); espSerial.println(F("AT+CWMODE=1")); if (!espSerial.find(findOK)) {Serial.println (F("[ESP] Modus fehlgeschlagen")); falsch zurückgeben; } Serial.println (F ("[ESP] Mit Router verbinden")); espSerial.print(F("AT+CWJAP=\"")); espSerial.print(ssid); espSerial.print(F("\",\"")); espSerial.print(pass); espSerial.println ("\""); if (!espSerial.find(findOK)) {Serial.println(F("[ESP] WiFi-Verbindung fehlgeschlagen")); falsch zurückgeben; } } espSerial.setTimeout(3000); Serial.println (F ("[ESP] WiFi ist verbunden")); return true;}void WhiteWalnutApi::updatePlant(Plant&plant) { String site =String(API_PLANT) + "?action=get&code=" + String(plant.code); while (!httpRequest(site)) connectToWiFi(); JsonObject&root =parseJson(); if (root.success()) { plant.humidityDataPin =root["dataPin"].as(); plant.humidityCheckInterval =atol(root["interval"].as()); }}void WhiteWalnutApi::sendHumidity(Plant&plant, int Humidity) { String site =String(API_PLANT) + "?action=humidity&code=" + String(plant.code) + "&humidity=" + String(humidity); while (!httpRequest(site)) connectToWiFi(); // TODO:REMOVE RETURN}void WhiteWalnutApi::sendHeartbeat(Plant&plant) { String site =String(API_PLANT) + "?action=heartbeat&code=" + String(plant.code); while (!httpRequest(site)) connectToWiFi();}void WhiteWalnutApi::receiveActionFromStack(EcoActionBuffer&actionBuffer) { while (!httpRequest(String(API_ACTION))) connectToWiFi(); JsonObject&root =parseJson(); if (root.success()) { actionBuffer.entryNo =atol(root["entryNo"].as()); actionBuffer.action =root["actionEnum"].as(); actionBuffer.pin =root["pin"].as(); actionBuffer.duration =atol(root["value"].as()); }}void WhiteWalnutApi::updateActionOnStack(EcoActionBuffer&actionBuffer) { String site =String(API_ACTION) + "?action=processed&entryNo=" + String(actionBuffer.entryNo); while (!httpRequest(site)) connectToWiFi();}void WhiteWalnutApi::switchPin(int pin, bool value) { String site =String(API_ACTION) + "?action=switch&pin=" + String(pin) + "&value=" + String(Wert); while (!httpRequest(site)) connectToWiFi();}bool WhiteWalnutApi::httpRequest(String site) { // char* cmd; // sprintf(cmd, "GET %s HTTP/1.0\r\nHost:%s\r\nVerbindung:schließen", Site, API_SERVER); /* Zeichenfolge cmd =""; cmd +="GET" + Site + " HTTP/1.0\r\n"; cmd +="Host:" + String(API_SERVER) + "\r\n"; cmd +="Verbindung:schließen"; int cmdLength =cmd.length() + 4; Serial.println (cmd); */ int cmdLength =44 + site.length() + strlen(API_SERVER); // Serial.print (F("[SPEICHER]")); // Serial.print (freeMemory()); // Serial.print (F ( " - ")); // Serial.println (Site); // -> 785 für extern espSerial.print(F("AT+CIPSTART=\"TCP\",\"")); espSerial.print(API_SERVER); espSerial.println(F("\",80") ); if (!espSerial.find(findOK)) {Serial.println(F("[ESP] TCP-Verbindungsfehler")); falsch zurückgeben; } espSerial.print(F("AT+CIPSEND=")); espSerial.println(cmdLength); // espSerial.println(strlen(cmd)); if (!espSerial.find(findGT)) { Serial.println(F("[ESP] Send State Error")); falsch zurückgeben; } espSerial.print(F("GET ")); espSerial.print(site); espSerial.print(F(" HTTP/1.0\r\n")); espSerial.print(F("Host:")); espSerial.print(API_SERVER); espSerial.print(F("\r\n")); espSerial.print(F("Connection:close\r\n")); espSerial.println(); // while (espSerial.available()) Serial.println(espSerial.readString()); Rückkehr; if (!espSerial.find(findDP)) { Serial.println(F("Bytes not sent")); espSerial.print(F("AT+CIPCLOSE")); falsch zurückgeben; } char status[32] ={0}; espSerial.readBytesUntil('\r', status, sizeof(status)); if (strcmp(status, "HTTP/1.1 200 OK") !=0) { Serial.print(F("[ESP] Unexpected response:")); Serial.println(status); falsch zurückgeben; } // Check HTTP status if (!espSerial.find(findHD)) { Serial.println(F("[ESP] Invalid response")); falsch zurückgeben; } // Skip HTTP headers // if (!espSerial.find(findBT)) { Serial.println(F("[ESP] Bytes not found")); Rückkehr; } // skip bytes (for http 1.1) return true;}JsonObject&WhiteWalnutApi::parseJson() { const size_t capacity =JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60; DynamicJsonBuffer jsonBuffer(capacity); JsonObject&root =jsonBuffer.parseObject(espSerial); if (!root.success()) Serial.println(F("Parsing failed!")); return root;}
WhiteWalnutApi.hArduino
#ifndef WHITEWALNUTAPI_H#define WHITEWALNUTAPI_H#include "Arduino.h"#include "ArduinoJson.h"#include "EcoActionBuffer.h"#include "Plant.h"class WhiteWalnutApi { public:static bool connectToWiFi(); static void updatePlant(Plant&plant); static void sendHumidity(Plant&plant, int humidity); static void sendHeartbeat(Plant&plant); static void receiveActionFromStack(EcoActionBuffer&actionBuffer); static void updateActionOnStack(EcoActionBuffer&actionBuffer); static void switchPin(int pin, bool value); private:static bool httpRequest(String site); static JsonObject&parseJson();};#endif

Schaltpläne

Chart about the communication and interfaces All implemented intents you can ask Alexa, including the response.
(multilingual) If you are interested in the entrance step of your alexa json parsing.

Herstellungsprozess

  1. Webbetriebener DMX-Controller
  2. Arduino Spybot
  3. Arduino-Alarmsystem:SERENA
  4. Arduino + ESP Weather Box
  5. Keller-/Kriechraum-Lüftungssystem
  6. Anwesenheitssystem basierend auf Arduino und Google Spreadsheet
  7. BLUE_P:Drahtloses Arduino-Programmierschild
  8. Arduino-basiertes Kollisionserkennungs-Warnsystem
  9. TFT-Shield für Arduino Nano - Start
  10. Arduino Shield NCS314 NIXIE Röhren Uhr IN-14