Türkontankte ob Tür offen oder geschlossen auf einer Internseite darstellen

Du willst garantiert nicht

Button, Keyboard, Slider, Pointer Brightness, Settings, Dialog Box Text

auf dem Display anzeigen sondern etwas anderes. Was ist dieses andere?

Also noch einmal explizit nachgefragt:

Soll auf einem 2,8Zoll Display der Schließzustand der drei Schlösser
geöffnet / geschlossen
angezeigt werden?

Das ist jetzt eine geschlossene Frage die man mit "ja" oder "nein" beantworten kann.

Wenn es denn "nein" als erste Kurzantwort ist.

Dann kann sollte sich eine sehr detaillierte Beschreibung was für Informationen sollen auf dem Display angezeigt werden anschließen.

Erst mal nur eine Beschreibung der angezeigten Informationen.
Erst mal ohne eine wie auch immer geartete Realisierungs-Idee wie man es umsetzen könnte.

Wie man das dann in die Realität umsetzt so, dass du dann möglichst wenig Programmierarbeit damit hast, hängt ganz wesentlich davon ab, was für Informationen das sind. Und deswegen sollte diese Beschreibung als erstes gegeben werden.

Hallo StefanL38, ja es Soll auf einem 2,8Zoll Display der Schließzustand der drei Schlösser
geöffnet / geschlossen
angezeigt werden? Gruß k_p_hund

OK. Dafür genügt es ein einzelnes Byte an den microcontroller der mit dem Display verbunden ist zu senden.

Ein Byte = 8 bit.
Man könnte also das
Bit 0, Bit 1, Bit 2 nehmen.
Das sähe dann so aus

alle drei Schlösser geschlossen jedes Bit hat den Wert 1
BitNr:  76543210
Bitwert:00000111


alle drei Schlösser geöffnet jedes Bit hat den Wert 0
BitNr:  76543210
Bitwert:00000000


Nur ein Schloss geschlossen
BitNr:  76543210
Bitwert:00000001


Zwei Schlösser geschlossen
BitNr:  76543210
Bitwert:00000101

oder
auch
Bit 4, Bit 5, Bit 6

Mit Bit4, Bit5, Bit6
BitNr:  76543210
Bitwert:01110000

Wenn man mit einzelnen Bits arbeitet dann hat man Bit-Operationen.
Wenn man Buchstaben übertragen will dann hätte man 3 Buchstaben
als Auswahl aus A,B,C,D,E,F

Das wäre ziemlich kryptisch weil man eine Übersetzung
"A" bedeutet Garagentor geschlossen
"B" bedeutet Garagentor geöffnet
usw.
programmieren müsste

oder in der Form
G wie Garage
W wie Werkstatt
K wie Keller

G0W1K1 bedeutet dann
G0: Garagentor geöffnet,
W1: Werksttatt geschlossen,
K1: Keller geschlossen

Dann müsste man die einzelnen Buchstaben der Zeichenkette
"G0W1K1" auseinander nehmen.

Beides braucht 20 bis 30 Zeilen Code.

Wie gut kannst du englisch?
Bei Random Nerd Tutorials gibt es inzwischen mehrere Tutorials wird so ein Display
mit einer bestimmten library ansteuert.

Ich habe auch zwei so cheap yellow displays.
Die Anzahl frei verfügbarer IO-pins beträgt 3. Das ist echt mau.
Alle anderen IO-pins werden für Display, Touchfunktion und SD-Karte verbraucht
aber für deinen Zweck würde es gehen.
Daten per WLAN übertragen und auf dem Display anzeigen.

Trotzdem mal die Frage: muss es unbedingt so ein TFT-Display sein?
würden es auch drei Rot-Grün LEDs tun?

würde es auch so ein 4x20 LCD tun?

Wenn man nicht gleich auf einen Raspberry Pi oder ein altes Smartphone hochsteigt das direkt die Webseite anzeigen kann,
dann muss man so oder so einen extra Datenaustausch programmieren.

Und die Anzeigenprogrammierung von 3 grün/rot-LEDs oder eines
20x4-LCD ist einfacher als ein TFT-Grafik-Display

Hallo StefanL38; ja du hast recht, es reicht auch eine LCD 2004 I2C Modul | 20x4 Zeichen Beleuchtung Blau & I2C Modul für Arduino als Display aus. Frage könntest du mir für zweiten ESP 8266 WEMOS Di Mine den Code dafür programmieren. Danke Grußk_p-Hund

