Hörmann Garagentor mit ESP32 steuern

Hallo zusammen,
ich bin was Elektronik betrifft noch nicht so bewandert. Dennoch habe ich mich mal an ein Projekt gewagt, das ich hier vorstellen möchte. Tipps oder Hinweise gerne, besonders zur Hardware. Sonst lerne ich das nie :o

Zunächst die Hardware:
1 ESP32-DevKit
3 Optokoppler
3 Widerstände 330 Ohm
3 Widerstände 3.3 kOhm
1 Widerstand 1.0 kOhm

Die Schaltung habe ich mal mit Fritzing erstellt und sieht so aus.
Garagentor.png

Die ersten beiden Kontakte auf dem ESP sind beschriftet und liefern 5V und Masse. Die weiteren sind GPIO 12, 14 und 33.
Die 4 Kontakte auf dem Connector sind wie folgt mit dem Hörmann Promatic verbunden:
1: Kontakt 21a
2: Kontakt 20
3: rotes Motorkabel
4: schwarzes Motorkabel

Die Funktion ist dann ganz einfach:

[ul]
[li]Mit einem kurzen Impuls auf GPIO 12 wird das Garagentor über den rechten Optokoppler und die Pins 1 und 2 gestartet und gestoppt.
[/li][li]Die Motorspannung wird über die Pins 3 und 4 erfasst. Diese wird in unterschiedlicher Richtung in die beiden linken Optokoppler gespeist, was je nach Motorlaufrichtung ein Signal bei GPIO 14 oder 33 auslöst.
[/li][/ul]

Bei Interesse kann ich auch gerne die ino-Datei posten. Und wie gesagt: Fragen und Anregungen gerne.
Viele Grüße
Jürgen

1 „Gefällt mir“

Glaub mir, du willst davor noch eine UAP1 haben und diese dann steuern:

Alleine wegen den idempotenten Befehlen hoch und runter…

ne, geht auch ohne. Das Geld kann ich sparen. Ich hab es ausprobiert. Die Schaltung funktioniert.
Die UAP1 scheint nicht schlecht zu sein. Für mich lag aber der Reiz darin

  1. etwas selbst zu bauen
  2. das möglichst kostengünstig zu realisieren. (Die Schaltung kostet nur 10€)

Auch wenn die Schaltung funktioniert, würde mich interessieren, ob sie fachmännisch korrekt aufgebaut ist. Oder ob man das auch einfacher oder besser realisieren kann.

Viele Grüße
Jürgen

1 „Gefällt mir“

Was mir so direkt ins Auge springt, wozu die Pulldown-Widerstände? Der ESP32 sollte eigentlich in der Lage sein, seine GPIOS high oder low zu ziehen.

Also, schaden tut’s wohl auch nicht, aber mich würde interessieren warum du sie eingebaut hast :slight_smile:

Ah, ich sehe gerade, die sind ja bei den Eingängen. Dann macht’s schon Sinn.

Hast du den ESP mal in den Antrieb verbaut? Ich meine das das nur nach unten und nach vorne nicht mit Metal abgeschirmt ist. Oder willst du am ESP ne Externe Antenne anbauen?

Momentan habe ich die Schaltung noch im Fensterbrett liegen. Kontakt zum Accesspoint ist dort auch ohne Zusatzantenne sehr stabil. Ich gehe aktuell davon aus, dass es auch mit Gehäuse stabil funktioniert. Mein Hörmanngehäuse ist allerdings 3-seitig Kunststoff

1 „Gefällt mir“

Danke für´s Draufgucken. Genau mit den Pulldown-Widerständen war ich unsicher.

1 „Gefällt mir“

Hallo Siberstreif,

ich habe diesen Eintrag mit den unseeligen Hörmann– Steuerungen gefunden und halte Deinen Ansatz für den Besten!
Ich habe verschiedene Tore (Hörmann Alt, Neu, Anderers, hundsaltes Einfahrts-Schiebetor aus 74xx-Gatterkonglomerat usw.) und Dein Ansatz kann ja jedes Tor steuern!

Könntest Du bitte Deine Arbeit veröffentlichen?

Du würdest einen alten Mann sehr glücklich machen :wink:

Vielen Dank!

Gruß,

OldMan

kein Problem. Die Hardware habe ich oben ja bereits veröffentlicht. Hast du diese bereits nachgebaut?

Hallo Silberstreifen,

Danke!
Esp 32 ist bestellt, Optokoppler habe ich da…
Mit Elektronik komme ich einigermassen zurecht, beim Programmieren bin ich eine Null und wäre froh über eine Lösung.

