String wird in einer Funktion mit millis nicht für die gewünschte Zeit beibehalten

Hallo zusammen.

Ich bin noch nicht so lange mit der Arduino Programmierung vertraut und benätige daher etwas Hilfe bei einer Funktion.

Ich habe mir einen Frostwächter mit dem Wemos D1 mini und einem BMP280 gebastelt.
Dieser soll bei Unterschreitung von 2° C für die Dauer von 120 Sekunden anbleiben und die Heizung laufen lassen.
Funktioniert soweit auch alles.
Nur habe ich mir noch einen String mit eingebaut, welcher mir den Status AN / AUS auf dem Webserver mit anzeigt.
Leider zeigt der String "Heiz" den Status "AN" nicht über die ganzen 120 Sekunden an.
Ich habe hier schon einiges versucht, aber irgendwie will es nicht funktionieren.

Anbei der Code:


unsigned long previousMillis = 0; // speichert den Zeitpunkt an dem zuletzt geschalten wurde
const long interval = 120000; // Länge der Pause in ms

.....

void Heizung() {
  String Heiz; 
  float tempC = bme.readTemperature();
  unsigned long currentMillis = millis(); // Aktuelle Zeit wird in currentMillis gespeichert
  if (tempC > 27) {
    if (currentMillis - previousMillis >= interval)
              {previousMillis = currentMillis;
               digitalWrite(D7, LOW);
               }
               Heiz = "AUS";
            }
   else{
   digitalWrite(D7, HIGH);
   Heiz = "AN";
  }

Ich würde mich über eure Hilfe sehr freuen.

Gruß
Domenico

Die String Klasse hält sich an das RAII Pattern
Wird also am Ende der Funktion zerstört.

static String Heiz; oder eine globale Instanz würde das verhindern.
Kann aber auch andere Probleme schaffen!

-------------------

Disclaimer:

  • Dieses ist ein typisches "Combie Posting".
  • Es kann Spuren von Wahnsinn enthalten
  • Es kann Anstoßpunkte für Irritationen, Ungenauigkeiten und Irrtümer enthalten.
  • Es macht keinen Versuch vollständig sein zu wollen.
  • Es wird dringendst dazu aufgefordert, die evtl. gegebenen Informationen, vor der Verwendung, pingelig zu überprüfen.
  • Es enthält keinerlei Zwang, den Vorschlägen/Gedanken zu folgen.
  • Wem dieses Posting nicht schmeckt, darf es einfach im Regal liegen lassen.
  • Es gibt keine Gewähr für die Funktion der evtl. gegebenen Tipps und/oder den Erhalt der geistigen Gesundheit des Gegenüber.

Hallo @combi,

danke für deine Antwort.
Ich werde es ein mal versuchen.
Verstehen kann ich es jedoch nicht, da mir hierzu noch die Übung fehlt.

Gruß
Domenico

Leider funktioniert es nicht.
Sobald die Temperatur den Wert für die Schaltung überschreitet, springt der String auf "AUS".
Die heizung bleibt aber für den Intervall eingeschalten.

Gruß
Domenico

Ich gehe davon aus, dass dein µC genau das tut, was du programmiert hast.
Was soll es denn tun?

Nun ja, er soll beim Unterschreiten der 27° C (hier natürlich zu Testzwecken so hoch gewählt) den Relay einschalten und für die Zeit "OInterwall" (hier mit 120 Sekunden) eingeschaltet bleiben.
Durch den String Heiz = "AUS"; soll ebenfalls für die 120 Sekunden angezeigt werden, dass die heizung läuft.
Macht er aber nicht, da dieser die millis nicht beachtet.

Gruß
Domenico

So hast du es auch geschrieben!
Dann tut es das auch.

Meinst du sowas?

void Heizung()
{
  String Heiz;
  float tempC = bme.readTemperature();
  unsigned long currentMillis = millis(); // Aktuelle Zeit wird in currentMillis gespeichert
  if (tempC > 27)
  {
    if (currentMillis - previousMillis >= interval)
    {
      previousMillis = currentMillis;
      digitalWrite(D7, LOW);
      Heiz = "AUS";
    }
  }
  else
  {
    digitalWrite(D7, HIGH);
    Heiz = "AN";
  }
}

Na ja, aber wenn die Temperatur nach 3 Sekunden über 27° C steigt, wird der String AUS angezeigt.
Das kann eigentlich nicht sein, da D7 ja auczh für 120 Sekunden den Status behält.
Es darf innerhalb des Intervalls keine Änderung der Anzeige statt finden.

Gruß
Domenico

Ich verstehe dich nicht!
In meinem Vorschlag sind String und D7 absolut Synchron.
Es kann gar nicht sein, dass sie sich unterschiedlich verhalten!

Nein!
Ich habe keine Ahnung, was dein Problem ist.
Ich gebe auf......

Hallo
Wie @combie bereits bemerkt hatte, liegt Dein Fehler an der falsch platzierten Klammer
Heinz

Ich sehe da nichts mit 2°C und auch nichts mit heizen, wenn irgendein Wert unterschritten ist.

Schmeiss den ganzen Kram raus - für die Webdarstellung machst Du in Deinem Response:

client.print("Heizungsstatus: ");
  if (digitalRead(D7))client.println("AN"); else client.println("AUS");

Nicht mehr und nicht weniger.

Erledigt.

Hallo,

natürlich funktioniert der Sketch so bis auf die Anzeige des Status.
Ich nutze das Teil ja schon im Gewächshaus.
Wollte eben nur, dass die Anzeige im gleichen Takt wie der Relay des Status ausgibt.
Die 2° C sind natürlich nur im Gewächshaus in verwendung.
Hier im Büro habe ich auf 27° C gesetzt, da wir ja zu Haus im Warmen sitzen :blush:

Das werde ich gleich mal probieren.

Gruß
Domenico

Ich verstehe das ganze Problem nicht.

Was du in der Funktion Heizung mit dem Pin D7 machst, kann sich natürlich in der realen Welt auswirken. Was du in den lokalen String Heiz; reinschreibst, ist aber nur innerhalb eines Durchlaufs Funktion Heizung sichtbar und danach weg (auch für den nächsten Durchlauf dieser Funktion).

Das hat @combie gleich in der ersten Antwort #2 geschrieben. Auf seine Art, damit du auch die Chance hast "RAII Pattern" zu googeln.

Wenn du außerhalb von Heizung irgendwas mit einer Variable namens Heiz machst, sie also irgendwo anzeigst o.ä., und du keinen Compilierfehler bekommst, ist das eine andere Variable, die wir in deinem Schnipsel natürlich nicht sehen können.

@my_xy_projekt macht es sich (und dir) einfach, indem er diese lokale String-Variable ignoriert und einfach abfragt, wie der Pin D7 zuletzt gesetzt wurde.

Das Büro dürfte verlassen sein.
Mit welchem Ergebnis?

Guten Morgen,
Hatte gestern nicht mehr die Zeit gefunden, um an den PC zu kommen.

Ich habe das ein mal mit Serial.println versucht.
Bekomme aber immer nur AN als Ausgabe.

Hier hast du natürlich Recht.
Ich hätte direkt den completten Code eintragen sollen, da man ansonsten nicht die komplette Vorgehensweise erkennen kann.
Anbei nun der aktuelle Code, welcher mir die Ausgabe von Heiz (AN sobald die Temperatur unter den Schwellwert fällt und AUS sobald der Wert wieder überschritten ist) ausgibt.
Das AUS darf aber erst dann ausgegeben werden, wenn D7 tatsächlich abschaltet was nach 120 Sekunden ist.

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <Wire.h>
#include <Adafruit_BME280.h>
#include <ArduinoOTA.h>
Adafruit_BME280 bme;
Adafruit_Sensor *bme_temp = bme.getTemperatureSensor();


#ifndef STASSID
#define STASSID "xxxxxxx"
#define STAPSK  "xxxxxxx"
#endif

const char *ssid = STASSID;
const char *password = STAPSK;

unsigned long previousMillis = 0; // speichert den Zeitpunkt an dem zuletzt geschalten wurde
const long interval = 120000; // Länge der Pause in ms

ESP8266WebServer server(80);

const int led = 13;

void indexHTML() {    
  server.send(200, "text/html", 
  "<!DOCTYPE html>\
  <html>\
  <head>\
  <title>Temperaturanzeige</title>\
  <meta http-equiv='content-type' content='text/html'; charset='utf-8'>\
  <style>\
  body { background-color: #585858; font-size: 50px; font-family: Arial, Helvetica, Sans-Serif; color: #F2F2F2; margin-left: 40px; }\
  h1 { color: #2ECCFA; margin-top: 50px; margin-bottom: 0px; }\
  h2 { font-size: 20px; margin-top: 0pFx; margin-bottom: 50px; }\
  #temp { width: 230px; height: 80px; border: 5px solid #F2F2F2; text-align:center; padding: 1px; color: #9AFE2E; background-color: #000000; font-size: 60px; }\
  </style>\
  </head>\
  <body>\
  <h1>Temperaturanzeige</h1>\
  <h2>(by Der Bastelbruder)</h2>\
  <table><tr><td>Aktuelle Temperatur:&nbsp;</td>\
  <td id='temp'><span id='TempWert'>-</span>°C</td></tr>\
  <tr><td>Status der Heizung:&nbsp;</td>\
  <td id='temp'><span id='Heiz'>-</span></td></tr></table>\
    <script>\
  setInterval(function() {\
    getData();\
    getHeiz();\
  }, 1000);\
  function getData() {\
    var xhttp = new XMLHttpRequest();\
    xhttp.onreadystatechange = function() {\
      if (this.readyState == 4 && this.status == 200) {\
        document.getElementById('TempWert').innerHTML = this.responseText;\
      }\
    };\
    xhttp.open('GET', 'TempWeb', true);\
    xhttp.send();\
  }\
  function getHeiz() {\
    var xhttp = new XMLHttpRequest();\
    xhttp.onreadystatechange = function() {\
      if (this.readyState == 4 && this.status == 200) {\
        document.getElementById('Heiz').innerHTML = this.responseText;\
      }\
    };\
    xhttp.open('GET', 'HeizWeb', true);\
    xhttp.send();\
  }\
  </script>\
  </body>\
  </html>\
  ");
}

void TempMessung() {
  String TempWert = String(bme.readTemperature(),1);
  server.send(200, "text/plane", TempWert);
  }

void Heizung() {
  String Heiz; 
  float tempC = bme.readTemperature();
  unsigned long currentMillis = millis(); // Aktuelle Zeit wird in currentMillis gespeichert
  if (tempC > 27) {
    if (currentMillis - previousMillis >= interval)
              {previousMillis = currentMillis;
               digitalWrite(D7, LOW);
               }
               Heiz = "AUS";
            }
   else{
   digitalWrite(D7, HIGH);
   Heiz = "AN";
  }
  
  //Serial.println (Heiz);
  server.send(200, "text/plane", Heiz);
}



void setup() {
  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_FS
      type = "filesystem";
    }

    // NOTE: if updating FS this would be the place to unmount FS using FS.end()
    Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  pinMode(D7, OUTPUT);
  if (!bme.begin());
  pinMode(led, OUTPUT);
  digitalWrite(led, 0);
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");
 
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
      }
