Startseite » Garagentor-Steuerung mit Hörmann ProMatic und OpenHAB

Garagentor-Steuerung mit Hörmann ProMatic und OpenHAB

Ein Hörmann-ProMatic-Garagentor lässt sich mit etwas Bastelaufwand smart nachrüsten. Aufbauend auf einer Vorlage von arduino-projekte.info zeige ich dir, wie du das Ganze mit ESPHome umsetzt und dein Garagentor sauber in OpenHAB steuerbar machst.

📅
•
⏱️ 10 Min. Lesezeit
•
✍️ Alexander Hacker

Wie kannst du deine ProMatic-Garagentor-Steuerung in dein OpenHAB einbinden?

Ich baue dabei auf den Beitrag von arduino-projekte.info auf und baue das kurz mit ESPHome nach. Der Vorteil ist, dass sich mit ESPHome auch für Laien schnell Veränderungen einarbeiten lassen, die Dokumentation wesentlich übersichtlicher wird und das Projekt auch schnell für andere SmartHome-Zentralen angepasst werden kann. In meinem Fall erstmal nach MQTT.

Der Hardware-technische Aufbau ist der Gleiche wie der auf arduino-projekte.info.

Hardware

Verdrahtung

Wie in arduino-projekte.info beschrieben, musst du zuerst die Klemmen-Belegung deiner Garagentorsteuerung bestimmen. Diese ist in der Bedienungsanleitung dokumentiert. Die werden wie auf der Platine beschrieben verbunden.

Den ESP8266 verlötest du am besten mit den langen Buchsenleisten kopfüber, sodass es einfach auf die Platine gesteckt werden kann, aber auch noch mit weiteren Pins von oben verbunden werden kann.

Einen BME680 schließe ich an D7 (SCL) und D8 (SDA) an und lasse ihn aus dem Gehäuse hängen um die Umgebungsdaten gleich auch zu messen.

Software

1) Vor oder nach dem Zusammenbau will der ESP8266 mit Software betankt werden. Mit ESPHome geht das sehr einfach, wenn du das erstmalig in Betrieb genommen hast. Python gibt es nicht nur für Linux, sondern auch für Windows. Hast du kein Linux auf deinem Rechner, willst es aber verwenden, kannst du das auch innerhalb einer VirtualBox laufen lassen. Ich habe es auch geschafft, mit Portable Python von Windows aus ESPHome zu verwenden.

1.1)Hinweis: Unter Ubuntu 22.04 wird der ESP nicht automatisch korrekt erkannt. Hier sind vorher noch zwei Handgriffe nötig:

  • btltty entfernen
sudo apt remove brltty #removes brltty, do not remove if you need this because of blindness!

oder benutze ein früheres Ubuntu.

Für Windows und normalerweise auch unter anderen Ubuntu-Versionen lässt sich der ESP recht einfach provisionieren ohne 1.1)

2) Schließe deinen ESP8266 an deinen Rechner an und provisioniere ihn mit web.esphome.io.

3) Und verwende folgende ESPHome-Konfiguration:
(nachdem du name, wifi und mqtt auf dein Netz angepasst hast)
Um zu verhindern, dass das Tor geöffnet wird, wenn der ESP8266 bootet, werden die PINs auf „inverted“ gesetzt

#**************************************************************
#* SmartHome ESP8266 Garagentor-Steuerung
#**************************************************************
#* ESP -- Sensor
#* 
#*  TX1 -- 
#*  RX0 -- 
#*  D1  -- Klemme 23 (S2)
#*  D2  -- Klemme 21 (S1)
#*  D3  -- [Free to use] [3V3-Level]
#*  D4  -- Tür-zu-Klemme
#*  GND -- GND
#*  5V  -- 5V
#*  
#*  RST -- 
#*  A0  -- [Free to use] [3V3-Level]
#*  D0  -- [Free to use] [3V3-Level]
#*  D5  -- [Free to use, with interrupt]
#*  D6  -- [Free to use] [3V3-Level]
#*  D7  -- SCL
#*  D8  -- SDA
#*  3V3 -- 
#*  
#*  Fensterkontakte Anschließen:
#*  1 Pin auf 5V, der andere auf den Dx-Eingang
#*
#**************************************************************/



esphome:
  name: arduino-s06

esp8266:
  board: d1_mini

# Enable logging
logger:

web_server:
  port: 80

# Enable Home Assistant API
#api:
#  password: ""

ota:
  password: ""

wifi:
  ssid: "XXXXXXXX"
  password: "XXXXXXXX"
  domain: ".local"
  reboot_timeout: 2min
  fast_connect: true
  power_save_mode: light
 
mqtt:
  broker: XXXXXX
  username: XXXXXX
  password: XXXXXX
  birth_message:
    topic: undef/undef/undef/undef/undef/Arduino_56/hello
    payload: online
  topic_prefix: undef/undef/undef/undef/undef/Arduino_56

#https://esphome.io/components/i2c/
i2c:
  id: i2c_main
  scl: D7
  sda: D8
  scan: true
  frequency: 20kHz

binary_sensor:
  #Digital Pins
  - platform: gpio
    pin: D4
    id: d4
    name: "D4"
    
sensor:
  - platform: bme280
    i2c_id: i2c_main
    temperature:
      name: "BME-T"
      id: bme_t
      oversampling: 8x
      filters:
        - filter_out: NaN
      internal: true
    pressure:
      name: "BME_P"
      id: bme_p
      oversampling: 8x
      filters:
        - filter_out: NaN
      internal: true
    humidity:
      name: "BME_H"
      id: bme_h
      oversampling: 8x
      filters:
        - filter_out: NaN
      internal: true
    address: 0x76
    update_interval: 10s
  - platform: template
    name: "Absolute Humidity"
    id: absolute_humidity
    lambda: |-
      const float mw = 18.01534;    // molar mass of water g/mol
      const float r = 8.31447215;   // Universal gas constant J/mol/K
      return (6.112 * powf(2.718281828, (17.67 * id(bme_t).state) /
        (id(bme_t).state + 243.5)) * id(bme_h).state * mw) /
        ((273.15 + id(bme_t).state) * r); // in grams/m^3
    accuracy_decimals: 2
    update_interval: 10s
    icon: 'mdi:water'
    unit_of_measurement: 'g/m³'
    filters:
      - filter_out: NaN
    internal: true
  - platform: template
    name: "Dew Point"
    id: dew_point
    lambda: |-
      return (243.5*(log(id(bme_h).state/100)+((17.67*id(bme_t).state)/
      (243.5+id(bme_t).state)))/(17.67-log(id(bme_h).state/100)-
      ((17.67*id(bme_t).state)/(243.5+id(bme_t).state))));
    unit_of_measurement: °C
    accuracy_decimals: 2
    update_interval: 10s
    icon: 'mdi:thermometer-alert'
    filters:
      - filter_out: NaN
    internal: true

switch:
  - platform: gpio
    pin: D2
    inverted: True
    restore_mode: RESTORE_DEFAULT_ON
    name: "Garage Door S1"
    id: garage_door_switch_s1
    on_turn_off:
      then:
        - delay: 0.1s
        - switch.turn_on: garage_door_switch_s1
  - platform: gpio
    pin: D1
    inverted: True
    restore_mode: RESTORE_DEFAULT_ON
    name: "Garage Door S2"
    id: garage_door_switch_s2
    on_turn_off:
      then:
        - delay: 0.1s
        - switch.turn_on: garage_door_switch_s2
  - platform: restart
    name: "Restart"
    
button:
  - platform: restart
    name: "Restart"
    

Einbindung in OpenHAB

Thing mittels mqtt-Binding anlegen:

Bridge mqtt:broker:myMosquitto "Mosquitto" [ host="XXXX", port=1883, secure=false, clientID="OpenHAB_pi", username="XXXXXX", password="XXXXXX" ] {}

	Thing mqtt:topic:myMosquitto:Arduino_56			"Arduino Garagentor"	(mqtt:broker:myMosquitto)	{
		Channels:
			Type switch : s1					[ stateTopic="+/+/+/+/+/Arduino_56/switch/garage_door_s1/state", commandTopic="undef/undef/undef/undef/undef/Arduino_56/switch/garage_door_s1/command", on="OFF", off="ON" ]
			Type switch : s2					[ stateTopic="+/+/+/+/+/Arduino_56/switch/garage_door_s2/state", commandTopic="undef/undef/undef/undef/undef/Arduino_56/switch/garage_door_s2/command", on="OFF", off="ON" ]
			Type switch : restart				[ commandTopic="undef/undef/undef/undef/undef/Arduino_56/switch/restart/command", on="OFF", off="ON" ]
	}