Ich finde es von Hörmann extra shice, das die nur einen „Zustand-Wechsel-Dich“ - Knopf bieten… und für „kleines Geld“ die Standard-Taster als extra-Box anbieten - Die Box kostet mehr, als die ganze Hörmann-Steuerung wert ist.
Toll ist nur die Kraftmessung, die Unfälle verhindert, insofern komme ich um so ein Ding nicht rum.

Danke!

Gruß,

OldMan

ich befürchte, dass es ohne Programmierkenntnisse für dich eng wird, auch wenn ich den Code gerne zur Verfügung stelle. Der Code muss aber auf dein Garagentor angepasst werden. Da musst du dann ein wenig an den Parametern drehen. Gucke mal, ob das für dich passt.

  #include <WiFi.h>
  #include <ESPmDNS.h>
  #include <ArduinoOTA.h>
  #include <MQTT.h>

// -----------------------------------------------------------------------------------------
// Statusvariablen
// -----------------------------------------------------------------------------------------

  unsigned long statusSend   = 0;
  unsigned long statusTarget = 0;
  unsigned long doorStart    = 0;
  unsigned long doorOpen     = 0;
  unsigned long doorSend     = 0;
  unsigned long statusRec    = 0;
  unsigned long rebootTarget = 600000;

  int           doorSwitch   = 0;
  int           doorRun      = 0;
  int           calUp        = 74;
  int           calDown      = 50;
  int           TargetDir    = 0;
  
// -----------------------------------------------------------------------------------------
// Definitionen für den Programmablauf
// -----------------------------------------------------------------------------------------

  #define MotorAuf 33
  #define MotorZu  14
  #define Taster   12
  
  bool Merker[50];
  String LogMessage  = "";

// -----------------------------------------------------------------------------------------
// Definitionen WIFI und MQTT
// -----------------------------------------------------------------------------------------

  String Topic          = "Garagentor"; 
  const char* host      = "Garagentor";
  const char* wifi_ssid = "meinSSID";
  const char* wifi_key  = "ganzGeheim!";
  const char* mqtt_host = "192.168.2.3";

  WiFiClient wifi_client;
  MQTTClient mqtt_client(512);


// *****************************************************************************************
// connectWIFI
// *****************************************************************************************

  void connectWiFi() {
    Serial.print("Connecting to WiFi: ");
    Serial.println(wifi_ssid);
    WiFi.begin(wifi_ssid, wifi_key);
    int tries = 0;
    while (WiFi.status() != WL_CONNECTED) {
      if(tries++ > 10)return;
      delay(1000);
      Serial.print(".");
    }
    // Good. We have WiFi now!
    Serial.println(" Success!");
  }

// *****************************************************************************************
// connectMQTT
// *****************************************************************************************

  void connectMQTT() {
    if(WiFi.status() != WL_CONNECTED) return;

    // Connect to MQTT server
    Serial.print("Connecting to MQTT server: ");
    Serial.println(mqtt_host);

    int tries = 0;
    while (!mqtt_client.connect(host, "", "")) {
      if(tries++ > 10)return;
      delay(5000);
      Serial.print(".");
    }

    Serial.println(" Success!");
    mqtt_client.subscribe(Topic+"/reset");
    mqtt_client.subscribe(Topic+"/open");
    mqtt_client.subscribe(Topic+"/close");
    mqtt_client.subscribe(Topic+"/switch");
  }

// *****************************************************************************************
// messageReceived
// *****************************************************************************************

  void messageReceived(String &topic, String &payload) {
    Serial.println("incoming: " + topic + " - " + payload);
    if(topic == Topic+"/reset"){
      ESP.restart();
    }else if(topic == Topic+"/switch"){
      digitalWrite(Taster, (payload == "true")?HIGH:LOW);
    }else if(topic == Topic+"/close"){
      TargetDir = 2;
      digitalWrite(Taster, HIGH);
      mqtt_client.publish(Topic+"/TargetDir", String(TargetDir));
    }else if(topic == Topic+"/open"){
      TargetDir = 1;
      digitalWrite(Taster, HIGH);
      mqtt_client.publish(Topic+"/TargetDir", String(TargetDir));
    }
  }

