ESP8266 - Rolladensteuerung mit WebIF mit Totmannschalter/Heartbeat - Funktion

  • CANDO : Wenn man einen Code kopiert weil man hofft, dass er die Lösung für das vorhandene Problem ist, sollte man auch mal schauen was für Bibliotheken dort verwendet werden und was die so können. Erst dann kann man doch beurteilen, ob damit eine Lösung möglich ist oder nicht.


    Hast Du Dir denn mal die Hilfe zu der verwendeten Webserver Bibliothek angeschaut?


    https://github.com/me-no-dev/E…bServer#espasyncwebserver


    Dort steht unter anderem, dass der Server ein AsyncEventSource Plugin hat, mit dem der Server Textnachrichten an einen Client schicken kann. Außerdem ist dort beschrieben, wie Server und Client funktionieren:

    https://github.com/me-no-dev/E…async-event-source-plugin.


    Das Ganze nennt sich HTML SSE (Server Sent Events) und wir sind, wie ich bereits vermutete, bei HTML5 und Javascript

    https://www.codingblatt.de/html5-server-sent-events/.


    Damit könnte sich etwas implementieren lassen, was Deinem Plan nahe kommt.


    Nun wird jedoch klar, warum der Kollege den Du angeschrieben hast, keine Zeit hat…. ;). Du darfst Dich jetzt nämlich mit mehreren Dingen beschäftigen (mindestens):

    • Die Funktionsweise der zu verwendenden Bibliotheken verstehen,
    • Die Erstellung der Webseite(n) (die Du beim ESP32 / 8266 auch im SPIFF Speicher ablegen kannst),
    • HTML 5 (SSE),
    • Javascript (auch Bestandteil der Webseiten),
    • die Implementierung des Codes.

    Wenn man das alles noch nicht gemacht bzw. noch nicht kennt, eine sehr anspruchsvolle, zeitintensive Aufgabe. Selbst dann, wenn man sich mit den Themen schon mehr oder weniger auskennt, so etwas aber nicht andauernd umsetzt und man tief im Thema drin ist.



    Was die Steuerung des Rolladens betrifft, gibt es aus meiner Sicht zwei kritische Punkte:

    Wenn der Rolladen ganz oben ist (oberer „Anschlag“).

    Wenn der Rolladen ganz unten ist (unterer „Anschlag“).


    Um diese Positionen festzustellen fallen mir auf die Schnelle folgende Möglichkeiten ein:

    • Die schon angesprochenen Reedkontakte (Neodyn Magnete sind sehr stark). Minimum wäre ein Magnet und zwei Kontakte (oben, unten)
    • Evtl. Hall-Sensoren statt Reedkontakte (sind empfindlicher für Magnetfelder)
    • Mikroschalter
    • Lichtschranke
    • Positionsermittlung über die Anzahl der Kurbeldrehungen

    Letzteres würde eine Kalibrierung benötigen und auch eine Mimik, die die Positionen dauerhaft speichert (Stromverlust, Aus-, Einschaltung). Allerdings wäre keine Installation am Rolladen notwendig.

  • Vielen Dank Knisterbein,


    wenn ich das richtig verstanden habe und mich grade richtig belesen habe, kann man die KeepAlive Funktion in der .htaccess Datei aktivieren, das währe dann wohl auf einem Apache Server möglich? Das Ding ist, mein "Server besteht aus u.g. Programmcode. Der HTML Code, dem ich dem ESP8266 zumuten darf, liegt wohl bei 14K Zeichenmenge. Ich habe keine Ahnung, wie hier dieses entprechende KeepAlive implementieren könnte. (Apache Server aufsetzen?)


    Die Hardware ist übrigens fertig: ESP8266 mit passendem 1A - USB-Netzteil, Scheibenwischermotor 12V mit passendem Netzteil, 4-fach Relaiskarte für Raspi, ESP, etc., 12V PWM Drehzahlregler mit Drehrichtungsumschalter (Amazon Asin: B072V8LHDY), verschiedene passende Sicherungen.


    Ich ergänze die Funktion wie folgt:

    Der Rolladen soll, solange ich den Richtungsbutton drücke, entsprechend abwärts oder aufwärts fahren. Es ist eine Miewohnung, der Umbau auf Rolladenmotor kommt nicht in Frage. Dieser Rolladen hat eine Kurbelstange verbunden mit einem Kreuzgelenk. Die Drehbewegung wird auf ein Schneckenradgetriebe übertragen, was den Rolladen dann dreht. Die Kurbel soll abmontiert werden und durch eine starre Gewindestange ersetzt werden, die mit einem Scheibenwischermotor angetrieben wird. Dieser Motor kann umgepolt werden zur Drehrichtungsänderung. Die benötigten Drehmomente bringt der Scheibenwischermotor locker. Neben dem "Rolladen-Kurbel-Anschluss" steht ein Hochschrank, perfekt geeignet, um einen kleinen Kasten oben drauf zu befestigen, von der aus die Gewindestange zum Rolladen geht.


    Kann man also hier (im u.g. Programm) das KeepAlive auch irgendwie aktivieren? Bietet diese Funktion eine von mir benutzte Library? Oder gibt es dafür eine spezielle Library?

  • Hallo CANDO


    Kai hat es richtig erklärt und ich kann ihm nur zustimmen. Das HTTP Protokoll ist eher schlecht für Dein Anliegen geeignet, da es sitzungsorientiert arbeitet.

    Ich würde empfehlen, bevor Du Dich mit der Übertragung der Befehle befasst, die Rollladen- Steuerung vorab zu realisieren. Zum Starten, Ausprobieren und der Funktionskontrolle sollten doch 2-3 Tasten reichen. Das Ausführen von Aktionen, das Verhindern von Kollisionen oder Fehlfunktionen des Rollladen ist Dein Hauptziel und wenn dieser Teil in allen Fällen richtig funktioniert, hast Du vermutlich den grössten Teil des Projektes erledigt. Den physischen Aufbau und die sich drumherum ergebenden Anforderungen sind uns nicht bekannt und da werden wir ausser bei Teilprobleme kaum sinnvolle Lösungsvorschläge aufzeigen können.

    Danach überlegt man ich, wie man die Steuerung via FB erledigen könnte (z.B: via IR oder mit einer HF FB, oder via IP/ TCP/HTTP).


    Da Dich aber natürlich Antworten auf die Benutzung des HTTP Protokoll interessiert hier ein möglicher Ansatz. Man kann sehr wohl, wenn Befehle nicht allzu zeitkritisch sind, vom Client zum Server mittels http Request eine logische Session mit dem Server aufbauen, indem man den jeden http Transfer als eine in sich abgeschlossene Einheit betrachtet. Dabei erstellt der Server einen handel (Zahl), der die Verbindung identifiziert. Dieser handel wird anschliessend vom Client bei jeder Aktion benutzt (mit geliefert), um die Session (eine logische Verbindung) zu identifizieren und aufrecht zu halten.


    Der Server setzt mit dem Aufbau der Sitzung ein Timeout auf, das ihm erlaubt zu erkennen, wenn ein vermutlicher Verbindungsabbruch erfolgte. Bei jedem Request des Clients mit dem korrekten Handle, wird das Timeout beim Server wieder zurück gesetzt (-> Verbindung ist noch da).


    Da der Server dem Client keine Anfrage oder Information zukommen lassen kann ohne dass der Client etwas geschickt hat, kann man lösen indem der Client in regelmässigen zeitlichen Abständen einen Request mit „KeepAlive“ an der Server schickt. Der Server muss darauf nicht unmittelbar Antworten, sondern kann seine Antwort etwas verzögern um vielleicht dem Client eine Information mitzuteilen.


    Diese Vorgehensweise benutzte ich, um ein Programm auf einem Client aus der Ferne kontrollieren zu können (Fern Wartung). Bekanntlich sitzen Arbeitsstationen in den Firmen hinter der FW und wollte man den Zugang von Aussen auf einen dieser Geräte erlauben, müsste man bei der FW ein Port öffnen und spezifizieren was da erlaubt sein soll und was nicht. Da aber die allermeisten Arbeitsstationen den Zugriff auf WebServer zulassen (von Innen nach Aussen) muss lediglich die Logik mit einem WebServer so umgestaltet werden, dass der Client und damit die SW auf dem Client immer einen HTTP Request zum Server offen hält, um darüber die Instruktionen von Aussen zu erhalten.


    Gruss
    Pus


    TCP Sitzungsaufbau

  • Hallo KaiR,

    vielen Dank für Deine Antwort. Ich hatte sowas schon befürchtet, das es komplizierter wird und das man eine andere "Mechanik" nutzen muss, daher gehe ich Deinen Ansatz, TCP zum Prüfen zu verwenden gern nach. Du hast Recht, eine Kontrollmimik zu verwenden, ist eine gute Lösung, meine erste Planung enthielt 5 Reed Kontakte, verteilt auf die Länge des Balkonfensters. Leider ist der Rolladen so krass dicht am Balkonfenster verbaut, sodass ich einen ausreichend starken Magneten nicht mehr zwischen Rolladen und Fenster bekomme, um die Reed-Kontakte sicher auszulösen. Gern schaue ich mich weiter um, mit dem neuen Ansatz. Vielen Dank für Deine Antwort. Vielleicht weiss ja noch jemand hierfür eine Lösung. Der Post ist ja auch erst ein paar Stunden alt.

  • Da das HTTP-Protokoll transaktionsorientiert ist, dürfte sich die Geschichte „Der Rolladen bewegt sich, solange der Button gedrückt ist (Totmannknopf)“ nicht ohne weiteres umsetzen lassen. Nur Button wurde gedrückt -> Rollladen bewegt sich. Button wird ein weiteres mal gedrückt -> Rolladen stoppt, funktioniert. So, wie es im geposteten Quellcode erfolgt.


    Beim Http-Protokoll erfolgen die Anfragen vom Client. Dieser erzeugt Requests, die vom Server beantwortet werden. Ist der Request bedient, kappt der Server die Verbindung wieder.


    Die Prüfung „ob der Client noch lebt“ muss demnach quasi vom Client selber kommen. Es müsste eher heißen, kann der Client den Server noch erreichen und reagiert dieser noch. Also ist der Ansatz eher schlecht, weil wenn der Server nicht mehr reagiert, nimmt er auch keine Steuerbefehle mehr an.


    Der Server (also der Micocontroller) könnte jedoch auf einer anderen Schicht, über den TCP-Socket, prüfen ob ein Client noch erreichbar ist.


    Evtl. lässt sich z.B. mit Javascript so etwas wie der Totmannknopf-Mechanismus umsetzen. Allerdings muss ich zugeben, dass mein Wissen um die Webprogrammierung veraltet ist. Evtl, gibt es ja noch Kniffe z.B. über HTML5 die ich nicht kenne. Das müssen Leute beantworten, die sich da besser auskennen.


    Was genau man alles machen kann wird auch von der Implementierung der ESPAsyncWebServer Bibliothek abhängen. Z.b. das Setzen von Cookies für die Clienterkennung.


    Der „Zerstörung“ des Rolladens könnte man ja durch entsprechende Reedkontakte am Rolladen oder einer elektronischen Kontrollmimik der Hebe-/Senkvorrichtung des Rolladens entgegenwirken.


    Jetzt habe ich viel geschrieben und konnte Dir nicht wirklich helfen, aber vielleicht waren ja ein paar Stichworte dabei, die bei Deiner Suche nach einer Lösung nützlich sind.

  • Liebe Community,


    ich würde gern einen Rolladen über ein Webinterface steuern, APPfrei sozusagen.


    Es soll im WebIF 2 Buttons geben (Up/Down).

    Weiterhin gibt es 3 Ausgänge:

    1. Relais "Netzteil 12V ein"

    2. Relais "Rolladen hoch"

    3. Relais "Rolladen runter"


    Funktion:

    - sobald ein Fahrbefehl ansteht, soll 1. Relais 12 ein kommen u. ca. 0,5 Sek. später entsprechendes Fahrrichtungsrelais

    - wenn Fahrbefehl beendet, Richtungsrelais sofort aus, 12V Relais ca. 5 Sek. später aus

    - bei Richtungsumkehr (evtl. Feinpositionierung) sollen ca. 0,5 Sek. vergehen, um auf jeden Fall die gleichzeitige Betätigung beider Richtungsrelais zu unterbinden und 1. Relais 12V ein bleibt betätigt (solange nicht mehr als 5 Sek. vergehen), auch wenn hier wieder der Fahrbefehl beendet ist, 5 Sek. später 12V aus (verlängert sich jeweils nach dem letzten Fahrbefehl)

    - wenn beide Richtungsbuttons gedrückt werden, bleibt alles aus.


    ja, ich bin mir bewusst, ich kann den Rolladen so auch zerstören, natürlich ist hier ein "Sichtfeedback" erforderlich...


    Nun zum Detail: Solange ich den Up-Button auf dem Handy im WebIF drücke, soll er fahren, wenn ich los lasse, soll er stoppen...soweit so gut...

    Problem:

    der Rolladen fährt weiter, wenn:

    - man aus Versehen den Home-Button am Handy drückt

    - das Handy ausschaltet (gegen den Ausschalter an der Seite kommt)

    - plötzlich das WLAN ausfällt oder der Empfang gestört ist)

    - der PC plötzlich einen Bluescreen bekommt

    - das Netzwerkkabel vom Laptop abzieht

    - das WLAN am Laptop durch Knopfdruck ausschaltet

    - der Router explodiert

    - ein Gauner sich von hinten anschleicht und ALT+F4 drückt... etc. ...

    - mir fallen noch weitere 100 Gründe ein, aber diese geschehen eher selten...


    Kann man hier eine Funktion einbauen, die überprüft, ob der verbundene Client noch "lebt" ?

    Kann man verhindern, dass ein 2. Client parallel im WebIF das Gleiche machen will?

    Ich denke in diese Richtungen:

    - während der WebIF Button Up/Down gedrückt wird, eine Art WebIF-Ping abfragen, wenn kein Ping zurück kommt, Rolladenstop

    - während der WebIF Button Up/Down gedrückt wird, 300ms Fahrbefehl anstehen lassen, aber nach 250ms erneut nachfragen, ob Richtugsbutton noch gedrückt ist, wenn ja wieder 350ms verlängern und wieder nach 250ms gedrückten Button abfragen, Ihr wisst, was ich meine...


    ich habe mir schon Gedanken gemacht, komme aber nicht weiter...

    - kein 1. Relais "Netzteil 12V ein" eingebunden

    - keine Ahnung, wie man hier "Totmannschalter/Heartbeat" - Funktion integrieren kann

    - keine Ahnung, wie man die Anzahl der Clienten auf einen beschränkt


    der Grundgedanke zu allem ist im Link im Programm enthalten

    Danke an Rui Santos

    (habe Ihn schon angeschrieben...Antwort:

    Unfortunately I don't have any tutorials on that exact subject, but it's definitely possible to implement that exact logic in the arduino code...

    Due to time constraints, I also don't do custom projects or consulting at the moment.)


    Ich hoffe, Ihr könnt mir helfen?

    Vielleicht ist auch der gesamte Lösungsansatz vollkommen falsch für diesen, meinen Zweck?

    Vielen Dank im Voraus



    hier das bisherige Arduino Programm:


    /*********

    Rui Santos

    Complete project details at https://RandomNerdTutorials.co…outputs-momentary-switch/


    Permission is hereby granted, free of charge, to any person obtaining a copy

    of this software and associated documentation files.


    The above copyright notice and this permission notice shall be included in all

    copies or substantial portions of the Software.

    *********/


    #include <ESP8266WiFi.h>

    #include <ESPAsyncTCP.h>

    #include <ESPAsyncWebServer.h>


    // REPLACE WITH YOUR NETWORK CREDENTIALS

    const char* ssid = "***";

    const char* password = "***";


    const int outputUP = 1;

    const int outputDOWN = 2;


    // HTML web page

    const char index_html[] PROGMEM = R"rawliteral(

    <!DOCTYPE HTML><html>

    <head>

    <title>Balkonrolladen</title>

    <meta name="viewport" content="width=device-width, initial-scale=1">

    <style>

    body {

    font-family: Arial;

    text-align: center;

    margin: 0% auto;

    padding-top: 1%;

    padding-bottom: 1%;

    background-color: #666666;

    }

    .button {

    width: 85%;

    height: 85%;

    font-size: 300%;

    text-align: center;

    line-height: 3;

    outline: none;

    color: #fff;

    background-color: #2f4468;

    border: none;

    border-radius: 5px;

    cursor: pointer;

    -webkit-touch-callout: none;

    -webkit-user-select: none;

    -khtml-user-select: none;

    -moz-user-select: none;

    -ms-user-select: none;

    user-select: none;

    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);

    }

    .button:active {

    background-color: #7f2e45;

    }

    </style>

    </head>

    <body>

    <h1>Balkonrolladen</h1>

    <button class="button buttonUP" onmousedown="toggleCheckbox('UPon');" ontouchstart="toggleCheckbox('UPon');" onmouseup="toggleCheckbox('UPoff');" ontouchend="toggleCheckbox('UPoff');">hoch</button>

    <br><br>

    <button class="button buttonDOWN" onmousedown="toggleCheckbox('DOWNon');" ontouchstart="toggleCheckbox('DOWNon');" onmouseup="toggleCheckbox('DOWNoff');" ontouchend="toggleCheckbox('DOWNoff');">runter</button>

    <script>

    function toggleCheckbox(x) {

    var xhr = new XMLHttpRequest();

    xhr.open("GET", "/" + x, true);

    xhr.send();

    }

    </script>

    </body>

    </html>)rawliteral";


    void notFound(AsyncWebServerRequest *request) {

    request->send(404, "text/plain", "Not found");

    }


    AsyncWebServer server(80);


    void setup() {

    Serial.begin(115200);

    WiFi.mode(WIFI_STA);

    WiFi.begin(ssid, password);

    if (WiFi.waitForConnectResult() != WL_CONNECTED) {

    Serial.println("WiFi Failed!");

    return;

    }

    Serial.println();

    Serial.print("ESP IP Address: http://");

    Serial.println(WiFi.localIP());


    pinMode(outputUP, OUTPUT);

    digitalWrite(outputUP, LOW);


    pinMode(outputDOWN, OUTPUT);

    digitalWrite(outputDOWN, LOW);


    // Send web page to client

    server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {

    request->send_P(200, "text/html", index_html);

    });


    // Receive an HTTP GET request UP HIGH

    server.on("/UPon", HTTP_GET, [] (AsyncWebServerRequest * request) {

    digitalWrite(outputDOWN, LOW);

    digitalWrite(outputUP, HIGH);

    request->send(200, "text/plain", "ok");

    });


    // Receive an HTTP GET request UP LOW

    server.on("/UPoff", HTTP_GET, [] (AsyncWebServerRequest * request) {

    digitalWrite(outputUP, LOW);

    request->send(200, "text/plain", "ok");

    });


    // Receive an HTTP GET request DOWN HIGH

    server.on("/DOWNon", HTTP_GET, [] (AsyncWebServerRequest * request) {

    digitalWrite(outputUP, LOW);

    digitalWrite(outputDOWN, HIGH);

    request->send(200, "text/plain", "ok");

    });


    // Receive an HTTP GET request DOWN LOW

    server.on("/DOWNoff", HTTP_GET, [] (AsyncWebServerRequest * request) {

    digitalWrite(outputDOWN, LOW);

    request->send(200, "text/plain", "ok");

    });


    server.onNotFound(notFound);

    server.begin();

    }


    void loop() {


    }