server.on("/", indexHTML);
  server.on("/TempWeb", TempMessung);
  server.on("/HeizWeb", Heizung);

  server.begin(); 
  Serial.println("Webserver ist gestartet");
 
  server.on("/inline", []() {
    server.send(200, "text/plain", "this works as well");
  });
  server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
   ArduinoOTA.handle();
   //Heizung();
   server.handleClient();
   MDNS.update();
}

Gruß
Domenico

Also, es hat jetzt mit dem Tipp von my_xy_projekt und etwas Anpassung funktioniert:

if (digitalRead(D7))Heiz=("AN"); else Heiz=("AUS");

Ich danke euch für die netten Hinweise und werde sicher in Zukunft mehr Zeit hier verbringen.
Schließlich lernt man das meiste ja doch durch Beiträhe hier im Forum.

Gruß
Domenico

Unfassbar!
In deiner letzten Version ist ja immer noch der Bock drin!

Zudem:
Kann es sein, dass deine Heizung nur funktioniert/regelt, wenn die Seite im Browser geöffnet ist?

Aber ok...
Will mich nicht weiter einmischen.

Ja, tu du das....
Es gibt noch viel zu lernen.

Na ja, der Block wurde jetzt mit dem folgenden aktualisiert:

void Heizung() {
  String Heiz; 
  float tempC = bme.readTemperature();
  unsigned long currentMillis = millis(); // Aktuelle Zeit wird in currentMillis gespeichert
  if (tempC > 27) {
    if (currentMillis - previousMillis >= interval)
              {previousMillis = currentMillis;
               digitalWrite(D7, LOW);
               }
               //Heiz = "AUS";
            }
   else{
   digitalWrite(D7, HIGH);
   //Heiz = "AN";
  }
  if (digitalRead(D7))Heiz=("AN"); else Heiz=("AUS");
  
  Serial.println (Heiz);
  server.send(200, "text/plane", Heiz);
}

So funktioniert alles perfekt.

Nein, die Heizung läuft wie gewünscht bei unterschreitung der 2°C springt der Relay an und bleibt es auch für mindestens 120 Sekunden.
Über Browser prüfe ich nur, ob auch alles läuft und wie die temperatur ist.
Natürlich will ich hier noch ein Sicherheits-Reset einbauen, denn diese Sensoren spinnen ab und zu.
Letztens hatte ich -144°C und die Heizung lief mal eben die ganze Nacht.
Also muss man immer ein Sicherheitscheck einbauen.

Gruß
Domenico

Hallo,
wenn Du in der HTML doch schon java-script nutzt warum nutzt Du dann nicht auch das Filesystem des ESP und legst die HTML darauf ab. Fetch wäre dann auch einen gescheite Lösung.

schau Dich mal bei Fips um , da findest Du jede Menge gute Beispiele

Heinz

Hallo, da kenne ich mich noch nicht so sehr aus.
Den Sketch hier hat der Bastelbruder über Youtube bereitgestellt.
Ich habe da nur noch die Funktion mit der Anzeige des Status mit integriert.
Daher auch dieser Sketch.
Werde mich aber ein mal bei Flips durchlesen.

Gruß
Domenico