Nachricht über WhatsApp

Hallo!
Hab ein Luft- und Bodenfeuchte-Sensor-Projekt.
Funktioniert ganz gut.
Wollte den Sketch jetzt so erweitern, dass ich eine WhatsApp-Nachricht bekomme, wenn die Bodenfeuchte unter einen bestimmten Wert fällt.
Das klappt auch, jedoch bekomme ich je nach delay (z.B.10000) im loopbereich (misst jeweils Temp., Luft-und Bodenfeuchte) entsprechend Nachrichten.
Möchte allerdings nur eine Nachricht erhalten.

Grüße

Klaus

Merke Dir in einer Variablen, dass die Nachricht geschickt wurde. Irgendwann musst Du diese aber wieder zurück setzen, sonst bekommst Du nie wieder Nachrichten.

Gruß Tommy

Moin @MogliW ,

habe mal ein kleines Beispiel geschrieben:

/*
  Forum: https://forum.arduino.cc/t/nachricht-uber-whatsapp/1245021
  Wokwi: https://wokwi.com/projects/394537395212181505
*/
const int  alarmFeuchte  = 500;
const int  normalFeuchte = 600;
const byte feuchtePin = A0;
const char * msgTrocken = "Zu trocken!";
const char * msgOk      = "Ok";
const unsigned long messIntervall  =   100;
const unsigned long meldeIntervall = 10000;

boolean msgTrockenGesendet = false;
boolean msgOkGesendet = false;

unsigned long letzteMeldung = 0;
unsigned long letzteMessung = 0;
int messWert;

void setup() {
  Serial.begin(115200);
  pinMode(feuchtePin, INPUT);
}

void loop() {
  if (millis() - letzteMessung >= messIntervall) {
    letzteMessung = millis();
    messWert = analogRead(feuchtePin);
    switch (messWert) {
      case 0 ... alarmFeuchte:
        sendeTrocken();
        break;
      /*
             Hier ist eine Lücke zwischen alarmFeuchte und normalFeuchte,
             die verhindert, dass man bei kleinen Schwankungen um einen Schwellwert
             ständig Nachrichten erhält (Stichwort: Hysterese)
      */
      case normalFeuchte ... 1023:
        sendeOk();
        break;
      /*
        Bei default kommt man an, wenn man im "Graubereich" zwischen alarmFeuchte
        und normalFeuchte ist; beim Start (beide boolsche Variable auf false) senden
        wir dann einfach "Ok"
      */
      default:
        if (!msgTrockenGesendet && !msgOkGesendet) {
          sendeOk();
        }
        break;
    }
  }
  // Zusätzliche Zeitsteuerung
  if (millis() - letzteMeldung >= meldeIntervall) {
    msgTrockenGesendet = false;
    msgOkGesendet = false;
  }
}

void sendeOk() {
  if (!msgOkGesendet) {
    letzteMeldung = millis();
    Serial.println(msgOk);
    msgOkGesendet = true;
    msgTrockenGesendet = false;
  }
}

void sendeTrocken() {
  if (!msgTrockenGesendet) {
    letzteMeldung = millis();
    Serial.println(msgTrocken);
    msgOkGesendet = false;
    msgTrockenGesendet = true;
  }
}

Kannst Du auf Wokwi testen: https://wokwi.com/projects/394537395212181505

Es gibt zwei Meldungen (Ok und Trocken), die sich gegenseitig wieder freigeben; heißt, dass man zunächst den jeweils anderen Zustand erreichen muss, damit es wieder eine Meldung (der anderen Art) gibt.

Ausserdem ist noch beispielhaft eine Zeitsteuerung drin, die nach einer vorgegebenen Zeit wieder eine Meldung freigibt.

Gemessen wird hier alle 0,1s, Wiederholungen der Nachrichten sind auf 10 s gestellt.

Viel Spaß damit :wink:
ec2021

Das würde mich interessieren...
(Serial.print kann ich schon)

Hallo ec2021!
Herzlichen Dank zunächst für deine Bemühungen.
Hab dem Programm einige Infos entnommen und werde versuchen, das in meinem Sketch unterzubringen. Mein Programmierniveau ist allerdings nicht sehr hoch.
In deinem Code ist die Ausgabe über den seriellen Monitor, ich möchte lediglich eine Nachricht über WhatsApp.
Hier mal mein "void loop" aus dem Sketch.
Hab hier einen delay von 1 Sekunde und bekomme jetzt auch neben der Aktualisierung über die Zeile " sendMessage("Gieß mich bitte!!!");" jede Sekunde eine Nachricht an WhatsApp.
Eine Nachricht reicht!

