Skip to content

Instantly share code, notes, and snippets.

@muxa
Last active May 25, 2024 18:41
Show Gist options
  • Save muxa/68a6e8f8cdbb734c9e0d06a9b87d0147 to your computer and use it in GitHub Desktop.
Save muxa/68a6e8f8cdbb734c9e0d06a9b87d0147 to your computer and use it in GitHub Desktop.
ESPHome Garage Switch with State Machine
substitutions:
room: Garage
device_name: Garage Switch
esphome:
name: garage_switch
platform: ESP8266
board: esp01_1m
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: true
logger:
level: DEBUG
api:
password: !secret api_password
ota:
password: !secret ota_password
external_components:
- source:
type: git
url: https://github.com/muxa/esphome-state-machine
binary_sensor:
- platform: gpio
pin:
number: GPIO16 #D0
mode: INPUT
inverted: True
name: "${device_name} Button 1"
internal: true
on_press:
- switch.toggle: load1
- platform: gpio
pin:
number: GPIO5 #D1
mode: INPUT
inverted: True
name: "${device_name} Button 2"
internal: true
on_multi_click:
- timing:
- ON for at least 500ms
then:
- logger.log: "- Garage door button held over 1s"
- switch.turn_on: garage_opener_relay
- state_machine.transition: PRESS
- platform: status
id: status_sensor
internal: true
name: "${device_name} API Status"
on_press: # connected
- logger.log: "CONNECTED"
- delay: 1s
- if:
condition:
binary_sensor.is_on: closed_endstop
then: # open
- logger.log: Garage door is open according to endstop
- if:
condition:
- state_machine.state: CLOSED
then:
- state_machine.set: OPEN
else: # closed
- state_machine.set: CLOSED
on_release: # disconnected
- logger.log: "DISCONNECTED"
- platform: homeassistant
name: "Garage Door Contact"
internal: true
id: closed_endstop
entity_id: binary_sensor.garage_door_sensor_contact
on_press: # garage is open(ing)
- state_machine.transition: OPENING_DETECTED
on_release: # garage is closed
- state_machine.transition: CLOSED_DETECTED
- platform: template
name: "Garage Door Obstruction"
device_class: problem # on means problem detected, off means no problem (OK)
lambda: |-
auto current_state = id(garage_sm).current_state();
return current_state.compare("CLOSING_INTERRUPTED") == 0
|| current_state.compare("OPENING_INTERRUPTED") == 0;
filters:
delayed_on: 2s
switch:
- platform: gpio
name: "Garage Light"
pin: GPIO13 #D7
id: load1
- platform: gpio
name: "Garage Door Switch"
pin: GPIO12 #D6
id: garage_opener_relay
internal: true
icon: "mdi:garage"
on_turn_on:
- delay: 200ms
- switch.turn_off: garage_opener_relay
status_led:
pin:
number: GPIO2 #D4
inverted: yes
sensor:
- platform: wifi_signal
name: "${device_name} WiFi Signal"
update_interval: 60s
- platform: uptime
name: "${device_name} Uptime"
filters:
- lambda: return x / 86400.0;
unit_of_measurement: "days"
accuracy_decimals: 1
# text_sensor:
# - platform: state_machine
# name: Garage Door State
state_machine:
- name: Garage Door State Machine
id: garage_sm
states:
- name: CLOSED
on_enter:
- cover.template.publish:
id: garage_door
state: CLOSED
current_operation: IDLE
- name: OPENING
on_enter:
- cover.template.publish:
id: garage_door
state: OPEN
current_operation: OPENING
- delay: 16s
- state_machine.transition: TIMEOUT
- name: OPEN
on_enter:
- cover.template.publish:
id: garage_door
state: OPEN
current_operation: IDLE
- name: OPENING_INTERRUPTED
on_enter:
- cover.template.publish:
id: garage_door
state: OPEN
current_operation: IDLE
- name: CLOSING
on_enter:
- cover.template.publish:
id: garage_door
state: OPEN
current_operation: CLOSING
- delay: 17s
- state_machine.transition: TIMEOUT
- name: CLOSING_INTERRUPTED
on_enter:
- cover.template.publish:
id: garage_door
state: OPEN
current_operation: IDLE
inputs:
- name: PRESS
transitions:
- CLOSED -> OPENING
- OPENING -> OPENING_INTERRUPTED
- OPENING_INTERRUPTED -> CLOSING
- OPEN -> CLOSING
- CLOSING -> CLOSING_INTERRUPTED
- CLOSING_INTERRUPTED -> OPENING
- name: TIMEOUT
transitions:
- OPENING -> OPEN
- CLOSING -> CLOSED
- name: OPENING_DETECTED
transitions:
- CLOSED -> OPENING
# below is a fallback so that contact sensor can override "normal" transitions
- CLOSING -> OPENING
- OPENING_INTERRUPTED -> OPENING
- CLOSING_INTERRUPTED -> OPENING
- name: CLOSED_DETECTED
transitions:
- CLOSING -> CLOSED
# below is a fallback so that contact sensor can override "normal" transitions
- OPEN -> CLOSED
- OPENING -> CLOSED
- OPENING_INTERRUPTED -> CLOSED
- CLOSING_INTERRUPTED -> CLOSED
- name: OPEN
transitions:
- CLOSED -> OPENING
- CLOSING -> CLOSING_INTERRUPTED
- CLOSING_INTERRUPTED -> OPENING
- OPENING_INTERRUPTED -> CLOSING
on_input:
- switch.turn_on: garage_opener_relay
- delay: 1500ms
- state_machine.transition: OPEN
- name: CLOSE
transitions:
- OPEN -> CLOSING
- OPENING -> OPENING_INTERRUPTED
- OPENING_INTERRUPTED -> CLOSING
- CLOSING_INTERRUPTED -> OPENING
on_input:
- switch.turn_on: garage_opener_relay
- delay: 1500ms
- state_machine.transition: CLOSE
- name: STOP
transitions:
- OPENING -> OPENING_INTERRUPTED
- CLOSING -> CLOSING_INTERRUPTED
on_input:
- switch.turn_on: garage_opener_relay
cover:
- platform: template
name: "Garage Door"
id: garage_door
device_class: garage
lambda: |-
if (id(garage_sm).current_state().compare("CLOSED") == 0) {
return COVER_CLOSED;
} else {
return COVER_OPEN;
}
open_action:
- logger.log: "Garage door is being opened by HA"
- state_machine.transition: OPEN
close_action:
- logger.log: "Garage door is being closed by HA"
- state_machine.transition: CLOSE
stop_action:
- logger.log: "Garage door is stopped by HA"
- state_machine.transition: STOP
@hoontune
Copy link

hoontune commented Oct 4, 2022

I have a garage door with a reed switch on GPIO5 that only tells me if the door is closed. I don't have a sensor to tell me direction of travel or if the door is fully open. A Shelly1 controls the door by toggling a relay. The issue is that toggling the relay while the door is still moving creates a different situation than if you toggle the relay when the door has stopped moving.

That's where I believe your state machine would help.

I'm trying to understand your code above. As far as I can see, in this example, you have two buttons:

  • button 1 on GPIO16 to turn on a light that is connected to GPIO13
  • button 2 on GPIO5 to turn on a relay on GPIO12

you also have a status led on GPIO2

I think that "Garage Door Contact" is a virtual/software sensor that you create as you don't have a physical endstop sensor.

In my situation, I have a physical endstop sensor on GPIO5 that tells me if the door is closed. I don't actually have button 1&2, everything is controlled via HA.

How would you suggest being able to override your "Garage Door Contact" with GPIO sensor values when the door is closed, or when the state machine says the door should be open/opening but the GPIO sensor says it's still closed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment