Таймер полотенцесушителя на ESP-01s (ESP8266)

Используя умную розетку из предыдущей статьи сделал свой электрический полотенцесушитель умным. Изначально греющий кабель был помещен под настенную плитку и подключен к сети через модульный выключатель. Рядом оставил свободный модуль под заглушкой. Стандартное реле ESP-01s замечательно входит внутрь этой заглушки. Нужно лишь чуть подрезать ребра жесткости (третий рисунок). Напротив светодиодов реле и ESP высверлил два маленьких отверстия. Их можно заклеить клеевым пистолетом либо вставить световод (у меня 2мм рисунок 4) — будет выглядеть как промышленный. Провода, раньше подключенные к выключателю, теперь подключаем к зеленой колодке средний и нижний контакт (первый рисунок). В синий контактор блока питания (нижний модуль) подключаем фазу и ноль 220В. К контактам, отмеченным на втором рисунке припаиваем два провода и подключаем их к нашему выключателю. Теперь вместо замыкания силовых проводов он будет выполнять роль кнопки замыкая GPIO2 на GND.

Подсмотрел у современных LED светильников. Нужно было реализовать два таймера на 2 и 4 часа. Просто щелкаем выключатель — включается реле с небольшой задержкой и запускается таймер. Через 2 часа реле отключает нагрузку.

Если в течение 2 сек включить — выключить и снова включить, то реле щелкнет два раза указывая на то, что таймер заведен уже на 4 часа.

Вся логика зашита внутрь и не зависит от wi-fi соединения. Однако, заведя устройство в свой умный дом Home assistant, теперь можно сушить полотенца автоматически определяя по датчику движения + датчик влажности + время суток что кто-то принял душ.

Спустя год эксплуатации могу сказать что штука получилась хорошей — активно пользуемся. Изменили первую ступень на 3 часа — двух маловато. Из косяков выяснили, что если подать питание при нажатой клавише то он виснет. Такое бывает когда отключают свет. При восстановлении если клавиша была нажатой, то он виснет и чтобы его сбросить придется снова выключить свет.

esphome:
  name: socket2towel

esp8266:
  board: esp01_1m

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:
  password: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

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

  manual_ip:
    static_ip: 192.168.1.14
    gateway: 192.168.1.1
    subnet: 255.255.255.0
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Socket2 Fallback Hotspot"
    password: "xxxxxxxxxxx"

captive_portal:


script:
  - id: switch_on_timeout1
    then:
     - delay: 1s
     - switch.turn_on: socket2TowelSwitch
     - delay: 120min
     - switch.turn_off: socket2TowelSwitch   
  - id: switch_on_timeout2
    then:
     - delay: 1s
     - switch.turn_on: socket2TowelSwitch
     - delay: 0.3s
     - switch.turn_off: socket2TowelSwitch
     - delay: 0.3s
     - switch.turn_on: socket2TowelSwitch
     - delay: 240min
     - switch.turn_off: socket2TowelSwitch   
     
switch:
  - platform: gpio
    device_class: switch
    pin: GPIO0
    name: "Switch"
    inverted: true
    id: socket2TowelSwitch

  # The following can be omitted
  - platform: restart
    name: socket2towel restart

binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO2
      inverted: true
      mode:
        input: true
        pullup: true    
    name: "Towel warmer button"
    
    on_press:
      then:
        - script.execute: switch_on_timeout1
        
    on_multi_click:
      - timing:
        - OFF for at least 2s
        - ON for at least 1s
        then:
        - logger.log: "One-Clicked"
        - script.stop: switch_on_timeout2
        - script.execute: switch_on_timeout1
      - timing:
        - ON for at most 1.5s
        - OFF for at most 1.5s
        - ON for at least 1s
        then:
        - logger.log: "Double-Clicked"
        - script.stop: switch_on_timeout1
        - script.execute: switch_on_timeout2

    on_release:
      then:
        - logger.log: "Stop"
        - script.stop: switch_on_timeout1
        - script.stop: switch_on_timeout2
        - switch.turn_off: socket2TowelSwitch
        
    filters:
      - delayed_on_off: 60ms
      
sensor:
  - platform: wifi_signal
    name: socket2towel wifi signal
    update_interval: 600s

  # human readable uptime sensor output to the text sensor above
  - platform: uptime
    name: socket2towel Uptime in Days
    id: uptime_sensor_days
    update_interval: 300s
    on_raw_value:
      then:
        - text_sensor.template.publish:
            id: uptime_human
            state: !lambda |-
              int seconds = round(id(uptime_sensor_days).raw_state);
              int days = seconds / (24 * 3600);
              seconds = seconds % (24 * 3600);
              int hours = seconds / 3600;
              seconds = seconds % 3600;
              int minutes = seconds /  60;
              seconds = seconds % 60;
              return (
                (days ? String(days) + "d " : "") +
                (hours ? String(hours) + "h " : "") +
                (minutes ? String(minutes) + "m " : "") +
                (String(seconds) + "s")
              ).c_str();

time:
  - platform: homeassistant
    id: homeassistant_time

# Text sensors with general information.
text_sensor:
  # Expose ESPHome version as sensor.
  - platform: version
    name: socket2towel Version
  # Expose WiFi information as sensors.
  - platform: wifi_info
    ip_address:
      name: socket2towel IP
    bssid:
      name: socket2towel BSSID

  # human readable update text sensor from sensor:uptime
  - platform: template
    name: socket2towel Uptime Human Readable
    id: uptime_human
    icon: mdi:clock-start