// *****************************************************************************************
// setup()
// *****************************************************************************************

  void setup() {

// -----------------------------------------------------------------------------------------
// WIFI und MQTT starten  
// -----------------------------------------------------------------------------------------

    WiFi.mode(WIFI_STA);
    WiFi.hostname(host);
    mqtt_client.begin(mqtt_host, wifi_client);
    mqtt_client.onMessage(messageReceived);
    connectWiFi();
    connectMQTT();

// -----------------------------------------------------------------------------------------
// OTA starten  
// -----------------------------------------------------------------------------------------

    ArduinoOTA.setHostname(host);
    ArduinoOTA.setPassword("ich liebe OTA!");
    ArduinoOTA.begin();
    
// -----------------------------------------------------------------------------------------
// Hardware initialisieren
// -----------------------------------------------------------------------------------------

    pinMode(MotorAuf,INPUT);
    pinMode(MotorZu, INPUT);
    pinMode(Taster, OUTPUT);
  }

// *****************************************************************************************
// loop()
// *****************************************************************************************
  void loop() {

// -----------------------------------------------------------------------------------------
// OTA-Abfrage
// -----------------------------------------------------------------------------------------

    ArduinoOTA.handle();
  
// -----------------------------------------------------------------------------------------
// WiFi
// -----------------------------------------------------------------------------------------

    if(WiFi.status() != WL_CONNECTED){
      WiFi.disconnect();
      delay(100);
      connectWiFi();
    }
  
// -----------------------------------------------------------------------------------------
// MQTT
// -----------------------------------------------------------------------------------------

    if(!mqtt_client.connected())connectMQTT();
    mqtt_client.loop();
  
// -----------------------------------------------------------------------------------------
// Stati senden
// -----------------------------------------------------------------------------------------
  
  
// **********Motor läuft in Richtung auf

    bool tmpMotorAuf = digitalRead(MotorAuf);
    if(Merker[MotorAuf] != tmpMotorAuf){
      Merker[MotorAuf] = tmpMotorAuf;
      doorStart = millis() - doorOpen/calUp;
      if(Merker[MotorAuf]==HIGH){
        doorRun = 1;
      }else{
        doorRun = 0;
      }     
      mqtt_client.publish(Topic+"/doorRun", String(doorRun));
      statusTarget = 500;

//  ---------Bei Wende am unteren Anschlag auf 0% setzten

      delay(250);

      if(digitalRead(Taster)==HIGH){
        digitalWrite(Taster, LOW);
      }else{
        doorStart = millis();
      }

      if(TargetDir != 0 && TargetDir != doorRun){
        delay(300);
        digitalWrite(Taster, HIGH);
      }else{
        TargetDir = 0;
      }

    }

    if(tmpMotorAuf==HIGH){
      if(millis() - doorStart >= 10){
        if (doorStart > 0){
          doorOpen = (millis() - doorStart)*calUp;
          if(doorOpen > 1000000)doorOpen = 1000000;
        }
      }
    }
  
// **********Motor läuft in Richtung zu

    if(Merker[MotorZu] != digitalRead(MotorZu)){
      Merker[MotorZu] = digitalRead(MotorZu);
      doorStart = millis() + doorOpen/calDown;
      if(Merker[MotorZu]==HIGH){
        doorRun = 2;
      }else{
        doorRun = 0;
      }     
      mqtt_client.publish(Topic+"/doorRun", String(doorRun));
      statusTarget = 500;
      if(digitalRead(Taster)==HIGH){digitalWrite(Taster, LOW);}

      if(TargetDir != 0 && TargetDir != doorRun){
        delay(300);
        digitalWrite(Taster, HIGH);
      }else{
        TargetDir = 0;
      }

    }

    if(digitalRead(MotorZu)==HIGH){
      if(millis() - doorStart >= 10){
        if (doorStart > 0){
          doorOpen = (doorStart - millis())*calDown;
          if(doorOpen > 1000000)doorOpen = 0; //unsigned long kann keine negativen Werte;
        }
      }
    }

// **********Taster

    if(Merker[Taster] != digitalRead(Taster)){
      if(digitalRead(Taster)==HIGH){
        doorSwitch = 1;
      }else{
        doorSwitch = 0;
      }
      mqtt_client.publish(Topic+"/switch", digitalRead(Taster)?"true":"false");
      Merker[Taster] = digitalRead(Taster);
    }

// -----------------------------------------------------------------------------------------
// regelmäßig Status senden
// -----------------------------------------------------------------------------------------

    if(abs(millis() - statusSend) >= statusTarget){
      statusSend = millis();

      mqtt_client.publish(Topic+"/RSSI", String(WiFi.RSSI()));
      mqtt_client.publish(Topic+"/doorOpen", String(doorOpen/10000));
      mqtt_client.publish(Topic+"/doorRun", String(doorRun));
      int doorState = (doorOpen > 30000)?2:0;
      if(doorRun == 1){doorState = 3;}else if(doorRun == 2){doorState = 1;}
      mqtt_client.publish(Topic+"/doorState", String(doorState));
      mqtt_client.publish(Topic+"/switch", digitalRead(Taster)?"true":"false");

      if((doorRun > 0)||(doorSwitch==1)){statusTarget = 1000;}else{statusTarget = 60000;}
    }
  }