Da gibt es ein klares "Jain" :wink:

Wo befindet sich der ESP8266 der die Schlösserkontakte abfragt / einliest
und wo befindet sich der zweite ESP8266 der das LCD ansteuern soll?
Kann man die ohne Klimmzüge zu veranstalten per Kabel miteinander verbinden?
Dann könnte man eine serielle Schnittstelle programmieren.

Wenn drahtlos
Was ich vergleichsweise einfach zeigen kann wie man des programmiert sind UDP-Nachrichten senden / empfangen.

Mit zeigen wie man es programmiert meine ich folgende Vorgehensweise:
Ich poste einen Code der das Prinzip zeigt und du machst den Anfang wie man das zusammenfügt. Es ist sehr wahrscheinlich dass dabei Fragen auftauchen und/oder der Compiler meckert. Dann den aktuellen vollständigen Sketch posten und dann helfe ich weiter.

Dann doch eher ESP-now. Geht schneller und spart dadurch Strom.

(Abgesehen davon das es noch viel stromsparendere Sachen gibt, z.B., die zustände wie Tür geschlossen/offen erkennen, und mit einer CR2032 über Jahre auskommen)

Ich habe einige Projekte ausschließlich mit ESP-NOW einige ausschließlich mit WiFi.
Weil - zumindest früher - ging beides nicht zusammen. Ich meine mich zu erinnern, dass wenn man WiFi und ESP-NOW gleichzeitig benutzen will dann geht es nur dann wenn ESP-NOW auf den aktiven WiFi-Kanal gesetzt wird.

Kannst du einen Beispiel-Sketch posten der WiFi und ESP-NOW gleichzeitig macht?

Der ESP der es gleichzeitig nutzt ist eher nicht das Problem. Denn durch das verbinden mit dem WiFi stellt sich der Kanal automatisch.

Das Problem liegt eher bei den stromsparenden ESPs mit den Sensoren. Da hilft aber eine kleine Routine, falls keine ESP-now Verbindung aufgebaut werden kann, wird sich kurz ins WLAN verbunden, dadurch stellt sich der Kanal ein, wird ein WiFi San ausgeführt und der Channel, der im Sketch hinterlegten SSID, im nichtdeepsleepflüchtigem RTC Speicher hinterlegt.
Und es passiert eher selten, das sich der WiFi Kanal wechselt, zumindest in meinem Heimnetz. Man könnte auch einen festen Kanal einstellen, aber es ist kein muss.

Edit: Gefunden. Vom 09.10.22. Doch schon so lange her :sweat_smile:

//Bibliotheken
#include <Wire.h>                                                         // für I2C (BME280, OLED, etc.)
#include <Adafruit_Sensor.h>                                              // für BME280
#include <Adafruit_BME280.h>                                              // für BME280
#include <ESP8266WiFi.h>                                                  // ESP8266 WLAN Bibliothek
#include <Adafruit_GFX.h>                                                 // OLED GFX Bibliothek
#include <Adafruit_SSD1306.h>                                             // OLED SSD1306 Bibliothek
#include <espnow.h>

//OLED SSD1306
#define OLED_RESET         -1                                             // Reset Pin # (oder -1 zum nutzen des internen Reset Pins)
#define SCREEN_WIDTH      128                                             // OLED Display Weite, in Pixels
#define SCREEN_HEIGHT      64                                             // OLED Display Höhe, in Pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // OLED initialisieren

const char*    ssid = "YOUR_SSID";                                        // WLAN Name (SSID)
const char*    zimmer = "Kinder";                                         // Fürs Display
const uint16_t hoehe = 114;                                               // Höhe zur Bestimmung des Luftdrucks auf Meereshöhe

uint8_t gatewayAddress[] = {0xEC, 0xFA, 0xBC, 0x58, 0xA4, 0x76};          // Empfänger-Adresse

String        rinfo;
const unsigned long sleepTime = 3e8;                                      // Schlafzeit in µS // Bsp: 3e8 = "3 und 8mal 0" = 300.000.000µs = 300.000ms = 300s = 5Min


