Rollladensteuerung mit ESP01 für Schalterdoseneinbau

Begonnen von Papa Romeo, 12 Juni 2018, 18:43:52

Vorheriges Thema - Nächstes Thema

Gisbert

Zitat von: Gisbert am 04 November 2018, 16:49:43
Hallo Papa Romeo,

vielen Dank, ich hab's jetzt zum Laufen gebracht.
Ich hatte mqttfx zum Subskribieren benutzt, und dafür funktioniert es sehr gut - aber das Publishen geht anscheinend anders als ich dachte, dass es gehen sollte.
D.h. CLIENTID/Befehl/Up geht nicht, auch alle Variationen mit Lehrzeichen, Gänsefüßchen etc. funktionieren nciht.

Nachdem ich Fhem ein Device angelegt habe mit einem entsprechend Attribut "CLIENTID/Befehl", geht der Befehl anstandslos raus.

Nochmals vielen Dank.
Bei dem 1. Gerät, das nicht wollte, muss ich noch auf Ursachenforschung gehen.

Viele Grüße Gisbert

Update zu den Schwierigkeiten, die ich hier im Forum geschildert habe:

Nach langem Versuchen habe ich zwei Rollladenschalter zum Laufen gebracht, hat mich einiges an Flashversuchen gekostet. Der Arduinosketch ist soweit funktional, ich wünsche mir aber noch einige weitere Verbesserungen, d.h. es geht dann noch weiter mit trial and error, wegen meiner mangelnden Arduinokenntnisse.

Woran meine anfänglichen Schwierigkeiten lagen, kann ich leider gar nicht sagen. Zunächst dachte ich ältere Libraries mit Arduino 1.8.0 seien notwenig, damit der Sketch läuft, zuletzt hab ich es mit Arduino 1.8.7 und den neuesten Libraries gemacht und es lief problemlos.

Nochmals vielen Dank
Gisbert​
Aktuelles FHEM | PROXMOX | Fujitsu Futro S740 | Debian 12 | UniFi | Homematic, VCCU, HMUART | ESP8266 | ATtiny85 | Wasser-, Stromzähler | Wlan-Kamera | SIGNALduino, Flamingo Rauchmelder FA21/22RF | RHASSPY

lewej

Hallo zusammen,

Zurzeit ist ja maxtime Fahrtzeit im Sketch vorgegeben, dss heisst man flasht seinen ESP für ein bestimmtes Fenster.

Könnte man diese Fahrzeit auch per mqtt konfigurierbar machen, die auch nach einem Stromausfall vorhanden ist.

Gruss

lewej

Hallo zusammen,

Wenn ich das Modul per Taster bediene, Schaltet das Modul gefühlte 1-2s versetzt.
Per mqtt Befehl geht es ohne Verzögerung.

Ist das nur bei mir so, oder konntet ihr dieses Verhalten auch beobachten?

Gisbert

Zitat von: lewej am 07 November 2018, 15:42:48
Hallo zusammen,

Zurzeit ist ja maxtime Fahrtzeit im Sketch vorgegeben, dss heisst man flasht seinen ESP für ein bestimmtes Fenster.

Könnte man diese Fahrzeit auch per mqtt konfigurierbar machen, die auch nach einem Stromausfall vorhanden ist.

Gruss

Hallo lewej,

genau das ist meine Intention, diese Daten an den ESP zusenden; ich hab auch noch vor eine "Lücke"-Funktion einzubauen, d.h. bspw. auf 17.3 Sekunden zu fahren - das muss dann noch im Sketch in % umgerechnet werden.

Ich melde mich, wenn ich's geschafft habe; kann aber dauern.

Viele​ Grüße​ Gisbert​
Aktuelles FHEM | PROXMOX | Fujitsu Futro S740 | Debian 12 | UniFi | Homematic, VCCU, HMUART | ESP8266 | ATtiny85 | Wasser-, Stromzähler | Wlan-Kamera | SIGNALduino, Flamingo Rauchmelder FA21/22RF | RHASSPY

Katzechrisu

Zitat von: Gisbert am 04 November 2018, 09:42:44
Hallo Katzechrisu,

ich bin gerade dabei den Sketch von Papa Romeo mit seinen Libraries zu testen; ich hoffe, dass ich damit Erfolg habe.
Mit Tasmota unter Zuhilfenahme von Rules konnte ich aus Tasmota heraus die Schaltung zum Laufen zu bringen, die Anordnung der Relais war nicht das Problem.
Was nicht funktioniert hat, war die Vorortbedienung.
Bald werde ich schlauer sein, wenn ich den Orginalsketch aufgespielt habe.

Viele Grüße Gisbert

Hallo Gisbert,
mit Tasmota und ioBroker habe ich das auch am laufen. Sogar mit der Vorortbedienung.
ganz ohne Tasmota-Rules.
Ich habe ganz einfach die zwei GPIO der Relais als Relais1 und 2 definiert damit kann man aus dem ioBroker schon schalten.
dann die Taster GPIOs als switch 3 und 4. Diese schalten dann virtuelle relais an GPIO 4 und 5.
mit den virtuellen Relais hab ich dann ein Blockly sript gebaut was bei down beide relais schaltet und bei up nur das eine.

Das ganze gefällt mir aber nicht so gut, weil dann ohne WLAN nix mehr geht.
Gibt es da eine Möglichkeit mit den Rules.
Ich muss gestehen da steige ich im Moment noch gar nicht durch

Katzechrisu

#140
Zitat von: Katzechrisu am 11 November 2018, 00:20:50
Hallo Gisbert,
mit Tasmota und ioBroker habe ich das auch am laufen. Sogar mit der Vorortbedienung.
ganz ohne Tasmota-Rules.
Ich habe ganz einfach die zwei GPIO der Relais als Relais1 und 2 definiert damit kann man aus dem ioBroker schon schalten.
dann die Taster GPIOs als switch 3 und 4. Diese schalten dann virtuelle relais an GPIO 4 und 5.
mit den virtuellen Relais hab ich dann ein Blockly sript gebaut was bei down beide relais schaltet und bei up nur das eine.

Das ganze gefällt mir aber nicht so gut, weil dann ohne WLAN nix mehr geht.

Gibt es da eine Möglichkeit mit den Rules.
Ich muss gestehen da steige ich im Moment noch gar nicht durch

So jetzt habe ich den Universalschalter genommen. Dabei mit der Brücke die Relaiskontakte NICHT! In Reihe geschaltet sondern parallel.
Damit gehts auch ohne iObroker.
Ich weiß PapaRomeo hat das extra so gemacht damit nicht beide Laufrichtungen gleichzeitig kommen können.
Deshalb habe ich bei Tasmota setoption14 eingeschaltet.
Und meine Taster sind mech. verriegelt.

Wenigstens eine Lösung bis ich das mit den Rules in Tasmota verstanden hab



lewej

Zitat von: lewej am 07 November 2018, 15:47:15
Hallo zusammen,

Wenn ich das Modul per Taster bediene, Schaltet das Modul gefühlte 1-2s versetzt.
Per mqtt Befehl geht es ohne Verzögerung.

Ist das nur bei mir so, oder konntet ihr dieses Verhalten auch beobachten?

Hallo,

habt ihr auch einen zeitlichen Versatz von ca. 1-2s, frage nochmal da kein Feedback bis jetzt.

Gruss

Katzechrisu

Ich schalte eins direkt und eins über Mqtt und ioBroker.
Auf beiden läuft Tasmota.
Kein Versatz festgestellt.


Ich stelle aber auch nochmal die Frage nach Tasmota Rules.
Kann das jemand verständlich auf deutsch erklären.

lewej

Hi,

Den Zetlichen Versatz habe ich mit der orginal ino Datei hier aus dem Thread, wäre Interessant ob das jemand auch hat.

Achja geschaltet wird mit den Berker S1 Schaltermaterial.

Gruss

Katzechrisu

Schaltermaterial dürfte ziemlich egal sein.

Den originalen Sketch hatte ich kurz drauf. Aber aber damit konnte ich nix anfangen.
Ich habe damit keine Verbindung zum ioBroker bekommen.

pc1246

