ESPHOME I/O Pin schalten basierend auf Binary Sensor für WLED Treppe

Hallo Zusammen,

ich hätte eine Frage ob ihr meinen Knoten im Hirn auflösen könnt.
Folgendes Szenario:
Mit WLED habe ich eine schöne Treppenbeleuchtung im Haus realisiert. Hierfür sind als Trigger in der Seite der Treppe PIR Sensoren eingelassen, die auch als solche in WLED genutzt werden.
Das Problem mit diesen Sensoren sind die vielen False-Positive Auslöser geschuldet dem Funktionsprinzip der PIR Sensoren.

Deshalb möchte ich jetzt auf Time of Flight Sensoren umsteigen.

Hierzu habe ich folgenden Code bislang umgesetzt

i2c:
  sda: GPIO4 #D2
  scl: GPIO5 #D1
  scan: True
  id: bus_a

sensor:
  - platform: vl53l0x
    id: distance_sensor_1
    name: "Laserschranke Treppe OG unten"
    address: 0x41
    enable_pin: GPIO0
    timeout: 200us
    update_interval: 500ms
    unit_of_measurement: m
    long_range: False
  
  - platform: vl53l0x
    id: distance_sensor_2
    name: "Laserschranke Treppe OG oben"
    address: 0x42
    enable_pin: GPIO2
    timeout: 200us
    update_interval: 500ms
    unit_of_measurement: m
    long_range: False
  
binary_sensor:
  - platform: template
    name: "Bewegungsmelder Treppe OG unten"
    device_class: motion
    lambda: |-
      if (id(distance_sensor_1).state < 0.7) {
        // Bewegung erkannt da Schranke durchbrochen
        return true;
      } else {
        // Keine Bewegung erkannt.
        return false;
      }
  - platform: template
    name: "Bewegungsmelder Treppe OG oben"
    device_class: motion
    lambda: |-
      if (id(distance_sensor_2).state < 0.7) {
        // Bewegung erkannt da Schranke durchbrochen
        return true;
      } else {
        // Keine Bewegung erkannt.
        return false;
      }



Dieser Funktioniert auch in HA.
Ich bekomme die Sensorwerte der TOFs angezeigt und auch der binäre Motion Sensor funktioniert.

Was möchte ich jetzt tun:
Der ESP soll die Bewegung erkennen und „direkt“ an WLED weitergeben - ohne das ich das via Home Assitant tue. Warum? Weil WLED hier teilweise etwas langsam ist und eine unmittelbare Reaktion erforderlich ist. Deshalb ziehe ich hier den Kabelweg vor.

Da ich native WLED (sprich ohne MODs) einsetzen möchte sind die Input Möglichkeiten begrenzt.
Hinzukommt, dass ich die Treppe bald auf ein neues professionelles WLED Modul (mit Trennrelais) umbauen möchte und hier wäre eine Lösung mit MODs nicht so toll. Desweiteren möchte ich die Sensoren in Home Assistant verfügbar machen für weitere Automationen.
Was jedoch geht ist für WLED einen „Schalter“ zusetzen. Hierzu muss ein PIN auf dem WLED Controller (auch ein ESP8266) einfach auf Low gesetzt werden und fertig.
Jetzt soll der ESP um den es hier geht genau das tun. Sprich ein Low Signal auf einen PIN setzen und diesen dann an WLED anschließen. Sofern beide die gleiche Stromversorgung haben (gleiches + und gleiches -) sollte das funktionieren.

Weil hierdurch entstehen für mich völlig neue Möglichkeiten…
WLED kann beim Schalter zwei verschiedene Aktionen ausführen:

  1. beim „Schalter drücken“
  2. beim „Schalter loslasen“

Genau das möchte ich mir zu nutze machen mit den Signalen die der ESP hier senden soll.

Erkennt der Sensor eine Bewegung z.b. Bewegungsmelder Treppe OG unten soll er einen GPIO auf low setzen und diesen solange auf Low lassen bis der andere Bewegungsmelder eine Bewegung erkennt (sprich ich bin oben angekommen) und dann wieder auf High gehen.

Somit kann ich ein korrektes Lauflicht bauen das mit mir die Treppe nach oben geht und dann die Treppe wieder ausschaltet wenn ich oben angekommen bin.

Nur fehlt mir dazu gerade total der Anfang wie ich das bauen könnte.

