{"id":24655321,"url":"https://github.com/wilmsn/espnode","last_synced_at":"2025-10-07T16:31:04.079Z","repository":{"id":179048030,"uuid":"661781296","full_name":"wilmsn/ESPNode","owner":"wilmsn","description":"Firmware für ESP8266 mit MQTT Client, Webserver und RF24 Gateway","archived":false,"fork":false,"pushed_at":"2024-12-15T18:08:17.000Z","size":35050,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-12-15T19:20:28.658Z","etag":null,"topics":["esp32","esp8266","html","platformio","rf24","websockets"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wilmsn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-03T16:22:38.000Z","updated_at":"2024-12-15T18:08:21.000Z","dependencies_parsed_at":"2023-07-07T11:15:25.483Z","dependency_job_id":"150c0c43-50d2-402c-add4-d84cdea33b09","html_url":"https://github.com/wilmsn/ESPNode","commit_stats":null,"previous_names":["wilmsn/espnode"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilmsn%2FESPNode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilmsn%2FESPNode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilmsn%2FESPNode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilmsn%2FESPNode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wilmsn","download_url":"https://codeload.github.com/wilmsn/ESPNode/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235641293,"owners_count":19022649,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["esp32","esp8266","html","platformio","rf24","websockets"],"created_at":"2025-01-25T22:36:55.395Z","updated_at":"2025-10-07T16:31:04.073Z","avatar_url":"https://github.com/wilmsn.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ESPNode\n## Brief Description\nESPNode is a firmware for ESP8266 and ESP32. This firmware is not generic, it has to be configured and compiled for each individual node.\n\n### Features:\n\n- Implemented RF24 Gateway for my RF24Hub (https://github.com/wilmsn/RF24Hub)\n- Implemented MQTT Client\n- Web Interface (based on J-Query and Websockets) \n- Written in C++ for Arduino\n\n![ESPNode Komponenten](https://wilmsn.github.io/ESPNode/espnode.png)\n\nThe main documentation of this projekt is in german language.\n \n[See the web version here](http://wilmsn.github.io/ESPNode/index.html) \n\n## Hauptprogramm\n\nMehr Details gibt es in der [Onlineprogrammdoku](http://wilmsn.github.io/ESPNode/index.html).\n\nIm Hauptprogramm sind folgende Komponenten vorgesehen:\n\n* Einbau von bis zu 6 Modulen.\n\nSofern die Module/Objektdefinitionen bereits vorhanden sind, kann das Programm einfach durch Konfiguration angepasst werden. Ohne Konfiguration sind alle Elemente deaktiviert. Details über die Konfiguration sind [hier](#konfiguration) zu finden\n\nInitialisierung des Hauptprogrammes:\nHier werden nacheinander folgende Dinge erledigt:\n\n* Einlesen von Konfigurationsdaten aus den Preferences\n\n* Öffnen des internen Filesystems\n\n* Verbindung mit dem WLAN\n\n* Starten des Webservers\n\n* Starten des RF24 Gateways (falls aktiviert)\n\n* Start des MQTT Clients (falls aktiviert)\n\n* Ausführen der BEGIN Statements aller Module\n\nDanach ist das Programm initialisiert und läuft in einer Endlosschleife. Innerhalb der Schleife finden (zum Teil zeitgesteuert) folgende Aktionen statt:\n\n* RF24 Gateway (falls aktiviert): Prüfen ob neue Datenpakete anliegen, wenn ja dann an den Hub oder Node weiterleiten\n\n* MQTT auf Pakete prüfen und verarbeiten\n\n* loop() Funktion aller Module bedienen\n\nZeitabhängige Aktionen:\n\n* Telemetriedaten senden (var: TELEINTERVAL)\n\n* Messungen starten (var: MESSINTERVAL)\n\n* Statusdaten und Messwerte senden (var: STATINTERVAL) \n\n## Module\nModule beschreiben bzw erzeugen eigene Objekte. Die Definition erfolgt in der Datei **\"Node_settings.h\"**. Die Aktivierung der Konfiguration für einen Node erfolgt in der Datei **\"config.h\"**\n\nFür die nachfolgenden Beispiele reichen die mitgelieferten Klassenbibliotheken.\n\n###Beispiel 1: Einfacher Node (ESP8266 oder ESP32) ohne externe Bauteile\nHie kann auf einem ESP8266/ESP32 lediglich die interne LED per Schalter über die Weboberfläche ein und ausgeschaltet werden.\n\n\t#ifdef NODESIMPLE\n\t#define USE_SWITCH_ONOFF\n\t#include \"switch_onoff.h\"\n\t\n\t#define HOSTNAME               \"nodesimple\"\n\t#define HOST_DISCRIPTION       \"Ein ESP32 Node ohne externe Elemente\"\n\t#define DEBUG_SERIAL_WEB\n\t#define DEBUG_SERIAL_MODULE\n\t#define DEBUG_SERIAL_MQTT\n\t#define MODULE1_DEFINITION      Switch_OnOff module1;\n\t#ifdef ESP32\n\t#ifndef LED_BUILTIN\n\t#define LED_BUILTIN   2\n\t#endif\n\t#define MODULE1_BEGIN_STATEMENT module1.begin(\"sw1\", \"interne LED\", \"int_led\", \"int_led\", false, true, LED_BUILTIN);\n\t#else\n\t#define MODULE1_BEGIN_STATEMENT module1.begin(\"sw1\", \"interne LED\", \"int_led\", \"int_led\", false, false, false, 2);\n\t#endif\n\t#define DO_LOG_SYSTEM           true\n\t#define MAGICNO                 0\n\t\n\t#endif\n\t\n###Beispiel 2: Demo für die Witty Cloud\nDie Witty Cloud ist ein ESP8266 Modul mit einer RGB LED und einem LDR. In der Weboberfläche gibt es 4 Schalter für die RGB Leds und die interne LED. Zusätzlich kann die Helligkeit der jeweiligen RGB Led mittels SChieberegler geändert werden.\n\n\t#ifdef WITTYNODE\n\t\n\t#define DEBUG_SERIAL_MODULE\n\t#define DEBUG_SERIAL_WEB\n\t\n\t#define USE_SWITCH_ONOFF\n\t#include \"switch_onoff.h\"\n\t#define USE_SENSOR_LDR\n\t#include \"sensor_ldr.h\"\n\t\n\t#define WITTY_RGB_RT           15\n\t#define WITTY_RGB_GN           12\n\t#define WITTY_RGB_BL           13\n\t#define WITTY_LED_PIN          2\n\t\n\t#define MAGICNO                123\n\t\n\t#define HOSTNAME               \"wittynode\"\n\t#define HOST_DISCRIPTION       \"A Witty Node\"\n\t\n\t#define MQTT_CLIENT            \"WittyNode\"\n\t#define MQTT_TOPICP2           \"wittynode\"\n\t\n\t#define DEBUG_SERIAL_WEB\n\t#define DEBUG_SERIAL_MODULE\n\t#define DEBUG_SERIAL_MQTT\n\t#define DEBUG_SERIAL_SYSTEM\n\t\n\t#define DO_LOG_MQTT              true\n\t#define DO_LOG_MODULE            true\n\t#define DO_LOG_WEB               true\n\t#define DO_LOG_SYSTEM            true\n\t\n\t#define MODULE1_DEFINITION      Switch_OnOff module1;\n\t#define MODULE1_BEGIN_STATEMENT module1.begin(\"sw1\", \"interne LED\", \"int_led\", \"int_led\", false, false, false, WITTY_LED_PIN);\n\t\n\t#define MODULE2_DEFINITION      Switch_OnOff module2;\n\t#define MODULE2_BEGIN_STATEMENT module2.begin(\"sw2\", \"RGB rot\", \"rot\", \"rot\", false, true, false, WITTY_RGB_RT, 100, 100, 1, \"Rot-Helligkeit\", \"rot_sl\", \"rot_sl\");\n\t\n\t#define MODULE3_DEFINITION      Switch_OnOff module3;\n\t#define MODULE3_BEGIN_STATEMENT module3.begin(\"sw3\", \"RGB gruen\", \"gruen\", \"gruen\", false, true, false, WITTY_RGB_GN, 100, 100, 2, \"Grün Helligkeit\", \"gruen_sl\", \"gruen_sl\");\n\t\n\t#define MODULE4_DEFINITION      Switch_OnOff module4;\n\t#define MODULE4_BEGIN_STATEMENT module4.begin(\"sw4\", \"RGB blau\", \"blau\", \"blau\", false, true, false, WITTY_RGB_BL, 100, 100, 3, \"Blau Helligkeit\", \"blau_sl\", \"blau_sl\");\n\t\n\t#define MODULE5_DEFINITION      Sensor_LDR module5;\n\t#define MODULE5_BEGIN_STATEMENT module5.begin(\"out1\", \"LDR\", 30);\n\t\n\t#endif\n\t\n###Funktion der jeweiligen Zeilen:\n\n\t#ifdef NODESIMPLE\n\t#endif\nSyntax:\n\t#ifdef \u003cName des Nodes\u003e\n\t#endif\nZwischen diesen beiden Zeilen befindet sich die Definition für den Node \"NODESIMPEL\". (Zeilen sind verpflichtend)\n\nDiese Konfiguration wird in der Datei **config.h** mit der folgenden Zeile aktiviert.\n\n\t#define NODESIMPEL\n\nSyntax:\n\n\t#define \u003cName des Nodes\u003e\n\n**Achtung:** Es darf immer nur eine Konfiguration aktiviert sein !!!\t\n\n\t#include \"switch_onoff.h\"\n\nSyntax:\n\n\t#include \"\u003cName der Headerdatei\u003e\"\n\nHier wird/werden die Headerdatei(en) für das/die verwendete Modul(e) includiert.\n(min. 1 Zeile ist verpflichtend)\n\n\t#define HOSTNAME               \"nodesimple\"\n\nSyntax:\n\n\t#define HOSTNAME               \u003cNetzwerkname des Nodes\u003e\n\nLegt den Hostnamen fest. Dieser wird für die Anmeldung im Netz genutzt und in der Weboberfläche angezeigt.\n(Zeile ist verpflichtend)\n\n\t#define HOST_DISCRIPTION       \"Ein ESP8266 Node ohne externe \n\nSyntax:\n\n\t#define HOST_DISCRIPTION       \u003cBeschreibender Text\u003e \n\nEin beschreibender Text für die Weboberfläche.\n(Zeile ist optional)\n\n\t#define MODULE1_DEFINITION      Switch_OnOff module1;\n\t#define MODULE2_DEFINITION      Sensor_LDR module2;\n\nSyntax:\n\n\t#define MODULE[1..6]_DEFINITION      \u003cName der Objektklasse\u003e module[1...6];\n\nDurch diese Zeile wird aus dem Klassenmodell eine Instanz. Wichtig dabei ist: \nDie Nummern müssen aufsteigend, mit 1 beginnend vergeben werden.\n\n\t#define MODULE1_BEGIN_STATEMENT module1.begin(\"sw1\", \"interne LED\", \"int_led\", \"int_led\", false, true, LED_BUILTIN);\n\t\nSyntax:\n\t#define MODULE[1...6]_BEGIN_STATEMENT module[1...6].begin(\u003cParameter1\u003e,...,\u003cParameterN\u003e);\nHier wird die Initialisierung des Objektes durchgeführt. Die Art und Anzahl der übergebenen Parameter hängt von deren Definition in der Klassenbibliothek ab.\n(min. 1 Zeile ist verpflichtend)\n\n###Weitere Konfigurationszeilen:\nEinschalten und konfigurieren des eingebauten MQTT Clients:\n\n\t#define MQTT_CLIENT            \"wittynode\"\n\t#define MQTT_TOPICP2           \"wittynode\"\n\t\nSyntax:\n\n\t#define MQTT_CLIENT            \u003cName des Clients\u003e\n\t#define MQTT_TOPICP2          \u003cTopic Part 2\u003e\n\nMit den beiden Zeilen wird der MQTT Client eingeschaltet und konfiguriert. (Wenn MQTT verwendet werden soll sind beide Zeilen verpflichtend)\n\n`\u003cName des Clients\u003e` ist der Name mit dem sich dieser Client bein MQTT Server anmeldet.\n\nDas Topic des MQTT Server (Vergleichbar mit einem Pfad im Dateisystem) ist im allgemeinen so aufgebaut:\n\n`\u003cTopic Part 1\u003e / \u003cTopic Part 2\u003e / \u003cTopic Part 3\u003e` Topic Part 1 und Topic Part 3 sind fest in der Konfiguration hinterlegt und werden idR. nicht geändert.\n\nTopic 1 und Topic 3 sind fallbezogen fest hinterlegt und können nur im Bedarf global in der Datei config.h geändert werden.\n\nTopic Part 2 kann bei Bedarf wiederum aus mehreren Subtopics bestehen. Denkbar wäre also folgende Konstellation:\n\n\t   stat/haus/keller/bastelkeller/temperaturnode/info1\n\nIn diesem Fall wäre `\u003cTopic Part 2\u003e` \"haus/keller/bastelkeller/temperaturnode\"\n\n---\nEinschalten und konfigurieren des eingebauten RF24 Gateways. Nähere Infos [RF24Hub auf Github](https://github.com/wilmsn/RF24Hub)\n\n\t#define RF24GW_HUB_SERVER        \"rpi1.fritz.box\"\n\t#define RF24GW_NO                \t   103\n\nSyntax:\n\n\t#define RF24GW_HUB_SERVER        \u003cHostname des RF24 Servers\u003e\n\t#define RF24GW_NO                         \u003cNummer des Gateways\u003e\n\nMit diesen beiden Zeilen wird der RF24 Gateway konfiguriert und aktiviert. Zum RF24 Gateway gibt es noch mehrere Einstellungen\nin der Datei \"config.h\", die einmalig für das komplette System festgelegt werden.\n---\nEinstellungen zum Debugging (Sollten in der produktiven Umgebung ausgeschaltet sein)\n\nDebuggingausgaben zum Web auf der seriellen Schnittstelle\n\n\t#define DEBUG_SERIAL_WEB\n\nDebuggingausgaben zum Modul auf der seriellen Schnittstelle\n\n\t#define DEBUG_SERIAL_MODULE\n\nDebuggingausgaben zu MQTT auf der seriellen Schnittstelle\n\n\t#define DEBUG_SERIAL_MQTT\n\nDebuggingausgaben zum System auf der seriellen Schnittstelle\n\n\t#define DEBUG_SERIAL_SYSTEM\n\n###Erstellung eines neuen Modules / einer neuen Klasse###\n\nFür jedes neue Modul werden jeweils eine Headerdatei und eine CPP-Datei angelegt. Innerhalb dieser Dateien wird eine Klasse beschrieben die in den ESPNode eingebaut wird. Diese Klasse kann natürlich Objekte nutzen die wiederum auf anderen Klassen basieren. Es ist darauf zu achten das sich in der Headerdatei nur Deklarationen befnden. Definitionen und Initialisierungen kommen in die CPP Datei.\n\nDie Modulklasse wird direkt oder indirekt von der Klasse \"Base_Generic\" abgeleitet. Beispiel:\n\n\tclass Sensor_18B20 : public Base_Generic {\n\t\n\tpublic:\n\t\n\tprivate:\n \t\n\t};\n\nDas hat den Vorteil das alle benötigten Funktionen bereits vorhanden sind und dadurch sichergestellt wird das der Compiler fehlerfrei läuft. Einige der in der Klasse \"Base_Generic\" definierten Funktionen sind jedoch leer und müssen in der abgeleiteten Funktion mit sinnvollem Inhalt gefüllt werden.\n\n**Wichtiger Hinweis**\n\nNicht benötigte Module ( wichtig bei Hardwarebezug z.B addressiete Pins ) müssen entweder\n\na) durch eine passende Precompilerdirektive deaktiviert werden (Beispiel Modul \"actor_ledmatrix\"):\n\nDatei \"actor_ledmatrix.h\":\n\n\t#ifdef USE_ACTOR_LEDMATRIX\n\t\n\t... Programmext ...\n\t\n\t#endif\n\t\nDatei \"actor_ledmatrix.cpp\":\n\n\t#include \"config.h\"\n    #ifdef USE_ACTOR_LEDMATRIX\n\t\n\t... Programmext ...\n\t\n\t#endif\n\t\nDiese Direktive wird dann in der Datei \"Node_settings.h\" aktiviert:\n\noder\n\nb) entfernt werden =\u003e sehr unpraktisch!!\n\n**Problem:** Besitzt ein Modul einen Hardwarebezug stören sich die Programme gegenseitig auch wenn sie nicht aktiv sind. (Beispiel: 2 Module greifen mit unterschiedlichen Methoden auf GPIO 4 zu, jedoch ist für einen Node jeweils nur ein Modul mit einer Methode aktiviert) \n\n**Lösung:** Umgesetzt ist die Methode a)\n\nDie benötigte Direktive steht jeweils in der ersten Zeile der Moduldateien *.h bzw. in der zweite Zeile von *.cpp\n\n###Aufgaben\nJedes Modul ist für die Bereitstellung seiner Daten egal ob Aktualisierung der Webseite oder Versand mittels MQTT selbst verantwortlich.\n\n####Web\nHier sind drei Szenarien zu unterscheiden: Die Kommunikation mit der Webseite erfolgt mittels JSON Statements. Ein JSON Statenment besteht immer aus einem Wertepaar: \"Schlüssel\":\"Wert\". Mehrere Statements werden durch Komma getrennt.\n\n**1) Öffnen einer Webseite**\nWird eine Webseite geöffnet und das Modul darüber (mittels html_init()) informiert, dann werden in der Variablen \"html_json\" alle benötigten JSON Statements gespeichert.\n\n**2) Update einer Webseite**\nBei jeder Änderung, die auf der Webseite dargestellt wird, wird durch das Modul eigenständig eine JSON Nachricht mit den neuen Daten an die Webseite geschickt.\n\n**3) Systeminfo Daten**\nHardwaredaten zu diesem Modul können auf der Seite \"Systeminfo\" angezeigt werden. Dazu sind folgende Maßnahmen erforderliich:\n\nÜber den Schalter \"html_has_info\" wird dem Hauptprogramm mitgeteilt das diese Daten vorhanden sind.\n\nIn der Variablen \"html_info\" werden diese Daten als JSON bereitgestellt.\n\nBeispiel: Es soll ein Sensor mit seinem HW-GPIO angezeigt werden:\n\nZunächst wird eine neue Abschnittsüberschrift erzeugt. Der Schlüssel dafür lautet `tab_head_\u003cmyname\u003e` Wichtig Da jeder Schlüssel im JSON eindeutig sein muss ist bei `\u003cmyname\u003eèine eindeutige Bezeichnung zu wählen. Der Wert ist die angezeigte Abschnittsüberschrift. Danach folgen max 5 Zeilen in folgender Syntax:\n\nSchlüssel: tab_lineX_id (mit X =1 ..5) \n\nWert: `\u003cZellelinks\u003e#\u003cZelle rachts\u003e`\n\nBeispiel:\n \n\t  \"tab_head_ldr\":\"Sensor\",\"tab_line1_ldr\":\"LDR:#GPIO: A0\"\n\t\n\n####MQTT\nMittels MQTT werden folgende Arten von Daten bereitgestellt.\n\n**1) Telemetriedaten**\n\nsind von ihrer Natur her statisch und verändern sich nicht während der Laufzeit. Die können z.B. Anschlüsse von Serńsoren oder Schaltern sein. Die Daten werden inḿ JSON Format in die Variable \"mqtt_info\" geschrieben. Um dem Hauptprogramm zu signalisieren das es diese Daten gibt ist der Schalter \"mqtt_has_info\" au true zu setzen.\n\n**2) Zustandsdaten**\n\nsind z.B Messwerte, Schalterzustände, etc. Zustandsdaten werden als normale Messwerte übertragen. Zusätzlich kann ein Wert den Status des kompletten Nodes darstellen.\n\nNormale Messwerte werden als JSON in die Variable \"mqtt_stat\" geschrieben. Durch den Schalter `mqtt_has_stat = true`wird dem Hauptprogramm mitgeteilt das dieses Modul Daten zuliefert. Wichtig: \"mqtt_stat\" ist immer mit den letzten gültigen Daten gefüllt. Werden die Daten aktualisiert wird der Schalter \"mqtt_stat_changed\" auf true gesetzt. Danach werden sie zeitnah vom Hauptprogramm an den Broker geschickt.\n\nWird ein Wert als Nodestatus definiert ist folgendes zu beachten: Der Wert wird in die Variable \"state\" eingetragen. Zusätzlich muss \"is_state\" auf true gesetzt sein. Achtung: Ein Node kann nur einen State haben!\n\n###Funktionen und Variablen\nHier werden nur Funktionen und Variablen beschrieben die zwingend erforderlich sind. Diese Funktionen sind alle in der Klasse \"Base_Generic\" definiert, es handelt ich jedoch teilweise nur um Funktionen ohne Inhalt.\n\n####Funktion \"begin()\"####\nHier wird das Objekt initialisiert dabei ist naturgemäß die Anzahl der Parameter variabel. Jedliche grundlegende Konfiguration muss hier erfolgen. Im weiteren Programm gibt es dazu keine Möglichkeit mehr.\nDer Einbau in den ESPNode mittels Precompilerdirektive wurde bereits behandelt.\n\n####Funktion set( _cmnd, _val)####\nHier werden alle Anweisungen für dieses Modul umgesetzt. Diese Funktion muss bei Bedarf im abgeleiteten Modul gefüllt werden.\nInnerhalb des Hauptprogrammes werden alle Befehle (Format \"comand\"=\"value\") durch jede set funktion der eingebauten Module geschleust. Die Module prüfen innerhalb der **\"set\"** Funktion ob das \"comand\" für sie ein keyword ist und sie handeln müssen. Die benötigte Funktion für diese Prüfung ist im generischen Basisobjekt als Funktion **keyword_match** hinterlegt. Alle nötigen Handlungen für einen \"Keyword Match\" sind hier zu hinterlegen.\n\n####Funktion \"html_init()\"####\nStellt alle Konfigurationsdaten (als JSON Teilstring) bereit, die für dieses Modul beim Aufruf der Webseite benötigt werden. Die Daten werden in die Variable \"html_json\" geschrieben. Um dem Hauptprogramm mitzuteilen das Daten zur Verfügung stehen wird der Schalter \"html_json_filled\" auf \"true\" gesetzt.\n\n####Funktion loop(time_t now)####\nIn dieser Funktion steht dem Modul Rechenzeit zur Verfügung. Hier werden alle Aktionen durchgeführt die nicht durch ein \"comand\" veranlasst worden sind z.B. regelmäßige Messungen mit Sensoren.\nZU beachten ist folgendes: Rechenzeit ist ein knappes Gut. Es findet seitens des Hauptprogrammes keine Kontrolle/Zeitbegrenzung statt. Die Loop Funktionen aller Module wird nah dem \"Round Robin\" Prinzip angesteuert. Verwendung von \"delay()\" ist unbedingt zu vermeiden. Um eine Wartefunktion zu realisieren gbt es den übergebenen Zeitstempel.\n \n \n(Modul Switch On Off)[./modul_switch_onoff.md]\n \n(technische Doku)[./technischedoku.md]\n \n \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilmsn%2Fespnode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwilmsn%2Fespnode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilmsn%2Fespnode/lists"}