Ich habe versucht, den Code hilfreich zu kommentieren. Damit man da besser durchsteigt.
Viel Erfolg

Hallo Jürgen,

ich bin gerade über dein Projekt gestolpert. Die Idee die Richtung über die Motor-Kontakte abzugreifen finde ich genial. Bei mir habe ich damals Endschalter verbaut um sicher zu sein ob das Garagentor geöffnet oder geschlossen ist. Den Status, in welche Richtung das Garagentor fährt, habe ich softwaretechnisch realisiert.

In deinem Code ist mir aber eines nicht ganz klar, und zwar, wie du den Impuls erzeugst um das Garagentor in Bewegung zu setzten.

In der Funktion „messageReceived“ setzt du den Taster lediglich auf HIGH und startest somit den Impuls. Das Setzen auf LOW, somit der Abschluss des Impulses, erfolgt aber erst in der loop Schleife, jedoch erst wenn der Motor bereits läuft. D.h. wenn der Code bei dir so funktioniert, müsste dein Motor bereits mit einem HIGH-Signal loslaufen. Oder der PIN wird wird extern wieder auf LOW gezogen.

bool tmpMotorAuf = digitalRead(MotorAuf);
    if(Merker[MotorAuf] != tmpMotorAuf){
      Merker[MotorAuf] = tmpMotorAuf;
      doorStart = millis() - doorOpen/calUp;
      if(Merker[MotorAuf]==HIGH){
        doorRun = 1;
      }else{
        doorRun = 0;
      }     
      mqtt_client.publish(Topic+"/doorRun", String(doorRun));
      statusTarget = 500;

//  ---------Bei Wende am unteren Anschlag auf 0% setzten

      delay(250);

      if(digitalRead(Taster)==HIGH){
        digitalWrite(Taster, LOW);
      }else{
        doorStart = millis();
      }

      if(TargetDir != 0 && TargetDir != doorRun){
        delay(300);
        digitalWrite(Taster, HIGH);
      }else{
        TargetDir = 0;
      }
    }

Ja, genauso ist es. Der Hörmann-Antrieb fährt los, sobald der Taster auf HIGH geht. Erst wenn der Motorlauf registriert wird, wird der Taster wieder auf LOW gezogen. Das habe ich deshalb so gemacht, damit der Impuls immer lang genug ist, um den Motor zu starten.

Inzwischen habe ich das System seit über 6 Jahren im Einsatz und noch nie eine Störung gehabt.

Grüße
Jürgen

Dank für deine Antwort. Ich prüfe mal heute Abend ob das bei meinem Hörmann-Antrieb auch so ist. Und wenn dann auf beiden Motorkontakten keine Spannung drauf ist, nimmst du an, dass die Endlage erreicht ist?

nee das geht leider nicht. Da kann ja auch jemand über einen externen Taster oder eine Fernbedienung das Tor gestopt haben. Ich habe die Zeit für Öffnen und Schließen gestoppt und im Programm als Kalibrierwerte calUp und calDown hinterlegt. Aber den genauen Zusammenhang weiß ich gar nicht mehr nach über 6 Jahren. :man_shrugging:

Falls noch nicht bekannt. Es gibt einen User, der was fertiges gebaut hat. Über seinen kleinen Shop

ist eine fertige Platine für diese Sache zu beziehen. Er stellt sie selbst her und ich habe das Vorgängermodell im Einsatz.
Mit der neuen Platine kann man auch RS485 grundsätzlich anbinden.

Beim Hörmann Torantrieb war es sehr einfach. Klappe auf und Kabel anstecken.

Gruß

interessante Alternative.

Das Problem mit der Steuerung über den BUS ist, dass nach der ersten BUS-Kommunikation die Platine nicht offline gehen darf, in diesem Fall funktioniert das Tor nicht einmal manuell und man muss die Steuerung zurücksetzen. Das finde ich ehrlich gesagt nicht so toll. Außerdem macht es mehr spaß das Ganze selbst zu bauen und zu programmieren.

1 „Gefällt mir“

Ok

Wir hatten schon einige Stromausfälle bisher aber das hatte ich noch nicht bemerkt.

Gruß
Andreas