Moin
Und zudem ist S1 nur das Drumherum (sichtbar auf der Wand), da fast alle Berker das gleiche in der Wand haben! (Aussnahme, die Drehschalter fuer Serien 1930, R.classic)
Gruss Christoph
HP T610
Onkyo_AVR;3 Enigma2; SB_Server ; SB_Player; HM-USB mit 15 HM-CC-RT-DN, 3 HM_WDS10_TH_O, 6 HM-Sec-SCo, 4 HM-Sec-MDIR-2, 1 HM-Sen-MDIR-O-2, 8 Ferion 5000 OW ; PhilipsTV; 4 harmony hub; Jeelink mit 9 PCA301; Somfy; S7-300; 3 LGW; HUE; HM-IP auf Charly

Sven77

Also der Sketch vom TE scheint (sorry Papa Romeo) recht undurchsichtig und - was immer als Generalausrede hiflt - "historisch gewachsen" zu sein... ;D

Wenn man den Code mal von Hand "abarbeitet", passiert vieles einfach doppelt (oder ich verstehe einfach nicht, warum es wiederholt wird) - Beispiel:
button1.tick() ruft bei Tastendruck DownHand() auf, was dann (u.a.) set_Down wieder auf 0 setzt, wenn es schon ganz unten ist. Danach macht TasterDown() genau das gleiche, wenn Modus!=1 und im Anschluss setzt relais() die Relais in den richtigen Zustand.

Was ich nun gar nicht verstehe: nachdem OneButton die ganze Vorarbeit geleistet hat, wird nochmal mir readDigital() der Tastenzustand geprüft und im Falle, das beide gedrückt sind, alles wieder rückgängig gemacht...