// ID 10=Kinder; 11=Schlafen; 12=Bad; 13=Wohnen;
struct PaketStruktur{
  uint32_t Loop;                      // LoopZeit in Microsekunden
  uint16_t ID = 10;                   // (0..65535) - Eindeutige ID des Senders
  int16_t  Temp = -999;               // Temperatur * 10
  uint16_t Humi = 0;                  // Luftfeuchtigkeit % * 10
  uint16_t Druck = 0;                 // Druck hPa
  uint16_t Vcc = 0;                   // Batteriespannung in mV
  int16_t  NTC = 0;                   // NTC Temperatur
  uint16_t Read = 0;                  // Magnetkontakt Wert / LinkerRead, RechterRead / 0 = 0b00 beide Reads geschlossen / 1 = 0b01 rechter Read offen / 2 = 0b10 linker Read offen / 3 = 0b11 beider Reads offen
  uint16_t NoCC = 0;                  // Übertragungsversuche seit letzten ACK
};
PaketStruktur payload;

struct {                                                                  // Struktur zum Speichern des RTC User Memorys (4 Byte Blöcke)
  uint32_t WiFiChannel = 0;
} rtcData;

Adafruit_BME280 bme;                                                      // Objekt für BME280 erstellen

void setup() {
  payload.Loop=micros();
  Serial.begin(115200);
  ESP.rtcUserMemoryRead(0, (uint32_t*) &rtcData, sizeof(rtcData));        // RTC User Memory auslesen
  Serial.print("Ausgelesener RTC Channel: "); Serial.println(rtcData.WiFiChannel);
  rinfo = ESP.getResetReason();                                           // Resetgrund einlesen
  Serial.print("Resetgrund: "); Serial.println(rinfo);
  bme.begin(0x76);                                                        // I2C Adress
  bme.setSampling(  Adafruit_BME280::MODE_FORCED,
                    Adafruit_BME280::SAMPLING_X1, // temperature
                    Adafruit_BME280::SAMPLING_X1, // pressure
                    Adafruit_BME280::SAMPLING_X1, // humidity
                    Adafruit_BME280::FILTER_OFF   );
  WiFi.mode(WIFI_STA);
  if(rtcData.WiFiChannel == 0 || rtcData.WiFiChannel > 13){               // Wenn der aus dem RTC User Memory eingelesen Wert ist
    rtcData.WiFiChannel = getWiFiChannel(ssid);                           // liefert den eingestellten Channel der oben hinterlegten SSID // kostet ungefähr 2,5 Sekunden !!
    ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData));     // Neu eingelesenen WiFi Channel in den RTC User Memory schreiben
  }
//  WiFi.printDiag(Serial); // Uncomment to verify channel number before    // Serielle Ausgabe der WiFi Einstellungen
//  wifi_promiscuous_enable(1);                                             // aus dem Beispiel, wird aber offenbar nciht benötigt.
  wifi_set_channel(rtcData.WiFiChannel);                                  // Setzt den Channel. Channel muss der des Empfängers sein. Der Empfänger richtet automatisch seinen Channel nach dem WLAN
//  wifi_promiscuous_enable(0);                                             // aus dem Beispiel, wird aber offenbar nciht benötigt.
//  WiFi.printDiag(Serial); // Uncomment to verify channel change after     // Serielle Ausgabe der WiFi Einstellungen
  WiFi.disconnect();                                                      // Wifi wird nicht benötigt
  if (esp_now_init() != 0) {                                              // EPS-now starten, und wenn es fehl schlägt schlafen gehen
    Serial.println("Error initializing ESP-NOW");
    ESP.deepSleep(sleepTime);                                             // Schlafzeit in Nanosekunden, für DeepSleep muss D0 mit Reset verbunden sein, zum aufwecken
    delay(100);                                                           // soll benötigt werden um korekt schlafen zu gehen
  }
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);                         // Sender
  esp_now_register_send_cb(OnDataSent);                                   // Funktion für Sendebericht
  esp_now_add_peer(gatewayAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);       // Funktion zum verbinden
  measureValues();                                                        // Werte einlesen
  payload.Loop = micros()-payload.Loop;                                   // Laufzeit berechnen
  esp_now_send(0, (uint8_t *) &payload, sizeof(payload));                 // Werte senden // braucht ein paar Millisekunden für einen erfolgreichen Sendebericht
  delay(500);                                                             // Delay für den zweiten Tastendruck für das Display
  if (rinfo == "External System"){                                        // Wenn Resetgrund = Resettaster, Display starten
    oled();
  }
  ESP.deepSleep(sleepTime);                                               // Schlafzeit in Nanosekunden, für DeepSleep muss D0 mit Reset verbunden sein, zum aufwecken
  delay(100);                                                             // soll benötigt werden um korekt schlafen zu gehen
}

void loop() {}                                                            // wird bei DeepSleep nicht benötigt

int32_t getWiFiChannel(const char *ssid) {                                // Scannen der WLAN-Netze, vergleichen mit der oben eingestellten SSID, und bei Übereinstimmung die ermittlung des Channels des Netzes
  if (int32_t n = WiFi.scanNetworks()) {
    for (uint8_t i=0; i<n; i++) {
      if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
        return WiFi.channel(i);
      }
    }
  }
  return 0;
}

void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
  Serial.print("\r\nSende-Status: ");
  if (sendStatus == 0){
    Serial.println("Zugestellt");
  }
  else{
    Serial.println("Zustellung Fehlgeschlagen, Scanne Channel");
    rtcData.WiFiChannel = 0;                                              // WiFiChannel auf 0 setzen
    ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData));     // Und in den RTC User Memory schreiben. Beim nächsten Start wird dadurch der Channel neu ermittelt
  }
}

void oled() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);                              // I2C address = 0x3C (links) oder 0x3D (rechts) (Aufdruck Rückseite verkehrt) // Kann durch umlöten des Widerstandes verändert werden.
  delay(100);                                                             // Pause zum Disply initialisieren
  display.clearDisplay();                                                 // Display löschen
  display.setTextSize(2);                                                 // Textgröße
  display.setTextColor(WHITE);                                            // Farbe (WHITE/BLACK)
  display.setCursor(0, 0);
  display.println(zimmer);
  display.print(payload.Temp/10.0);
  display.println("C");
  display.print(payload.Humi/10.0);
  display.println("%");
  display.print(payload.Vcc/1000.0);
  display.println("V");
  display.display();
  delay(10000);
  display.clearDisplay();
  display.display();
  display.ssd1306_command(SSD1306_DISPLAYOFF);    
}

void measureValues() {
  bme.takeForcedMeasurement();
  delay(10);
  payload.Vcc = map(analogRead(A0),0,1023,0,4300);
  payload.Temp = (bme.readTemperature()*10);
  payload.Humi = (bme.readHumidity()*10);   
  payload.Druck = ((bme.readPressure()/(pow(1.0 - (hoehe / 44330.0), 5.255)))/100.0);  //Luftdruckberechnung auf Merreshöhe
}

wenn ich deinen Sketch richtig lese, machst du in dem Fall aber keinen WLAN Verbindungsaufbau sondern nur einen Wifi Scan und ermittelst den Channel des "Heim"-Wifis ... richtig?

Naja, was heißt WiFi Scan.

Edit: Ja, hatte ich falsch verstanden. Früh am Morgen für mich.

ich sehe nur das scanNetworks, nie ein connect.

int32_t getWiFiChannel(const char *ssid) {                                // Scannen der WLAN-Netze, vergleichen mit der oben eingestellten SSID, und bei Übereinstimmung die ermittlung des Channels des Netzes
  if (int32_t n = WiFi.scanNetworks()) {
    for (uint8_t i=0; i<n; i++) {
      if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
        return WiFi.channel(i);
      }
    }
  }

aber ist schon ok, kenn mich soweit aus.

Ja, hab dein Post erst anders verstanden. Ja, Scan. Wenn eine SSID gefunden wird die hinterlegt ist, dann wird dessen Channel genommen.

Um es noch einmal deutlich auf den Punkt zu bringen:

Es geht darum das zwei Dinge die ganze Zeit "gleichzeitig" sekundenaktuell gemacht werden.

Eine Webseite die im ESP8266 mit der library ESPUI erstellt wird im Sekundentakt aktualisieren. Sobald sich der Schließzustand der Schlösser ändert soll eine Sekunde später die Webseite den neuen Schließzustand anzeigen.

Im Sekundentakt an einen zweiten ESP8266 Daten übermitteln um auf einem LCD den Schließzustand sekundenaktuell anzuzeigen.

Das bedeutet es müssten wirklich WiFi-Verbindung und ESP-NOW "gleichzeitig" im Sinne von beides WiFi und ESP-NOW sind in jeder einzelnen Sekunde Betriebszeit aktiv sein.

Wenn du dazu einen Demo-Sketch hast der nichts weiter benötigt als den ESP8266 selbst dann poste den.
Wenn du keinen solchen Demo-Sketch hast kein Problem. Ich selbst will ja sowieso für beides WiFi verwenden.

Demo Sketch nein. Eine Funktionierende nRF24l01 ESPnow MQTT WiFi Bridge habe ich. Es sind gleichzeitig nRF24 ESPnow und WiFi aktiv. Ein Webserver braucht es bei mir nicht. Die Daten werden per MQTT zur Zentrale weitergeleitet.

Sieht dann z.B. so aus.

Würde ich auch so machen.

Nur die Frage ist was jetzt wirklich entstehen soll.

@k-p_hund

Offenbar gibt es

einen ESP, ich nenn ihn mal espAuswertung

  • mit 3 Eingängen
  • einem webserver zur Darstellung der 3 Eingänge

und nun soll ein weiterer ESP mit einem Bildschirm dazu kommen, ich nenn den mal espBildschirm
und der könnte sich nun

  • von espAuswertung die Daten abholen
  • am Bildschirm (Display) anzeigen

Wenn du nun also am espAuswertung die Erweiterung der automatischen Aktualsierung mittels JSON/FetchAPI machen würdest - hättest du am espAuswertung alles erledigt für ein erste Kommunikation zwischen den beiden ESPs.

Genau das gleiche JSON das für die Aktualisierung der webpage verwendet wird könnte sich der espBildschirm auch vom espAuswertung abholen und die Daten am Bildschirm aktualisieren.

Wenn es ein funktionierendes Wifi gibt, würde ich nicht noch mit ESP NOW anfangen.

Wenn man will, kann man den espAuswertung eine Statusänderung ja auch zusätzlich mittels UDP Broadcast senden lassen. Aber ich empfehle dir das schrittweise zu machen.

JSON/FetchAPI keine Ahnung wie das geht.
Kommt mir deutlich komplizierter vor als ein UDP-Packet zu senden.

UDP ist mit diesen code-zeilen hier (fast) erledigt

#include <WiFiUdp.h>
WiFiUDP Udp;

int packetSize;

// senden
    Udp.beginPacket(remoteIP(), remotePort());
    Udp.write(Buffer);
    Udp.endPacket();


//empfangen
  packetSize = Udp.parsePacket(); // Udp.parsePacket() delivers the number of bytes of the UDP-packet

  if (packetSize) { // a value > 0 is seen as a true
    int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    packetBuffer[n] = 0; // terminate char-array with zero

geht das mit JSON/FetchAPI auch mit so wenig Zeilen?
Wie viel Wissen muss man über die Details zur JSON/FetchAPI haben um es anzupassen`?

oder
kannste mal einen Demo-Sketch der das per JSON/FetchAPI macht posten?

nein natürlich nicht.

a)

Daher schrieb ich ja, wenn man schon einen sich aktualisierende Webpage hat - (was ja oben angesprochen wurde),

dann hat man sich mit dem JSON/FetchAPI beschäftigt.
Das erkläre ich z.B. hier:
https://werner.rothschopf.net/microcontroller/202310_esp_webserver_maxi_en.htm#70

Dann beschäftigt man sich mit dem HTTP Client am espBildschirm wie man das JSON parst. Ich würde dazu die ArduinoJson verwenden. Und nur das wäre der Aufwand den man kalkulieren muss, wenn man nun noch zusätzlich die Daten auf einem anderen esp verwenden will.

b)
wenn du tiefer drüber nachdenkst, reicht ein einfaches UDP senden ja auch nicht.
du brauchst auch einen Empfänger-Sketch und du benötigst Logic die entweder dauerhaft alle Daten ins Netz schickt oder du musst was bidirektionales aufbauen damit du einen Anfangszustand auch hast.

Nein. Gar nicht. Es wird ESPUI benutzt und das wars

ESPUI-Quellcode
#include <ESPUI.h>
#include <SafeString.h>

cSF(myTuerStatus_SS, 512);
cSF(multiPurp_SS, 512);

const byte DNS_PORT = 53;
IPAddress apIP(192, 168, 4, 1);

#if defined(ESP32)
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif

const byte    OnBoard_LED = 2;

const char *home_ssid     = "";
const char *home_password = "";

unsigned long MyTestTimer;

const byte pinStatusGargentor   = 16;
const byte pinStatuswerkstattor = 14;
const byte pinStatuskellertor   = 12;

byte aufZuGaragenTor;
byte aufZuWerkstattTor;
byte aufZuKellerTor;

uint16_t statusLabel_ID;

void defineGUI() {
  statusLabel_ID = ESPUI.label("Türenstatus", ControlColor::Turquoise, "0");
}


void leseKontakteSetzeStatus() {

  // Schaltzustände der IO-pins einlesen
  aufZuGaragenTor   = digitalRead(pinStatusGargentor);
  aufZuWerkstattTor = digitalRead(pinStatuswerkstattor);
  aufZuKellerTor    = digitalRead(pinStatuskellertor);

  // anzuzeigenden Text zusammensetzen
  // erste Textzeile Garagentor:geöffnet   / Garagentor:geschlossen
  myTuerStatus_SS  = "Garagentor:";

  if (aufZuGaragenTor == HIGH) {
    myTuerStatus_SS += "geöffnet";
  }
  else {
    myTuerStatus_SS += "geschlossen";
  }
  myTuerStatus_SS += "\n";  //   "\n" macht Zeilen-Umbruch => nachfolgender Text landet in Zeile darunter


  // zweite Textzeile Werkstatt-Tor:geöffnet   / Werkstatt-Tor:geschlossen
  myTuerStatus_SS += "Werkstatt-Tor:";
  if (aufZuWerkstattTor == HIGH) {
    myTuerStatus_SS += "geöffnet";
  }
  else {
    myTuerStatus_SS += "geschlossen";
  }
  myTuerStatus_SS += "\n";  //   "\n" macht Zeilen-Umbruch => nachfolgender Text landet in Zeile darunter


  // dritte Textzeile Keller-Tor:   / Keller-Tor:
  myTuerStatus_SS += "Keller-Tor:";
  if (aufZuWerkstattTor == HIGH) {
    myTuerStatus_SS += "geöffnet";
  }
  else {
    myTuerStatus_SS += "geschlossen";
  }

  // Webseite mit dem Inhalt der SafeString-Variable  myTuerStatus_SS updaten
  ESPUI.updateControlValue(statusLabel_ID, myTuerStatus_SS.c_str() );
}



void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();
  
  pinMode(pinStatusGargentor,INPUT);
  pinMode(pinStatuswerkstattor,INPUT);
  pinMode(pinStatuskellertor,INPUT);

  ESPUI.setVerbosity(Verbosity::VerboseJSON);
  PrintFileNameDateTime();
  connectToWiFi();
  defineGUI();

  ESPUI.begin("I am the website created by the ESPUI-Demo");
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 500);

  if ( TimePeriodIsOver(MyTestTimer, 1000) ) {
    leseKontakteSetzeStatus();
  }
}


void connectToWiFi() {

  // try to connect to existing network
  WiFi.begin(home_ssid, home_password);
  Serial.print("\n\nTry to connect to existing network");
  Serial.print(" named #");
  Serial.print(home_ssid);
  Serial.println("#");

  uint8_t timeout = 10;

  // Wait for connection, 5s timeout
  do {
    BlinkHeartBeatLED(OnBoard_LED, 100);
    delay(500);
    Serial.print(".");
    timeout--;
  } while (timeout && WiFi.status() != WL_CONNECTED);

  // not connected -> create hotspot
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("\n\n no connection to SSID #");
    Serial.print(home_ssid);
  }

  Serial.print("IP address: ");
  Serial.println(WiFi.getMode() == WIFI_AP ? WiFi.softAPIP() : WiFi.localIP());
  Serial.println("type this IP-adress into your browser to connect to the GUI of your ESP");
}


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


/* Erklärung der Webseiten-Definition
  statusLabel_ID = ESPUI.label("Türenstatus", ControlColor::Turquoise, "0");
  // statusLabel_ID     : number that is used to identfy the GUI-element
  // .label             : the type of the GUI-element
  // "Number of Clicks" : the text that describes the GUI-element
  // ControlColor::Turquoise : explains ITSELF
  // "0" initial VALUE shown on the element (will be updated on runtime)
*/

ist halt eine andere Arbeitsweise. Ich mach Sachen zu Fuß, gern nach "primitiven" Standards, damit ich sie für ähnliche Fälle wiederverwenden kann.

Mir ging es nur darum, wenn die Sensoren mit Akkus versorgt werden, und auf Funk gesetzt wird, das so stromsparend wie möglich aufzubauen.

Wenn die Sensoren mit einem Netzteil betrieben werden, kann natürlich ein ESP 24/7 daran wach sein.