Für Tipps wäre ich sehr dankbar. Gerne stelle ich am Ende alles zum Nachbauen hier zur Verfügung.

Respekt :hugs:
Das ist bestimmt alles möglich, aber das schüttelt hier keiner aus dem Ärmel

Das wird viel mit on_ / then: / lamda / usw.

Größtes Projekt war eine Power Ampel mit 10 adressierbaren WLED und Display :hugs: der Code war schon recht lang für den ESP32. Aber die Steuerung macht dann trotzdem HA

Wünsche viel Erfolg :+1::four_leaf_clover:

Leute was soll ich sagen. Ich arbeite selbst seit fast 20 Jahren in und um die IT. Bin aber jetzt zugleich beeindruckt und schockiert zugleich.
Ich habe jetzt mal einen Selbstversuch gestartet mit ChatGPT und was soll ich sagen. Nach ungefähr 50 prompts hin und her kam jetzt eine vorerst funktionierende Logik heraus auf die ich - in der Form niemals gekommen wäre.

Ich wollte wie eingangs erwähnt eine nahezu HA unabhängige (Autonome) Lösung um etwaige Latenzen oder Netzwerkinterferenz vorzubeugen. Gerade die kleinen D1MINI neigen ja zu gelegentlichen WLAN Hickups. Für HA interessiert mich eigentlich nur die Tatsache ob die Bewegungsmelder was erkannt haben oder nicht. Der Rest soll wenn möglich komplett ohne HA gehen.

Nach viel Chatten kam heraus, dass die einzig sinnige Lösung für meine ganzen WENN-Dann-Sonst Bedingungen Lambda ist. Jedoch war auch mein Grunddenkfehler genau da…

Trivial gesagt:

Es gibt oben und unten jeweils einen Sensor der Bewegung erkennt. Wenn der Sensor oben auslöst soll WLED das Programm für Treppe runter starten. Wenn der untere Sensor auslöst soll das Programm von WLED Beendet werden. Genau das gleiche (nur umgekehrt wenn man die Treppe rauf geht)

Somit gibt es in Summe 4 Fälle zu betrachten:

  1. Start Go Down
  2. Stop Go Down
  3. Start Go Up
  4. Stop Go Up

Aber nun kommt die Falle:

Startet Fall 1 korrekt über die Lamda Funktion wird auch korrekt Fall 2 verarbeitet nun jedoch entsteht das Problem das Fall 3 auch auslöst weil wir ja wieder die Abfrage von vorne Starten und somit die Rahmenbedingungen auch für 3 erfüllt sind.
Das war die Schwierigkeit. Der restliche Code - ehrlich gesagt war nach 3 Prompts fertig…

esphome:
  name: tof-treppe-oben
  friendly_name: TOF_Treppe_oben

esp8266:
  board: d1_mini

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "***"

ota:
  - platform: esphome
    password: "***"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Tof-Treppe-Oben Fallback Hotspot"
    password: "***"

captive_portal:

i2c:
  sda: GPIO4 #D2
  scl: GPIO5 #D1
  scan: True
  id: bus_a





globals:
  - id: motion_threshold
    type: float
    restore_value: no
    initial_value: '0.2'  # Schwellenwert für den Abstand
  - id: action_in_progress
    type: bool
    restore_value: no
    initial_value: 'false'  # Flag, um zu verhindern, dass mehrere Aktionen gleichzeitig ausgeführt werden
  - id: last_action_time
    type: unsigned long  # Zeitstempel der letzten Aktion
    restore_value: no
    initial_value: '0'
  - id: wled_up_active
    type: bool
    restore_value: no
    initial_value: 'false'  # Zustandsflag für WLED Up
  - id: wled_down_active
    type: bool
    restore_value: no
    initial_value: 'false'  # Zustandsflag für WLED Down

sensor:
  - platform: vl53l0x
    id: distance_sensor_1
    name: "Laserschranke Treppe OG unten"
    address: 0x41
    enable_pin: GPIO0
    timeout: 200us
    update_interval: 500ms
    unit_of_measurement: m
    long_range: False

  - platform: vl53l0x
    id: distance_sensor_2
    name: "Laserschranke Treppe OG oben"
    address: 0x42
    enable_pin: GPIO2
    timeout: 200us
    update_interval: 500ms
    unit_of_measurement: m
    long_range: False