Nun aber zum eigentlichen Problem: die Verzögerung scheint durch die Implementierung von OneButton zu kommen.
Google hat mir als erstes Ergebnis diese Quelle hier dazu geliefert.
Dort wird _pressFunc() logischerweise erst nach Drücken des Tasters für 1s (_pressTicks=1000) aufgerufen und _clickFunc() erst im nächsten Durchlauf nach Erkennen des Clicks! Die wohl "richtige" Lösung wäre, das "else" vor den ganzen "else if (_state == [...]" zu entfernen. Will man das nicht, sollte es helfen, in der mail loop einfach beide Buttons 2x mittels tick() abzufragen:
void loop()
     {if (!client.connected())                                                    // wenn nicht verbunden - Reconnect
      {reconnect();}
      client.loop();                                                              // MQTT Client abhochen
      button1.tick();                                                             // Schalter Eingang 1 abfragen
      button2.tick();                                                             // Schalter Eingang 2 abfragen
      button1.tick();                                                             // Schalter Eingang 1 abfragen
      button2.tick();                                                             // Schalter Eingang 2 abfragen
      [...]


Unabhängig davon würde ich den Code grundsätzlich aufräumen und die Taster/Schalter-Steuerung priorisieren. Aktuell wird im ungünstigsten Fall, wenn beide Taster gedrückt werden, relais() ganze 3x aufgerufen und setzt dabei (wenn ich mich nicht verzählt habe) 7x client.publish() ab. Ganz zu schweigen davon, dass vorher ja auch schon client.loop() für jede(!) empfangene Nachricht, also auch für andere Kanäle, relais() aufruft und damit sicher auch schon oft genug client.publish() gestartet hat.

Kurzum - ich würde das strikt trennen: MQTT abfragen und "Wünsche" registrieren, danach die Taster abfragen und abgleichen. So eineindeutig den neuen Zustand der Relais bestimmen und diese einmalig setzen. Ganz am Ende, wenn noch Zeit bleibt, das ganze auf MQTT publizieren.

Darüberhinaus würde ich das delay(250) in relais() nur ausführen, wenn RelMOD>0, also nur wenn sie zu diesem Zeitpunkt überhaupt gefahren sind.
VG, Sven

Papa Romeo

Hallo Sven,

kein Problem, bin dir sogar für deine Kritik dankbar. Ich hab es schon mehrmals geschrieben, dass "Dieses" Programieren hier ein notwendiges Übel ist. Das "historisch gewachsen" kommt in etwa hin. Ich habe mir ein Grundgesrüst gebaut auf dem ich dann die Sketche aufgebaut habe. Hat was nicht so funktioniert wie ich dachte, hab ich es so " hingebogen"  dass es dann gepasst hat. Ich wäre sogar dankbar dafür, wenn jemand den Sketch "ausmisten" würde und mir dann zukommen ließe, damit ich sehen könnte, wie es optimaler gemacht werden kann.

Gruss

Papa Romeo
...die richtige Lötspitzentemperatur prüft man zwischen Daumen und Zeigefinger.
...überlasse niemals etwas einer Software, das du hardwaremässig erreichen kannst.
...unvorsichtige Elektriker werden schnell zu leitenden Angestellten.
und...never change a running System...no Updates if not necessary

lewej

Hallo Sven,

Wenn du das umbaust, wäre es genial wenn man Taster und Relais von einander per Option trennen könnte.
Sprich ich Taste, Nachricht an eine Zentrale Stelle und Server schaltet die Relais.

Als weiterer Punkt, wäre statt mqtt die Nachrichten per UDP zu senden.

Dann wäre dieses Modul direkt in Loxone auch einsetzbar!

Gruss

Gisbert

Hallo Sven,
Hallo Papa Romeo,

wir wollen aber nur konstruktive Kritik am Sketch anbringen; ohne den Sketch von Papa Romeo wäre ich zumindest komplett aufgeschmissen, was mich aber auch gleich zu meinem Problem führt.

Ich möchte gerne einen Webserver integrieren. Damit habe ich die Möglichkeit beim Aufrufen der IP-Adresse des Schalters Fahrbefehle abzusetzen. Damit gibt es eine weitere Möglichkeit den Schalter zu bedienen, z.B. vom Sofa aus. Die Bedienung über Fhem will sich vielleicht nicht jedes Familienmitglied antun.

Wenn ich den Webserver, den ich aus dem Blog von Stefan Thesen habe und mit einem Sonoff Dual bestens funktioniert, in den Sketch von Papa Romeo einbaue, dann läuft dieser nicht mehr "richtig". Er fährt dann nur bis zum nächsten % und bleibt dann dort eingeschaltet stehen.

Ich hänge den Sketch, den ich auf einem Sonoff Dual nutze, an, in der Hoffnung, dass sich jemand der Sache annimmt und den Webserver-Teil in den Sketch von Papa Romeo integriert.
Hinweis, falls es jemand probiert:
Für das Schalten über den Webserver muss in Fhem noch eine Defintion hinterlegt werden.
Die Kompilierung in Arduino muss mit dem Board Manager esp8266 in der Version 2.4.0 erfolgen.

Viele Grüße Gisbert

#include <SPI.h>
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>


// Counters
unsigned long ulReqcount;
unsigned long ulReconncount;

// Create an instance of the server
// Specify the port to listen on as an argument
WiFiServer server(80);

// Time to wait when turning motor off or changing direction
// Recommended to allow motor capacitor to unload over motor coil
#define MOTORWAIT 300

// Time for direction relay to swtich before power is applied
// Recommended to avoid implicit switch of direction with power on
#define RELAISWAIT 200

// Duration of a motor event
#define EVENT 40000
unsigned long ulMotorEventEnd=0;  // end of current motor event

// Rollladen auf Lücke, von oben
unsigned int ZeitLuecke = 23600;

// Relaisschaltung
void switch_relay(byte b)
{
  if (0<=b && b<=2)
  {
    Serial.write(0xA0);
    Serial.write(0x04);
    Serial.write(b);
    Serial.write(0xA1);
    Serial.flush();
  }
}


const char* mqttServer = "192.168.xx.yy";
const int mqttPort = 1883;
const char* mqttUser = "myUSER";
const char* mqttPassword = "myPASSWORD";

WiFiClient client;
PubSubClient MQTTclient(client);

// Topic für die Subskription der Fahrzeit des Rollladens auf Lücke
char* RollladenLuecke = "/Pub/Rollladen/Gisbert/Luecke";

// Topic für das Publishen des durchgeführten Fahrbefehls
char* RollladenPub = "/Sub/Rollladen/Gisbert";


void reconnect()
{
  while (!MQTTclient.connected())
  {
    Serial.println("Connecting to MQTT...");
    if (MQTTclient.connect("ROLLLADEN", mqttUser, mqttPassword))
      {
        Serial.println("connected");
        MQTTclient.publish(RollladenPub,"online");
        MQTTclient.subscribe(RollladenLuecke);
       
      } else
      {
        Serial.print("failed with state ");
        Serial.print(MQTTclient.state());
        delay(2000);
      }
  }
}


// Setup routine

void setup()
{
  ulReqcount=0;
  ulReconncount=0;

  Serial.begin(19200);
 
  // Switch off both relays
  switch_relay(0);
  delay(MOTORWAIT);

  WiFiManager wifiManager;
  wifiManager.autoConnect("AP_Roll_Gisbert", "configesp");
  Serial.println("");
  Serial.println("WiFi connected");
 
  // Start the server
  server.begin();
  Serial.println("Server started");

  // Print the IP address
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  MQTTclient.setServer(mqttServer, mqttPort);
  MQTTclient.setCallback(callback);

  while (!MQTTclient.connected())
  {
    Serial.println("Connecting to MQTT...");
    if (MQTTclient.connect("ROLLLADEN", mqttUser, mqttPassword))
      {
        Serial.println("connected"); 
      } else
      {
        Serial.print("failed with state ");
        Serial.print(MQTTclient.state());
        delay(2000);
      }
  }
}


// handle message arrived
void callback(char* topic, byte* payload, unsigned int length)
{
  payload[length] = '\0';
  String sPayload = String((char *)payload);
  String sTopic = String(topic);
    if (sTopic == "/Pub/Rollladen/Gisbert/Luecke")
    {
      ZeitLuecke = sPayload.toInt();
    }
}


void loop()
{
  // Stop motor if required
  if (ulMotorEventEnd<millis())
  {   
    switch_relay(0);
    delay(MOTORWAIT);
  }
   
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client)
  {
    return;
  }
 
  // Wait until the client sends some data
  Serial.println("new client");
  unsigned long ULTIMEOUT = millis()+250;
  while(!client.available() && (millis()<ULTIMEOUT) )
  {
    delay(1);
  }
  if (millis()>ULTIMEOUT)
  {
    Serial.println("client connection time-out!");
    return;
  }
 
  // Read the first line of the request
  String sRequest = client.readStringUntil('\r');
  client.flush();
 
  if (sRequest=="")
  {
    Serial.println("empty request! - stopping client");
    client.stop();
    return;
  }

  if (!MQTTclient.connected())
  {
    reconnect();
  } 
  MQTTclient.loop();
  delay(10);

 
  // Get path; end of path is either space or ?
  // Syntax is e.g. GET /?pin=MOTOR1STOP HTTP/1.1
  String sPath="",sParam="", sCmd="";
  String sGetstart="GET ";
  int iStart,iEndSpace,iEndQuest;
  iStart = sRequest.indexOf(sGetstart);
  if (iStart>=0)
  {
    iStart+=+sGetstart.length();
    iEndSpace = sRequest.indexOf(" ",iStart);
    iEndQuest = sRequest.indexOf("?",iStart);
   
    // Are there parameters?
    if(iEndSpace>0)
    {
      if(iEndQuest>0)
      {
        // There are parameters
        sPath  = sRequest.substring(iStart,iEndQuest);
        sParam = sRequest.substring(iEndQuest,iEndSpace);
      }
      else
      {
        // NO parameters
        sPath  = sRequest.substring(iStart,iEndSpace);
      }
    }
  }
 
// Output command to serial so that we can read it on the Arduino

  if(sParam.length()>0)
  {
    int iEqu=sParam.indexOf("=");
    if(iEqu>=0)
    {
      sCmd = sParam.substring(iEqu+1,sParam.length());
      // Output to serial, which is connceted to the Arduino
      Serial.println(sCmd);
    }
  }
 
// Format the html response

  String sResponse,sHeader;
 
// 404 for non-matching path

  if(sPath!="/")
  {
    sResponse="<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL was not found on this server.</p></body></html>";

    sHeader  = "HTTP/1.1 404 Not found\r\n";
    sHeader += "Content-Length: ";
    sHeader += sResponse.length();
    sHeader += "\r\n";
    sHeader += "Content-Type: text/html\r\n";
    sHeader += "Connection: close\r\n";
    sHeader += "\r\n";
  }
 
  // Format the html page
 
  else
  {
    ulReqcount++;
    sResponse  = "<html><head><title>SZ.Gisbert</title></head><body>";
    sResponse += "<font color=\"#000000\"><body bgcolor=\"#d0d0f0\">";
    sResponse += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">";
    sResponse += "<h1>Rollladen Schlafzimmer Gisbert</h1>";
    sResponse += "<FONT SIZE=+2>";
    sResponse += "<p><a href=\"?pin=FunctionHoch\"><button>Hoch</button></a>&nbsp;<a href=\"?pin=FunctionStop\"><button>Stop</button></a>&nbsp;<a href=\"?pin=FunctionRunter\"><button>Runter</button></a>&nbsp;<a href=\"?pin=FunctionLuecke\"><button>L&uuml;cke</button></a></p>";

    // React on parameters

    if (sCmd.length()>0)
    {
      // Write received command to html page
      sResponse += "Kommando: " + sCmd + "<BR>";
     
        // Prepare relays - 230 Volt Schaltung Ein / Aus
        // Both relays off
        // switch_relay(0);
        // Relay 1 on
        // switch_relay(1);
        // Relay 2 on
        // switch_relay(2);
        // Both relays on - Das muss bei einer Rolladenschaltung unbedingt vermieden werden, da ansosnsten der Motor zerstört wird !!!
        // switch_relay(3);
        // Relais 1: Runterfahren
        // Relais 2: Hochfahren
             
      if(sCmd.indexOf("FunctionStop")>=0)
      {
        MQTTclient.publish(RollladenPub, "Stop");
        delay(10);
        switch_relay(0);
        ulMotorEventEnd=millis();
        MQTTclient.publish(RollladenPub, "Stop");
      }

      else if(sCmd.indexOf("FunctionRunter")>=0)
      {       
        MQTTclient.publish(RollladenPub, "Runter");
        delay(RELAISWAIT);       
        switch_relay(0);
        delay(MOTORWAIT);
        switch_relay(1);
        ulMotorEventEnd=millis()+EVENT;
        MQTTclient.publish(RollladenPub, "Runter");
      }

      else if(sCmd.indexOf("FunctionLuecke")>=0)
      {       
        MQTTclient.publish(RollladenPub, "L&uuml;cke");
        delay(RELAISWAIT);       
        switch_relay(0);
        delay(MOTORWAIT);
        switch_relay(1);
        ulMotorEventEnd=millis()+ZeitLuecke;
        MQTTclient.publish(RollladenPub, "L&uuml;cke");
      }

      else if(sCmd.indexOf("FunctionHoch")>=0)
      {
        MQTTclient.publish(RollladenPub, "Hoch");
        delay(RELAISWAIT);       
        switch_relay(0);       
        delay(MOTORWAIT);
        switch_relay(2);
        ulMotorEventEnd=millis()+EVENT;
        MQTTclient.publish(RollladenPub, "Hoch");
      }
    }

    sResponse += "<FONT SIZE=-2>";
    sResponse += "<BR>Aufrufz&auml;hler=";
    sResponse += ulReqcount;
    sResponse += " - Verbindungsz&auml;hler=";
    sResponse += ulReconncount;
    sResponse += "<BR>";
    sResponse += "Aktueller Stand<BR>";
    sResponse += "</body></html>";
   
    sHeader  = "HTTP/1.1 200 OK\r\n";
    sHeader += "Content-Length: ";
    sHeader += sResponse.length();
    sHeader += "\r\n";
    sHeader += "Content-Type: text/html\r\n";
    sHeader += "Connection: close\r\n";
    sHeader += "\r\n";
  }


  // Send the response to the client
  client.print(sHeader);
  client.print(sResponse);
  client.stop();

  Serial.println("Client disonnected");
}
Aktuelles FHEM | PROXMOX | Fujitsu Futro S740 | Debian 12 | UniFi | Homematic, VCCU, HMUART | ESP8266 | ATtiny85 | Wasser-, Stromzähler | Wlan-Kamera | SIGNALduino, Flamingo Rauchmelder FA21/22RF | RHASSPY