void loop() 
{

  // Wartezeit vor der Messung
  delay(1000);

  // Sensor wird ausgelesen. Hier nur Celsius, Fahrenheit ist auskommentiert (|| isnan(f)).
  float h = dht.readHumidity();
  // Temperatur in Celsius (default)
  float t = dht.readTemperature();
  // Temperatur in Fahrenheit (isFahrenheit = true)
  //float f = dht.readTemperature(true);

  // Fehlersuchlauf und Abbruch mit Meldung.
  if (isnan(h) || isnan(t) ) {
    Serial.println(F("Fehler beim Auslesen des Sensors!"));
    return;
  }

  float hic = dht.computeHeatIndex(t, h, false);
  Serial.println(WiFi.localIP());
  Serial.print(F("Temperatur: "));
  Serial.print(t);
  Serial.println(F("°C "));
  Serial.print(F("Luftfeuchtigkeit: "));
  Serial.print(h);
  Serial.println(F("% "));
  
  Sensorwert = analogRead(SensorPin);  //Sensor in die Erde
  Serial.println(Sensorwert);

     
if(Sensorwert < 340)
{
  Serial.println("Pflanze gut gewässert!");
  digitalWrite(Led , LOW);
  client.println("<center>");
  client.println("<H3><span style='color: #00FF00;'>Pflanze gut gewässert!!</span></H3>");
}
else if(Sensorwert > 340)
{
  Serial.println("Bitte gießen!!!");
  digitalWrite(Led , HIGH);
  
  sendMessage("Gieß mich bitte!!!");
}

So far have a nice Day ;_))`

Schick die Meldung nicht bei Sensorwert > 340 sondern einmal, wenn du 340 überschreitest.

setze ein Flag active = false dass du gesendet hast (deaktiviere die Verständigung)
Wenn du wieder auf <= 340 kommst, setzt du das Flag active = true (deine Anlage ist wieder scharf)

und im If Sensorwert > 340 prüfst du zusätzlich auf active

if(Sensorwert > 340 && active)
{

Na gut, dann eben nicht. Wie man in loop nur bei Bedarf Serial.print oder eine andere Funktion aufruft, ist jetzt nicht sooo interessant, finde ich.

Kurz google bemüht und whatabot.io gefunden, die sich freuen (4.00$ / 1500 Nachrichten), jemandem eine whatsapp senden zu dürfen. Mit einem ESP mit Internetzugang ist der Rest dann einfach.

Falls du (@MogliW) was anderes verwendest, sag bitte Bescheid. Danke.

Hab Dir das mal in Deinen Code-Auszug eingearbeitet (nicht getestet, das ist bei Teilsketchen immer etwas aufwendig ...):

boolean okgesendet = false;
boolean trockengesendet = false;

void loop() 
{

  // Wartezeit vor der Messung
  delay(1000);

  // Sensor wird ausgelesen. Hier nur Celsius, Fahrenheit ist auskommentiert (|| isnan(f)).
  float h = dht.readHumidity();
  // Temperatur in Celsius (default)
  float t = dht.readTemperature();
  // Temperatur in Fahrenheit (isFahrenheit = true)
  //float f = dht.readTemperature(true);

  // Fehlersuchlauf und Abbruch mit Meldung.
  if (isnan(h) || isnan(t) ) {
    Serial.println(F("Fehler beim Auslesen des Sensors!"));
    return;
  }

  float hic = dht.computeHeatIndex(t, h, false);
  Serial.println(WiFi.localIP());
  Serial.print(F("Temperatur: "));
  Serial.print(t);
  Serial.println(F("°C "));
  Serial.print(F("Luftfeuchtigkeit: "));
  Serial.print(h);
  Serial.println(F("% "));
  
  Sensorwert = analogRead(SensorPin);  //Sensor in die Erde
  Serial.println(Sensorwert);
     
if((Sensorwert < 340) && !okgesendet)
{
  Serial.println("Pflanze gut gewässert!");
  digitalWrite(Led , LOW);
  client.println("<center>");
  client.println("<H3><span style='color: #00FF00;'>Pflanze gut gewässert!!</span></H3>");
  okgesendet = true;
  trockengesendet = false;
}
// auf das "else" können wir verzichten, da Sensorwert nur grösser/gleich oder kleiner sein kann
// Allerdings bedeutet eine(!) Schwelle, dass bei wechselnden Werten um 340 (341, 339, 342, 338)
// am Schwellwert häufig Meldungen kommen (Stichwort Hysterese!!! Mal googeln!!!)
// Beim Messwert 340 kommt übrigens nix, da oben nur auf kleiner, unten auf grösser reagiert wird ...
// Mag selten vorkommen, ist aber eine prinzipielle Fehlerquelle.
if ((Sensorwert > 340) && !trockengesendet)
{
  Serial.println("Bitte gießen!!!");
  digitalWrite(Led , HIGH);
  okgesendet = false;
  trockengesendet = true;
  sendMessage("Gieß mich bitte!!!");
}

Bitte die Kommentare lesen; eine Hysterese habe ich nicht eingebaut, das kannst Du ändern, indem zwischen den Schwellwerten eine Lücke lässt und noch den folgenden Code in loop einfügst (das ist insgesamt optimierbar, indem man die Ausgaben für trocken und gut bewässert in separate Funktionen auslagert und so von verschiedenen Stellen einfach aufrufen kann; hier die unschöne "Copy'nPaste" Variante):

if (!trockengesendet && !okgesendet) {
  if (Sensorwert > 340) {
    Serial.println("Bitte gießen!!!");
    digitalWrite(Led, HIGH);
    okgesendet = false;
    trockengesendet = true;
    sendMessage("Gieß mich bitte!!!");
  } else {
    Serial.println("Pflanze gut gewässert!");
    digitalWrite(Led, LOW);
    client.println("<center>");
    client.println("<H3><span style='color: #00FF00;'>Pflanze gut gewässert!!</span></H3>");
    okgesendet = true;
    trockengesendet = false;
  }
}

Wenn Du den kompletten Sketch posten würdest, könnte man das einbauen und testen ... :wink:

Ansonsten steht schon alles Wesentliche bei meinem obigen Beispiel.

Guten Morgen ec2021!
Meinen Herzlichsten für deine Bemühungen.
Ich erkenne, dass ich es mit einem Profi zu tun habe.
Brauche da meine Zeit, um alles zuzuordnen bzw. anzuwenden.
Bin LOW-Level unterwegs.
Manche Dinge scheinen so einfach;
Hier mal der bis jetzt lauffähige Sketch;

const int Lw = 595;   //Anpassen des Wertes, den der Sensor in der Luft (trocken) anzeigt (serieller Monitor). 
const int Fw = 270;  // Anpassen des Wertes, den der Sensor in der gewässerten Erde (nass) anzeigt (serieller Monitor).
const int SensorPin = A0;
const int Led = 14; //"D5" am ESP8266

int Sensorwert = 0;

#include <DHT.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <UrlEncode.h>

#define DHTPIN 4        // Ist am ESP8266 "D2"!
#define DHTTYPE DHT11   // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE);

const char* ssid = "";
const char* password = "";

WiFiServer server(80);

// +international_country_code + phone number
// Portugal +351, example: +351912345678
String phoneNumber = "";
String apiKey = "";

void sendMessage(String message){

  
  String url = "http://api.callmebot.com/whatsapp.php?phone=" + phoneNumber + "&apikey=" + apiKey + "&text=" + urlEncode(message);
  WiFiClient client;    
  HTTPClient http;
  http.begin(client, url);

 
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  
  // Send HTTP POST request
  int httpResponseCode = http.POST(url);
  if (httpResponseCode == 200){
    Serial.print("Message sent successfully");
   
  }
  
  else{
    Serial.println("Error sending the message");
    Serial.print("HTTP response code: ");
    Serial.println(httpResponseCode);
  }

  // Free resources
  http.end();
}

void setup() 
{
  Serial.begin(115200); 
  pinMode(Led , OUTPUT);
  dht.begin(); 
  WiFi.mode(WIFI_STA);
  
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  server.begin();
  Serial.println("Server started");

  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());

}

void loop() 
{

  // Wartezeit vor der Messung
  delay(10000);

  // Sensor wird ausgelesen. Hier nur Celsius, Fahrenheit ist auskommentiert (|| isnan(f)).
  float h = dht.readHumidity();
  // Temperatur in Celsius (default)
  float t = dht.readTemperature();
  // Temperatur in Fahrenheit (isFahrenheit = true)
  //float f = dht.readTemperature(true);

  // Fehlersuchlauf und Abbruch mit Meldung.
  if (isnan(h) || isnan(t) ) {
    Serial.println(F("Fehler beim Auslesen des Sensors!"));
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  // float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);
  Serial.println(WiFi.localIP());
  Serial.print(F("Temperatur: "));
  Serial.print(t);
  Serial.println(F("°C "));
  Serial.print(F("Luftfeuchtigkeit: "));
  Serial.print(h);
  Serial.println(F("% "));
  
  Sensorwert = analogRead(SensorPin);  //Sensor in die Erde
  Serial.println(Sensorwert);

  String cmd;
  cmd += "\"";

  WiFiClient client = server.available();
  client.println("HTTP/1.1 200 OK");
  client.println();
  client.println("<!DOCTYPE html><html>");
  client.println("<head><meta name =\"viewport\" content=\"width=device-width, initial-scale=1\">");
  client.println("<meta charset=utf-8 />");
  client.println("<head><meta http-equiv=\"refresh\" content=\"10\">");
  client.println("<link rel=\"icon\" href\"data:,\">");
  client.println("<title>PlantBox</title>");
  client.println("<body>");
  client.println("<span style='color: #199BDE;'>");
  client.println("<H2><u><center><span style='color: #ff5733;'>PlantBox</span></center></u></H2>");
  client.println("<h4><center>Temperatur:");
  client.println(dht.readTemperature()-5);                                // Ausgeben der Temperatur
  client.println("°");                // Schreiben des ° Zeichen
  //client.println("C</h4></center>");
  client.println("<h4><center>Luftfeuchte:");
  client.println(dht.readHumidity());                                // Ausgeben der Temperatur
  client.print("%");                // Schreiben des ° Zeichen
  client.println("<h4><center>Bodenfeuchte:");
  client.println(analogRead(SensorPin));
  client.println("</h4></center>");

    
if(Sensorwert <= 500)
{
  Serial.println("Pflanze gut gewässert!");
  digitalWrite(Led , LOW);
  client.println("<center>");
  client.println("<H3><span style='color: #00FF00;'>Pflanze gut gewässert!!</span></H3>");
}
if(Sensorwert >= 340)
{
  Serial.println("Bitte gießen!!!");
  digitalWrite(Led , HIGH);
  client.println("<center>");
  client.println("<H3><span style='color: #FF0000;'>Bitte gieß mich!</span></H3>");
  **sendMessage("Gieß mich bitte!!!");**
}
  client.print("</body>\n</html>");  
}

Die Anweisung sendMessage("Gieß mich bitte!!!"); soll mir nur einmal geschickt werden.

Wünsche einen schönen Tag!!! ;_)) Klaus

Moin Klaus,

hier Dein bezogen auf die Meldungen überarbeiteter Sketch (kompiliert, ansonsten nicht getestet):


/*
 Da diese Konstanten im Sketch nicht verwendet werden, sondern stattdessen feste Werte (340, 500) eingetragen wurden, habe ich neue Konstanten mit selbst sprechenden Namen eingeführt:

const int Lw = 595;  //Anpassen des Wertes, den der Sensor in der Luft (trocken) anzeigt (serieller Monitor).
const int Fw = 270;  // Anpassen des Wertes, den der Sensor in der gewässerten Erde (nass) anzeigt (serieller Monitor).

Weiteres dazu in einem Kommentar weiter unten

*/
const int SensorPin = A0;
const int Led = 14;  //"D5" am ESP8266

int Sensorwert = 0;

#include <DHT.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <UrlEncode.h>

#define DHTPIN 4       // Ist am ESP8266 "D2"!
#define DHTTYPE DHT11  // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE);

const char* ssid = "";
const char* password = "";

WiFiServer server(80);

// +international_country_code + phone number
// Portugal +351, example: +351912345678
String phoneNumber = "";
String apiKey = "";

boolean schonWasGemeldet = false;
boolean giessMichGesendet = false;
const int schaltSchwelle = 420;
const int toleranz = 20;

void sendMessage(String message) {


  String url = "http://api.callmebot.com/whatsapp.php?phone=" + phoneNumber + "&apikey=" + apiKey + "&text=" + urlEncode(message);
  WiFiClient client;
  HTTPClient http;
  http.begin(client, url);


  http.addHeader("Content-Type", "application/x-www-form-urlencoded");

  // Send HTTP POST request
  int httpResponseCode = http.POST(url);
  if (httpResponseCode == 200) {
    Serial.print("Message sent successfully");

  }

  else {
    Serial.println("Error sending the message");
    Serial.print("HTTP response code: ");
    Serial.println(httpResponseCode);
  }

  // Free resources
  http.end();
}

void setup() {
  Serial.begin(115200);
  pinMode(Led, OUTPUT);
  dht.begin();
  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  server.begin();
  Serial.println("Server started");

  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
}

void loop() {

  // Wartezeit vor der Messung
  delay(10000);

  // Sensor wird ausgelesen. Hier nur Celsius, Fahrenheit ist auskommentiert (|| isnan(f)).
  float h = dht.readHumidity();
  // Temperatur in Celsius (default)
  float t = dht.readTemperature();
  // Temperatur in Fahrenheit (isFahrenheit = true)
  //float f = dht.readTemperature(true);

  // Fehlersuchlauf und Abbruch mit Meldung.
  if (isnan(h) || isnan(t)) {
    Serial.println(F("Fehler beim Auslesen des Sensors!"));
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  // float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);
  Serial.println(WiFi.localIP());
  Serial.print(F("Temperatur: "));
  Serial.print(t);
  Serial.println(F("°C "));
  Serial.print(F("Luftfeuchtigkeit: "));
  Serial.print(h);
  Serial.println(F("% "));

  Sensorwert = analogRead(SensorPin);  //Sensor in die Erde
  Serial.println(Sensorwert);
 
  WiFiClient client = server.available();
  client.println("HTTP/1.1 200 OK");
  client.println();
  client.println("<!DOCTYPE html><html>");
  client.println("<head><meta name =\"viewport\" content=\"width=device-width, initial-scale=1\">");
  client.println("<meta charset=utf-8 />");
  client.println("<head><meta http-equiv=\"refresh\" content=\"10\">");
  client.println("<link rel=\"icon\" href\"data:,\">");
  client.println("<title>PlantBox</title>");
  client.println("<body>");
  client.println("<span style='color: #199BDE;'>");
  client.println("<H2><u><center><span style='color: #ff5733;'>PlantBox</span></center></u></H2>");
  client.println("<h4><center>Temperatur:");
  client.println(dht.readTemperature() - 5);  // Ausgeben der Temperatur
  client.println("°");                        // Schreiben des ° Zeichen
  //client.println("C</h4></center>");
  client.println("<h4><center>Luftfeuchte:");
  client.println(dht.readHumidity());  // Ausgeben der Temperatur
  client.print("%");                   // Schreiben des ° Zeichen
  client.println("<h4><center>Bodenfeuchte:");
  client.println(analogRead(SensorPin));
  client.println("</h4></center>");


  /*
    Das hier ist so nicht ok:
    =====================================
    if (Sensorwert <= 500) {
      // Gut bewässert
    }
    if (Sensorwert >= 340) {
      // zu trocken
    }
    =====================================

    Beispiel: Der Sensorwert 400 ist kleiner als 500 aber auch grösser als 340.
              Damit ist gleichzeitig sowohl alles gut bewässert wie auch zu trocken ...
              Die Wertebereiche dürfen sich nicht überschneiden; eine Lücke 
              ist jedoch zulässig, wenn man sie von Anfang an richtig 
              behandelt. 

    Ich gehe mangels besseren Wissens davon aus, dass die Schwelle zwischen 
    "gut bewässert" und "zu trocken" in der Mitte bei (500+340)/2 = 420 liegt.

    Als Hysteresetoleranz setze ich provisorisch einen Wert von +/-20 an:

    * Untere Schaltschwelle 420-20 = 400 
    * Obere Schaltschwelle  420+20 = 440

    Bei Bedarf anpassen bei den Konstanten (siehe oben)

    const int schaltSchwelle = 420;
    const int toleranz       = 20;

  */
  switch (Sensorwert) {
    case 0 ... schaltSchwelle - toleranz:  // Wertebereich für gut bewässert
      allesOk(client);
      break;
    case schaltSchwelle - toleranz + 1 ... schaltSchwelle + toleranz - 1:  // Hysterese
      // Wenn wir gleich nach einem Neustart hier landen, signalisieren wir
      // dass alles Ok ist. Später passiert hier nichts mehr
      if (!schonWasGemeldet) {
        allesOk(client);
      }
      break;
    case schaltSchwelle + toleranz... 1023:  // Wertebereich für definitiv zu trocken
      giessMich(client);
      break;
  }
}

void giessMich(WiFiClient& aClient) {
  Serial.println("Bitte gießen!!!");
  digitalWrite(Led, HIGH);
  aClient.println("<center>");
  aClient.println("<H3><span style='color: #FF0000;'>Bitte gieß mich!</span></H3>");
  aClient.print("</body>\n</html>");
  schonWasGemeldet = true;
  if (!giessMichGesendet) {
    giessMichGesendet = true;
    sendMessage("Gieß mich bitte!!!");
  }
}

void allesOk(WiFiClient& aClient) {
  giessMichGesendet = false;
  schonWasGemeldet = true;
  Serial.println("Pflanze gut gewässert!");
  digitalWrite(Led, LOW);
  aClient.println("<center>");
  aClient.println("<H3><span style='color: #00FF00;'>Pflanze gut gewässert!!</span></H3>");
  aClient.print("</body>\n</html>");
}

Zwei Hinweise:

  • Generell sollte man bei Fragen hier im Forum den kompletten Sketch posten. Häufig sind bei Teil-Sketchen relevante Teile im "Verborgenen" zu finden. Wenn man grundsätzlich Schwierigkeiten hat, erforderlichen Anpassungen selbst einzubauen, ist das Posten des kompletten Sketches eher zwingend.
  • Es würde sich empfehlen, getrennte Funktionen für das Timing (millis() statt delay()), das Einlesen der Sensorwerte, das Erstellen der Webseite und die Auswertung des Feuchtesensors zu erstellen und dies alles nicht unübersichtlich in der loop() aneinanderzureihen ... Das würde Übersicht und Pflegbarkeit des Codes deutlich verbessern ... Dazu müsstest Du Dich vielleicht von LOW auf MEDIUM Level hocharbeiten. Es kommt halt darauf an, ob Du eher an einem Einzelprojekt interessiert bist, oder aber für die Zukunft weitere Arbeiten in Planung hast, die Du ganz oder zumindest weitgehend ohne externe NI ("Natürliche Intelligenz", eine alte, vom Aussterben bedrohte Technik) erarbeiten möchtest :wink:

Ob der Sketch gleich in Deinem Sinne funktioniert, kann ich ohne eigenen Test nicht gesichert sagen. Gerne mal testen. In den Kommentaren steht etwas zu den Änderungen und Ergänzungen.

Gruß
ec2021

P.S.: Das Handling der Webseite ist m.E. auch nicht ok....

Hier ein komplett überarbeiteter Sketch, der kompiliert und (ohne den DHT11 angeschlossen zu haben) grundsätzlich läuft. Für die Anwendung auf einem meiner ESP32 habe ich die Möglichkeit der bedingten Compilierung per #define genutzt. Da #define ESP32USED auskommentiert ist, sollte es bei Dir für den ESP8266 ohne Änderungen kompilieren. SSID/Passwort-Daten musst Du natürlich noch eintragen.

Der integrierte Webserver funktioniert grundsätzlich, könnte aber noch optimiert werden; das bräuchte etwas mehr Zeit ...

Modifizierter Sketch
//#define ESP32USED

#include <DHT.h>

#ifdef ESP32USED

#include <WiFi.h>
#include <HTTPClient.h>
#include "WiFiSecrets.h"
const byte SensorPin = 34;

#else

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

const char* ssid = "";
const char* password = "";
const byte SensorPin = A0;

#endif

#include <WiFiClient.h>
#include <UrlEncode.h>

#define DHTPIN 4       // Ist am ESP8266 "D2"!
#define DHTTYPE DHT11  // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE);

WiFiServer server(80);

// +international_country_code + phone number
// Portugal +351, example: +351912345678
String phoneNumber = "";
String apiKey = "";

const int schaltSchwelle = 420;
const int toleranz = 20;
const int Led = 14;  //"D5" am ESP8266
float humidity;
float temperature;
int Sensorwert = 0;
const unsigned long messIntervall = 10000;
unsigned long letzteMessung = 0;
boolean schonWasGemeldet = false;
boolean giessMichGesendet = false;
boolean dhtValid = false;
char aColor[10];  // Es braucht nur 7, aber besser etwas Luft
char aText[65];   // Auch hier einiges an Sicherheit eingebaut (bisher max. 39 Zeichen)

void setup() {
  Serial.begin(115200);
  pinMode(Led, OUTPUT);
  dht.begin();
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  server.begin();
  Serial.println("Server started");
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
  // Dieser Dummy-Text dürfte normalerweise nie erscheinen ...
  strcpy(aColor, "FF00FF");
  strcpy(aText, "----------- Bitte warten ------------");
  // Einmal vor der loop() ausführen, um klare Startbedingungen zu schaffen
  messenUndAuswerten();
}

void loop() {
  if (millis() - letzteMessung >= messIntervall) {
    messenUndAuswerten();
  }
  updateWebPage(aColor, aText);
}

void messenUndAuswerten() {
  letzteMessung = millis();
  messung();
  auswertung();
}

void messung() {
#ifdef ESP32USED
  dhtValid = false;
#else
  // Sensor wird ausgelesen
  humidity = dht.readHumidity();
  // Temperatur in Celsius (default)
  temperature = dht.readTemperature();
  // Temperatur in Fahrenheit (isFahrenheit = true)
  //temperature = dht.readTemperature(true);
  dhtValid = !(isnan(humidity) || isnan(temperature));

#endif

  // Compute heat index in Fahrenheit (the default)
  // float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahrenheit = false)
  // Der Heat Index ist die "gefühlte Temperatur"; wird hier zwar ermittelt
  // aber ansonsten nirgends verwendet ?!?!?!?
  // *********************************************
  // float hic = dht.computeHeatIndex(temperature, humidity, false);
  // *********************************************

  Sensorwert = analogRead(SensorPin);  //Sensor in die Erde
#ifdef ESP32USED
  Sensorwert = map(Sensorwert, 0, 4095, 0, 1023);
#endif

  Serial.println(WiFi.localIP());
  if (dhtValid) {
    Serial.print(F("Temperatur: "));
    Serial.print(temperature);
    Serial.println(F("°C "));
    Serial.print(F("Luftfeuchtigkeit: "));
    Serial.print(humidity);
    Serial.println(F("% "));
  } else {
    Serial.println(F("DHT11-Werte fehlerhaft"));
  }
  Serial.print("Feuchtemesswert: ");
  Serial.println(Sensorwert);
}


void auswertung() {
  switch (Sensorwert) {
    case 0 ... 19:  // Eher ein Kurzschluss ???
      fehler();
      break;
    case 20 ... schaltSchwelle - toleranz:  // Wertebereich für gut bewässert
      allesOk();
      break;
    case schaltSchwelle - toleranz + 1 ... schaltSchwelle + toleranz - 1:  // Hysterese
      // Wenn wir gleich nach einem Neustart hier landen, signalisieren wir
      // dass alles Ok ist. Später passiert hier nichts mehr
      if (!schonWasGemeldet) {
        allesOk();
      }
      break;
    case schaltSchwelle + toleranz... 1023:  // Wertebereich für definitiv zu trocken
      giessMich();
      break;
  }
}

void giessMich() {
  Serial.println("Bitte gießen!!!");
  digitalWrite(Led, HIGH);
  strcpy(aColor, "FF0000");
  strcpy(aText, "Bitte gieß mich!");
  schonWasGemeldet = true;
  if (!giessMichGesendet) {
    giessMichGesendet = true;
    sendMessage("Gieß mich bitte!!!");
  }
}

void allesOk() {
  giessMichGesendet = false;
  schonWasGemeldet = true;
  Serial.println("Pflanze gut gewässert!");
  digitalWrite(Led, LOW);
  strcpy(aColor, "00FF00");
  strcpy(aText, "Pflanze gut gewässert!!");
}

void fehler() {
  Serial.println("Fehlerhafter Sensorwert");
  digitalWrite(Led, HIGH);
  strcpy(aColor, "FF0000");
  strcpy(aText, "Fehlerhafter Sensorwert!!");
}

void updateWebPage(char* color, char* text) {
  //  WiFiClient client = server.accept();
  WiFiClient client = server.available();
  if (client) {
    if (client.connected()) {
      //    Serial.println("Client connected");
      client.println("HTTP/1.1 200 OK");
      client.println();
      client.println("<!DOCTYPE html><html>");
      client.println("<head><meta name =\"viewport\" content=\"width=device-width, initial-scale=1\">");
      client.println("<meta charset=utf-8 />");
      client.println("<head><meta http-equiv=\"refresh\" content=\"3\">");
      client.println("<link rel=\"icon\" href\"data:,\">");
      client.println("<title>PlantBox</title>");
      client.println("<body>");
      client.println("<span style='color: #199BDE;'>");
      client.println("<H2><u><center><span style='color: #ff5733;'>PlantBox</span></center></u></H2>");
      if (dhtValid) {
        client.println("<h4><center>Temperatur:");
        client.print(temperature - 5);  // Ausgeben der Temperatur
        client.println("°");            // Schreiben des ° Zeichen
        client.println("<h4><center>Luftfeuchte:");
        client.print(humidity);  // Ausgeben der Temperatur
        client.println("%");     // Schreiben des ° Zeichen
      } else {
        client.println("<h4><center>Temperatur: ungültig");
        client.println("<h4><center>Luftfeuchte: ungültig");
      }
      client.println("<h4><center>Bodenfeuchte:");
      client.println(Sensorwert);
      client.println("</h4></center>");
      char buffer[100];  // Bei längeren Ausgaben muss die Puffergröße ggf. angepasst werden!!!!!
      sprintf(buffer, "<H3><span style='color: #%s;'>%s</span></H3>", color, text);
      client.println(buffer);
      client.println("<center>\n\n");
      client.print("</body>\n</html>");
    }
    client.stop();
  }
}

void sendMessage(String message) {
#ifndef ESP32USED
  String url = "http://api.callmebot.com/whatsapp.php?phone=" + phoneNumber + "&apikey=" + apiKey + "&text=" + urlEncode(message);
  WiFiClient client;
  HTTPClient http;
  http.begin(client, url);
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  // Send HTTP POST request
  int httpResponseCode = http.POST(url);
  if (httpResponseCode == 200) {
    Serial.print("Message sent successfully");
  } else {
    Serial.println("Error sending the message");
    Serial.print("HTTP response code: ");
    Serial.println(httpResponseCode);
  }
  // Free resources
  http.end();
#endif
}

Hallo!
Sorry, dass ich mich erst jetzt zurückmelde, war in Kurzurlaub.
Hut ab vor der Kompetenz, allerherzlichsten Dank.
Melde mich, ;_)) Klaus

Hallo ec2021!
Hab versucht, deinen und meinen Code zusammenzufügen.
Zudem habe ich den DHT durch einen kombinierten CJMCU8118 ersetzt. Der misst Temp, Humid, eCo2 und Tvoc.
Und ich hab OTA eingebunden.
Mich erschlägt deine Programmierkompetenz, da die beiden Codes so weit auseinanderstehen, dass ich viele Erklärungen bräuchte, wenn ich deinen verstehen soll.
Mein bisheriges Ergebnis bis zum "jetzt weiß ich nicht mehr weiter", hab ich hier mal gepostet.

//#define ESP32USED

#include <DHT.h>
#ifdef ESP32USED
#include <WiFi.h>
#include <HTTPClient.h>
#include "WiFiSecrets.h"
const byte SensorPin = 34;

#else

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <Wire.h>    // I2C Library
#include "ccs811.h"  // CCS811 Library
#include "ClosedCube_HDC1080.h"
#include <ArduinoOTA.h>


const char* ssid = "";
const char* password = "";
const byte SensorPin = A0;

const int dry = 595; // value for dry sensor
const int wet = 270; // value for wet sensor

#endif

#include <WiFiClient.h>
#include <UrlEncode.h>

WiFiServer server(80);

CCS811 ccs811(D3); // nWAKE on D3
ClosedCube_HDC1080 hdc1080; //Aktivierung des Sensors

// +international_country_code + phone number
// Portugal +351, example: +351912345678
String phoneNumber = "";
String apiKey = "";

const int schaltSchwelle = 420;
const int toleranz = 20;
float humidity;
float temperature;
int Sensorwert = 0;
const unsigned long messIntervall = 10000;
unsigned long letzteMessung = 0;
boolean schonWasGemeldet = false;
boolean giessMichGesendet = false;
boolean dhtValid = false;
char aColor[10];  // Es braucht nur 7, aber besser etwas Luft
char aText[65];   // Auch hier einiges an Sicherheit eingebaut (bisher max. 39 Zeichen)

void setup() {
  ArduinoOTA.setHostname("");
  ArduinoOTA.setPassword("");
  ArduinoOTA.begin();
  Serial.begin(115200);

Wire.begin(); 
  hdc1080.begin(0x40);
  // Enable CCS811
  ccs811.set_i2cdelay(50); // Korrekturanweisung, um am ESP8266 die I2C clock zu korrigieren
  bool ok= ccs811.begin();
  // Display aktivieren
  ok= ccs811.start(CCS811_MODE_10SEC);
  
  WiFi.mode(WIFI_STA);
  WiFi.hostname("");
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  server.begin();
  Serial.println("Server started");
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
  // Dieser Dummy-Text dürfte normalerweise nie erscheinen ...
  strcpy(aColor, "FF00FF");
  strcpy(aText, "----------- Bitte warten ------------");
  // Einmal vor der loop() ausführen, um klare Startbedingungen zu schaffen
  messenUndAuswerten();
}

void loop() 
{
  ArduinoOTA.handle();
  uint16_t eco2, etvoc, errstat, raw;
  ccs811.read(&eco2,&etvoc,&errstat,&raw);
  // Ausgabe der Messergebnisse am seriellen Monitor
  if( errstat==CCS811_ERRSTAT_OK ) 
  if (millis() - letzteMessung >= messIntervall) {
    messenUndAuswerten();
  }
  updateWebPage(aColor, aText);
}

void messenUndAuswerten() {
  letzteMessung = millis();
  messung();
  auswertung();
}

void messung() {
#ifdef ESP32USED
  dhtValid = false;
#else
  // Sensor wird ausgelesen
  hdc1080.readHumidity();
  // Temperatur in Celsius (default)
  hdc1080.readTemperature()();
  // Temperatur in Fahrenheit (isFahrenheit = true)
  //temperature = dht.readTemperature(true);
  //dhtValid = !(isnan(humidity) || isnan(temperature));

#endif

  // Compute heat index in Fahrenheit (the default)
  // float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahrenheit = false)
  // Der Heat Index ist die "gefühlte Temperatur"; wird hier zwar ermittelt
  // aber ansonsten nirgends verwendet ?!?!?!?
  // *********************************************
  // float hic = dht.computeHeatIndex(temperature, humidity, false);
  // *********************************************

  Sensorwert = analogRead(SensorPin);  //Sensor in die Erde
#ifdef ESP32USED
  Sensorwert = map(Sensorwert, 0, 4095, 0, 1023);
#endif

  Serial.println(WiFi.localIP());
  
}


void auswertung() {
  switch (Sensorwert) {
    case 0 ... 19:  // Eher ein Kurzschluss ???
      fehler();
      break;
    case 20 ... schaltSchwelle - toleranz:  // Wertebereich für gut bewässert
      allesOk();
      break;
    case schaltSchwelle - toleranz + 1 ... schaltSchwelle + toleranz - 1:  // Hysterese
      // Wenn wir gleich nach einem Neustart hier landen, signalisieren wir
      // dass alles Ok ist. Später passiert hier nichts mehr
      if (!schonWasGemeldet) {
        allesOk();
      }
      break;
    case schaltSchwelle + toleranz... 1023:  // Wertebereich für definitiv zu trocken
      giessMich();
      break;
  }
}

void giessMich() {
  Serial.println("Bitte gießen!!!");
  strcpy(aColor, "FF0000");
  strcpy(aText, "Bitte gieß mich!");
  schonWasGemeldet = true;
  if (!giessMichGesendet) {
    giessMichGesendet = true;
    sendMessage("Gieß mich bitte!!!");
  }
}

void allesOk() {
  giessMichGesendet = false;
  schonWasGemeldet = true;
  Serial.println("Pflanze gut gewässert!");
  strcpy(aColor, "00FF00");
  strcpy(aText, "Pflanze gut gewässert!!");
}

void fehler() {
  Serial.println("Fehlerhafter Sensorwert");
  strcpy(aColor, "FF0000");
  strcpy(aText, "Fehlerhafter Sensorwert!!");
}

void updateWebPage(char* color, char* text) {
  //  WiFiClient client = server.accept();
  WiFiClient client = server.available();
  if (client) {
    if (client.connected()) {
      //    Serial.println("Client connected");
      client.println("HTTP/1.1 200 OK");
      client.println();
      client.println("<!DOCTYPE html><html>");
      client.println("<head><meta name =\"viewport\" content=\"width=device-width, initial-scale=1\">");
      client.println("<meta charset=utf-8 />");
      client.println("<head><meta http-equiv=\"refresh\" content=\"3\">");
      client.println("<link rel=\"icon\" href\"data:,\">");
      client.println("<title>PlantBox</title>");
      client.println("<body>");
      client.println("<span style='color: #199BDE;'>");
      client.println("<H2><u><center><span style='color: #ff5733;'>PlantBox</span></center></u></H2>");
      if (dhtValid) {
        client.println("<h4><center>Temperatur:");
        client.print(temperature - 5);  // Ausgeben der Temperatur
        client.println("°");            // Schreiben des ° Zeichen
        client.println("<h4><center>Luftfeuchte:");
        client.print(humidity);  // Ausgeben der Temperatur
        client.println("%");     // Schreiben des ° Zeichen
        client.println("<h4><center>eCo2:");
        client.println(eco2);                                // Ausgeben der Temperatur
        client.println("ppm");                // Schreiben des ° Zeichen
        client.println("<h4><center>eTVOC:");
        client.println(etvoc);                                // Ausgeben der Temperatur
        client.println("ppb");                // Schreiben des ° Zeichen           
      } else {
        client.println("<h4><center>Temperatur: ungültig");
        client.println("<h4><center>Luftfeuchte: ungültig");
        client.println("<h4><eco2: ungültig");
        client.println("<h4><center>etvoc: ungültig");
      }
      client.println("<h4><center>Bodenfeuchte:");
      client.println(percentageHumididy); 
        client.println("%");    
        client.println("/");                              
        client.println(sensorVal);
      //client.println(Sensorwert);
      client.println("</h4></center>");
      char buffer[100];  // Bei längeren Ausgaben muss die Puffergröße ggf. angepasst werden!!!!!
      sprintf(buffer, "<H3><span style='color: #%s;'>%s</span></H3>", color, text);
      client.println(buffer);
      client.println("<center>\n\n");
      client.print("</body>\n</html>");
    }
    client.stop();
  }
}

void sendMessage(String message) {
#ifndef ESP32USED
  String url = "http://api.callmebot.com/whatsapp.php?phone=" + phoneNumber + "&apikey=" + apiKey + "&text=" + urlEncode(message);
  WiFiClient client;
  HTTPClient http;
  http.begin(client, url);
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  // Send HTTP POST request
  int httpResponseCode = http.POST(url);
  if (httpResponseCode == 200) {
    Serial.print("Message sent successfully");
  } else {
    Serial.println("Error sending the message");
    Serial.print("HTTP response code: ");
    Serial.println(httpResponseCode);
  }
  // Free resources
  http.end();
#endif
}

So far ;_)) Klaus

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.