Warum verwende ich „secure=false“, warum hat mein MQTT keine verschlüsselte Verbindung? Ich sichere mein WLAN und biete auch für meine Freunde und Besucher nur ein Gast-WLAN an. Da mein privates WLAN-Netz nach aktuellem Stand der Technik gesichert ist, übertrage ich MQTT innerhalb der Verbindung unverschlüsselt.

Dazugehörige Items:
(Auch hier halte ich mich strikt an meine gesetzte Struktur, daher nochmal die ig-Gruppe darüber)

Group	igArduino56				(sgGarage)["Sensor"]
Switch	Arduino56_SwitchS1	"Garagentor" 	(igArduino56)		{ channel="mqtt:topic:myMosquitto:Arduino_56:s1", expire="1s,command=OFF", alexa="Door.Mode" [capabilityNames="Garagentor", supportedModes="ON=@Value.Open,OFF=@Value.Close", actionMappings="Close=ON,Open=ON,Lower=ON,Raise=ON"] }

Intelligente Automatisierung mit openHAB JS Scripting

Mit der reinen Schaltung des Kontakts ist das Garagentor zwar steuerbar, aber noch nicht „smart“. Die eigentliche Magie entsteht durch die Automatisierungsregeln in openHAB (hier umgesetzt mit modernem openHAB JS Scripting / ECMAScript 2021+):

  • Akustische Rückmeldung: Beim Öffnen des Tors wird sofort ein Sound-Befehl per MQTT abgesetzt (z. B. ein Ton über den Außenlautsprecher).
  • 20-Minuten-Offen-Warnung mit Kamera-Schnappschuss: Bleibt das Tor länger als 20 Minuten offen, schaltet openHAB kurz das Garagenlicht ein, wartet 3 Sekunden (damit sich die Belichtung der Überwachungskamera anpasst!), schießt ein Foto und sendet es via Telegram direkt auf das Smartphone.
  • Interaktive Telegram-Aktion: Zusammen mit dem Foto wird eine interaktive Abfrage mit Buttons gesendet: „Soll das Tor geschlossen werden? [Schließen] [Ignorieren]“.
  • Zwei-Wege-Verifikation: Klickt man auf „Schließen“, wird der Tasterimpuls ausgelöst. Nach 60 Sekunden Fahrzeit prüft openHAB über den Magnetsensor, ob das Tor wirklich zu ist. Falls nicht, erfolgt ein zweiter Schließ-Impuls mit Alarmierung.
const { rules, triggers, items, time, actions } = require('openhab');

// Konstante für die Chat-ID, damit du sie nicht überall ändern musst
const TELEGRAM_CHAT_ID = -552188908;
const SNAPSHOT_URL = "http://192.168.22.56:8081/";
const GARAGE_OPEN_TIMEOUT = 20 * 60 * 1000; // 20 minutes in milliseconds
const GARAGE_TRAVEL_TIME = 60 * 1000; // 40 seconds to wait before second impulse
const LIGHT_WARMUP_TIME = 3000; // 3 seconds to let camera exposure adjust

/**
 * Garage Door - Sends MQTT sound command when opened
 */
rules.JSRule({
  name: "GarageDoorOpened",
  triggers: [triggers.ItemStateChangeTrigger('Arduino56_door_state', 'CLOSED', 'OPEN')],
  execute: (event) => {
    // 1. Get the MQTT action broker
    const mqttActions = actions.get("mqtt", "mqtt:broker:myMosquitto");
    
    // 2. Publish sound command to the central MQTT topic
    if (mqttActions) {
      mqttActions.publishMQTT(
        "mecklar/outdoor/bell", 
        JSON.stringify({
          "play_url": "http://192.168.22.3/files/sounds/pkmn_lvl_up.wav",
          "volume": 50
        })
      );
    } else {
      console.error("MQTT Action could not be loaded!");
    }
  }
});

