Skip to main content

YAML per ESPHome Builder

substitutions:
  relay1_pin: D1   # GPIO5
  relay2_pin: D2   # GPIO4
  btn_up_pin: D5   # GPIO14
  btn_down_pin: D6 # GPIO12
  limit_switch_pin: D7  # GPIO13
  toggle_btn_pin: D9    # GPIO3 (RX)

  run_max: 12s # Max durata movimento
  lock_release_time: 5s # Rilascio tasti dopo fine corsa
  
  api_encryption_key: !secret luc_api_encryption_key
  ota_password: !secret luc_ota_password

  wifi_ssid_2_4G: !secret wifi_ssid_2_4G
  wifi_password_2_4G: !secret wifi_password_2_4G
    
  ap_ssid: !secret luc_ap_ssid
  ap_password: !secret luc_ap_password

esphome:
  name: lucernario
  friendly_name: Lucernario

esp8266:
  board: nodemcuv2

logger:
  level: DEBUG

api:
  encryption:
    key: ${api_encryption_key}

ota:
  - platform: esphome
    password: ${ota_password}

wifi:
  networks:
    - ssid: ${wifi_ssid_2_4G}
      password: ${wifi_password_2_4G}

  ap:
    ssid: ${ap_ssid}
    password: ${ap_password}

captive_portal:

globals:
  - id: up_locked
    type: bool
    restore_value: no
    initial_value: 'false'

  - id: down_locked
    type: bool
    restore_value: no
    initial_value: 'false'

  - id: last_direction
    type: int
    restore_value: no
    initial_value: '0'  # 0 = nessuna, 1 = UP, 2 = DOWN

switch:
# Relay 1
  - platform: gpio
    pin:
      number: ${relay1_pin}
      mode: OUTPUT
    name: "Relay 1"
    id: relay1
    restore_mode: ALWAYS_OFF  # spento all'avvio del sistema
    inverted: true # logica invertita per via del componente

# Relay 2
  - platform: gpio
    pin:
      number: ${relay2_pin}
      mode: OUTPUT
    name: "Relay 2"
    id: relay2
    restore_mode: ALWAYS_OFF
    inverted: true

# Toggle logico per HA (general purpose)
  - platform: template # entità per HA
    name: "Toggle Virtuale"
    id: toggle_virtual
    optimistic: true
    turn_on_action:
      - logger.log: "Toggle Virtuale ON"
    turn_off_action:
      - logger.log: "Toggle Virtuale OFF"
        
button:

# Tasto UP logico
  - platform: template
    name: "UP"
    id: btn_up_ha
    on_press:
      then:
        - globals.set:
            id: last_direction
            value: '1'
        - if:
            condition:
              lambda: 'return !id(up_locked);'
            then:
              - switch.turn_off: relay2   # spegne relay2 per sicurezza
              - switch.turn_on: relay1    # accende relay1 -> motore si muove
              - delay: ${run_max}   # durata massima del movimento
              - switch.turn_off: relay1   # torna a riposo
        - if:
            condition:
              lambda: 'return id(up_locked);' # controllo fine corsa
            then:
              - logger.log: "Direzione UP bloccata da HA"

# Tasto DOWN logico
  - platform: template
    name: "DOWN"
    id: btn_down_ha
    on_press:
      then:
        - globals.set:
            id: last_direction
            value: '2'
        - if:
            condition:
              lambda: 'return !id(down_locked);'
            then:
              - switch.turn_off: relay1
              - switch.turn_on: relay2
              - delay: ${run_max}   # durata massima del movimento
              - switch.turn_off: relay2
        - if:
            condition:
              lambda: 'return id(down_locked);'
            then:
              - logger.log: "Direzione DOWN bloccata da HA"

# Tasto STOP logico
  - platform: template
    name: "STOP"
    id: btn_stop
    on_press:
      - switch.turn_off: relay1
      - switch.turn_off: relay2

binary_sensor:

# Pulsante UP fisico
  - platform: gpio
    pin:
      number: ${btn_up_pin}
      mode: INPUT_PULLUP
      inverted: true
    id: btn_up_physical
    internal: true
    filters:
      - delayed_on: 50ms
      - delayed_off: 50ms
    on_press:
      then:
        - globals.set:
            id: last_direction
            value: '1'
        - if:
            condition:
              lambda: 'return !id(up_locked);'
            then:
              - switch.turn_off: relay2
              - switch.turn_on: relay1
              - delay: ${run_max}
    on_release:
      - switch.turn_off: relay1
      - switch.turn_off: relay2

# Pulsante DOWN fisico
  - platform: gpio
    pin:
      number: ${btn_down_pin}
      mode: INPUT_PULLUP
      inverted: true
    id: btn_down_physical
    internal: true
    filters:
      - delayed_on: 50ms
      - delayed_off: 50ms
    on_press:
      then:
        - globals.set:
            id: last_direction
            value: '2'
        - if:
            condition:
              lambda: 'return !id(down_locked);'
            then:
              - switch.turn_off: relay1
              - switch.turn_on: relay2
              - delay: ${run_max}
    on_release:
      - switch.turn_off: relay1
      - switch.turn_off: relay2

# Fine corsa
  - platform: gpio
    pin:
      number: ${limit_switch_pin}
      mode: INPUT_PULLUP
      inverted: true
    name: "Fine Corsa"
    id: limit_switch
    filters:
      - delayed_on: 50ms
      - delayed_off: 50ms

    on_press:
      then:
        # ferma il motore
        - switch.turn_off: relay1
        - switch.turn_off: relay2

        - if:
            condition:
              lambda: 'return id(last_direction) == 1;'
            then:
              - globals.set:
                  id: up_locked
                  value: 'true'
              - logger.log: "Fine corsa UP: direzione UP bloccata"
              - delay: ${lock_release_time}
              - globals.set:
                  id: up_locked
                  value: 'false'
              - logger.log: "Direzione UP sbloccata dopo lock_release_time"

        - if:
            condition:
              lambda: 'return id(last_direction) == 2;'
            then:
              - globals.set:
                  id: down_locked
                  value: 'true'
              - logger.log: "Fine corsa DOWN: direzione DOWN bloccata"
              - delay: ${lock_release_time}
              - globals.set:
                  id: down_locked
                  value: 'false'
              - logger.log: "Direzione DOWN sbloccata dopo lock_release_time"

# Sensore movimento UP
  - platform: template
    name: "Pulsante UP"
    lambda: 'return id(relay1).state;'
    icon: "mdi:arrow-up-bold"

# Sensore movimento DOWN
  - platform: template
    name: "Pulsante DOWN"
    lambda: 'return id(relay2).state;'
    icon: "mdi:arrow-down-bold"

# Sensore UP HA
  - platform: template
    name: "Direzione UP Attiva"
    lambda: 'return !id(up_locked);'
    icon: "mdi:arrow-up-bold"
    filters:
      - delayed_on: 10ms
      - delayed_off: 10ms

# Sensore DOWN HA
  - platform: template
    name: "Direzione DOWN Attiva"
    lambda: 'return !id(down_locked);'
    icon: "mdi:arrow-down-bold"
    filters:
      - delayed_on: 10ms
      - delayed_off: 10ms

# Sensore STOP HA
  - platform: template
    name: "STOP Attivo"
    lambda: 'return !id(relay1).state && !id(relay2).state;'
    icon: "mdi:stop"

# Toggle fisico
  - platform: gpio
    pin:
      number: ${toggle_btn_pin}
      mode: INPUT_PULLUP
      inverted: true
    name: "Pulsante Toggle"
    id: toggle_btn
    filters:
      - delayed_on: 50ms
      - delayed_off: 50ms
    on_press:
      - switch.toggle: toggle_virtual

# Wrapper per HA (dispositivo window)
cover:
  - platform: template
    name: "Lucernario"
    device_class: window
    open_action:
      - button.press: btn_up_ha
    close_action:
      - button.press: btn_down_ha
    stop_action:
      - button.press: btn_stop
    optimistic: true
    assumed_state: true