switch:
  - platform: gpio
    pin: GPIO13  # D7
    id: wled_up
    name: "WLED Up"
    restore_mode: ALWAYS_OFF

  - platform: gpio
    pin: GPIO15  # D8
    id: wled_down
    name: "WLED Down"
    restore_mode: ALWAYS_OFF

binary_sensor:
  - platform: template
    name: "Bewegungsmelder Treppe oben"
    id: motionsensor_top
    device_class: motion
    lambda: |-
      if (id(distance_sensor_2).state < id(motion_threshold)) {
        return true;
      }
      return false;

  - platform: template
    name: "Bewegungsmelder Treppe unten"
    id: motionsensor_bottom
    device_class: motion
    lambda: |-
      if (id(distance_sensor_1).state < id(motion_threshold)) {
        return true;
      }
      return false;

  # Kombinierter Bewegungsmelder, um die WLEDs zu steuern (internal)
  - platform: template
    name: "WLED Steuerung"
    id: wled_control
    device_class: power
    internal: true  # Dieser Sensor wird nicht in Home Assistant angezeigt
    lambda: |-
      // Verhindere mehrfaches Auslösen der Aktion
      if (id(action_in_progress)) {
        return false;
      }

      // Warten, bis der Zustand für eine neue Aktion bereit ist
      unsigned long current_time = millis();
      if (current_time - id(last_action_time) < 200) {
        return false; // Verhindere mehrfaches Auslösen innerhalb von 200 ms
      }

      // Start Go-Down (Bewegung oben erkannt, WLED Down einschalten)
      if (id(motionsensor_top).state && !id(motionsensor_bottom).state && !id(wled_up_active) && !id(wled_down_active)) {
        id(wled_down).turn_on();  // WLED Down einschalten
        id(wled_down_active) = true;  // WLED Down aktivieren
        id(action_in_progress) = true;
        id(last_action_time) = current_time;
        return true;
      }

      // Stop Go-Down (Bewegung unten erkannt, WLED Down ausschalten)
      if (!id(motionsensor_top).state && id(motionsensor_bottom).state && id(wled_down_active) && !id(wled_up_active)) {
        id(wled_down).turn_off();  // WLED Down ausschalten
        id(wled_down_active) = false;  // WLED Down deaktivieren
        id(action_in_progress) = true;
        id(last_action_time) = current_time;
        return true;
      }

      // Start Go-Up (Bewegung unten erkannt, WLED Up einschalten)
      if (id(motionsensor_bottom).state && !id(motionsensor_top).state && !id(wled_up_active) && !id(wled_down_active)) {
        id(wled_up).turn_on();  // WLED Up einschalten
        id(wled_up_active) = true;  // WLED Up aktivieren
        id(action_in_progress) = true;
        id(last_action_time) = current_time;
        return true;
      }

      // Stop Go-Up (Bewegung oben erkannt, WLED Up ausschalten)
      if (id(motionsensor_top).state && !id(motionsensor_bottom).state && id(wled_up_active) && !id(wled_down_active)) {
        id(wled_up).turn_off();  // WLED Up ausschalten
        id(wled_up_active) = false;  // WLED Up deaktivieren
        id(action_in_progress) = true;
        id(last_action_time) = current_time;
        return true;
      }

      return false;  // Keine Aktion erforderlich

  - platform: template
    name: "Reset Action Flag"
    id: reset_flag
    device_class: motion  # Wir verwenden motion als Device-Class für den Trigger
    internal: true  # Dieser Sensor wird nicht in Home Assistant angezeigt
    lambda: |-
      // Prüfe, ob 3 Sekunden vergangen sind (Timeout für die Aktion)
      if (millis() - id(last_action_time) > 3000) {
        id(action_in_progress) = false;  // Setze das Flag zurück, nachdem 3 Sekunden vergangen sind
      }
      return false;  // Der Sensor bleibt "inaktiv"

Jetzt tut der Code genau das was er soll. In Summe ist eine Cool Down Phase von 3 Sekunden eingebaut, was aber nicht stört.

Was jetzt noch fehlt, dass ich den Controller noch anweise wenn einer der beiden Schalter aktiv ist ein entsprechender GPIO Pin auf LOW gesetzt wird. Das sollte aber machbar sein.