// Monitors the garage door state and triggers the Telegram query
rules.JSRule({
  name: "Garage Door 20 Min Warning",
  description: "Starts a timer when the garage door opens to send a snapshot and a Telegram query after 20 minutes.",
  triggers: [
    triggers.ItemStateChangeTrigger('Arduino56_door_state')
  ],
  execute: (event) => {
    const doorState = event.newState.toString();
    const openTimerCacheKey = 'garageOpenTimer';
    const verifyTimerCacheKey = 'garageVerifyTimer';

    if (doorState === 'OPEN') {
      // Start the 20-minute timer when the door is opened
      let openTimer = setTimeout(() => {
        
        // Turn on the garage light
        items.getItem('Garage_Brightness').sendCommand('ON');

        // Wait for the camera to adjust to the light, then take/send the photo
        setTimeout(() => {
          const telegramAction = actions.get("telegram", "telegram:telegramBot:home_Bot");
          if (telegramAction) {
            
            // 1. Send the snapshot photo
            telegramAction.sendTelegramPhoto(
              TELEGRAM_CHAT_ID, 
              SNAPSHOT_URL, 
              "Das Garagentor steht seit 20 Minuten offen!"
            );

            // 2. Send the interactive query
            telegramAction.sendTelegramQuery(
              TELEGRAM_CHAT_ID,
              "Soll das Tor geschlossen werden?",
              "Query_Close_Garage",
              "Schließen",
              "Ignorieren"
            );
          } else {
              console.error("Telegram Action could not be loaded!");
          }

          // 3. Turn the light back off
          items.getItem('Garage_Brightness').sendCommand('OFF');

        }, LIGHT_WARMUP_TIME);

      }, GARAGE_OPEN_TIMEOUT);
      
      cache.private.put(openTimerCacheKey, openTimer);

    } else if (doorState === 'CLOSED') {
      // Clear the open timer if the door is closed before 20 minutes
      let existingOpenTimer = cache.private.get(openTimerCacheKey);
      if (existingOpenTimer) {
        clearTimeout(existingOpenTimer);
        cache.private.put(openTimerCacheKey, null);
      }

      // Clear the verification timer if the door successfully closed after an impulse
      let existingVerifyTimer = cache.private.get(verifyTimerCacheKey);
      if (existingVerifyTimer) {
        clearTimeout(existingVerifyTimer);
        cache.private.put(verifyTimerCacheKey, null);
      }
    }
  }
});

// Handles the response from Telegram and manages the double-impulse logic
rules.JSRule({
  name: "Garage Door Telegram Reply Handler",
  description: "Executes the garage door impulse based on Telegram query reply.",
  triggers: [
    // Triggers when the specific reply ID is received
    triggers.ItemStateUpdateTrigger('TelegramBot_ReplyId', 'Query_Close_Garage')
  ],
  execute: (event) => {
    const lastMessage = items.getItem('TelegramBot_LastMessageText').state.toString();

    if (lastMessage === "Schließen") {
      // Send the first impulse to start door movement
      items.getItem('Arduino56_SwitchS2').sendCommand('ON');

      // Start a verification timer to check if the door actually closed
      let verifyTimer = setTimeout(() => {
        const currentDoorState = items.getItem('Arduino56_door_state').state.toString();

        if (currentDoorState === 'OPEN') {
          // Door is still open. Send the second impulse.
          items.getItem('Arduino56_SwitchS2').sendCommand('ON');
          
          // Optionally inform the user about the second attempt
          const telegramAction = actions.get("telegram", "telegram:telegramBot:home_Bot");
          if (telegramAction) {
            telegramAction.sendTelegram(
              TELEGRAM_CHAT_ID, 
              "Garagentor war nach 40 Sekunden noch offen. Zweiter Schließ-Impuls wurde ausgelöst."
            );
          }
        }
      }, GARAGE_TRAVEL_TIME);

      cache.private.put('garageVerifyTimer', verifyTimer);
    }
  }
});

Praxis-Tipp zum Kamera-Warmup: Überwachungskameras im Außenbereich oder in der Garage benötigen nach dem Einschalten einer Lampe meist 1–3 Sekunden, um Weißabgleich und Belichtungszeit nachzuregeln. Ohne den eingebauten 3-Sekunden-Timer wäre das Telegram-Foto bei Dunkelheit komplett überbelichtet oder weiß.

0
0
Alexander Hacker
Autor & Smart-Home-Entwickler

Alexander Hacker

Dokumentiert auf SmartHome Node praxisnahe Do-It-Yourself-Projekte, offene Architekturen und Automatisierungen mit openHAB 5, Zigbee2MQTT, ESPHome und Linux – ohne Abhängigkeit von Hersteller-Clouds.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden.

Translate »