I am working on a garage door controller for my Liftmaster unit. I tried the ratgdo but unfortunately did not do what I need it to do for my use case.
I have the hardware installed, and the code done in ESPHome. I am now in the perfection stage, so wondering if this is possible. Some functionality I would like to add.
Add an input to ESPHome to start calibration.
When the user clicks it from HA, it will start with an open or closed position, and trigger the door to open or close, and start a timer to measure how long it will take to go from one position to the next.
This will be then saved in Flash so it is recoverable if device shuts down or restarts. The values will load at boot again.
This is then used as a reference to measure if the door is stuck opening or closing (if Liftmaster stopped mid function) as this is the only way I can think of.
Also used to set a pedestrian mode, so if the user wants to walk through, only trigger it for 50% of the total time (it is a dual gate, so you can walk between doors if they are half open).
So modify the code I am using to start a countdown from the activation start, to within 25%. If the state does not trigger, then it is a fault. Or trigger the state to stop the door like for pedestrian mode.
I used the code from here to begin with (thanks @SpikeyGG) and used some interface elements from ratgdo.
Interface looks like this. The values I am trying to calibrate are the ones under Configuration.
This is my code in case anyone is looking for something similar.
#Name the Project here to dentify the specific node
substitutions:
project: Gallery Door Controller
id: gallery_door_controller
friendly_name: Gallery Door Controller
#Include the board used
<<: !include common/esphome/esp32.yaml
#include common Wifi-OTA-API, etc
<<: !include common/common.yaml
# This is for the parameter configuration. These numbers
# are used in Node Red to detect if a door is stuck opening
# or closing if the timeouts based on these values occur
# The Pedestrian control will basically open the door slightly
# and stop it in the middle. No need to open it completely.
# I have a swing gate so this works.
number:
- platform: template
id: ${id}_open_delay
name: Open Delay
optimistic: true
initial_value: 10
min_value: 0
max_value: 100
step: 1
unit_of_measurement: "sec"
entity_category: config
mode: box
icon: mdi:timer-sand
restore_value: true
- platform: template
id: ${id}_close_delay
name: Close Delay
optimistic: true
initial_value: 10
min_value: 0
max_value: 100
step: 1
unit_of_measurement: "sec"
entity_category: config
mode: box
icon: mdi:timer-sand
restore_value: true
- platform: template
id: ${id}_open_pedestrian
name: Open to Pedastrian
optimistic: true
initial_value: 5
min_value: 0
max_value: 100
step: 1
unit_of_measurement: "sec"
entity_category: config
mode: box
icon: mdi:timer-sand
restore_value: true
output:
# Register the blue LED as a dimmable output ....
- platform: ledc
id: ${id}_blue_led
pin: GPIO5
inverted: true
# Define the stop switches in my liftmaster motor for open and closed.
# Reading of the SBC input from my wall switch to pass it through
# this module instead of directly to liftmaster
binary_sensor:
#Include the status
- !include common/binary_sensors/status.yaml
#add the inputs of the garage door
- platform: gpio
pin:
number: GPIO26
inverted: true
mode:
input: true
pullup: true
name: Door Open
id: ${id}_door_open
entity_category: "diagnostic"
- platform: gpio
pin:
number: GPIO27
inverted: true
mode:
input: true
pullup: true
name: Door Closed
id: ${id}_door_closed
entity_category: "diagnostic"
- platform: gpio
pin:
number: GPIO14
inverted: true
mode:
input: true
pullup: true
name: SBC Input
id: ${id}_sbc_input
entity_category: "diagnostic"
# All the relays definition for controlling loads or voltages to remote boards
switch:
#Include restart button
- !include common/switches/restart.yaml
- platform: gpio
name: 'Relay 1'
id: ${id}_relay1
pin: GPIO0
restore_mode: RESTORE_DEFAULT_OFF
- platform: gpio
name: 'Relay 2'
id: ${id}_relay2
pin: GPIO16
restore_mode: RESTORE_DEFAULT_OFF
- platform: gpio
name: 'Relay 3'
id: 'relay3'
pin: GPIO17
restore_mode: RESTORE_DEFAULT_OFF
- platform: gpio
name: 'Relay 4'
id: 'relay4'
pin: GPIO18
restore_mode: RESTORE_DEFAULT_OFF
- platform: gpio
name: 'Relay 5'
id: 'relay5'
pin: GPIO19
restore_mode: RESTORE_DEFAULT_OFF
- platform: gpio
name: 'SBC Control'
id: ${id}_sbc
pin: GPIO25
restore_mode: ALWAYS_OFF
on_turn_on:
- delay: 250ms
- switch.turn_off: ${id}_sbc
sensor:
#Include wifi signal sensor
- !include common/sensors/wifi_signal.yaml
- !include common/sensors/uptime.yaml
# Door status
text_sensor:
- platform: template
name: "Door Position Sensor"
id: ${id}_door_position_sensor
lambda: |-
if (id(${id}_door_closed).state) {
${id}_door_position_sensor->publish_state("Closed");
return{};
} else if (id(${id}_door_open).state) {
${id}_door_position_sensor->publish_state("Open");
return{};
}
# Ensure the global value is defined
globals:
- id: ${id}_performing_last_movement
type: boolean
restore_value: no
initial_value: 'false'
# Define the cover for HA with the states and controls
# Original code from https://community.home-assistant.io/t/looking-for-examples-of-custom-cover-from-esphome-io/177142/21?page=2
# Adapted to my use case
cover:
- platform: template
name: Door
id: ${id}_door
device_class: garage
lambda: |-
if (id(${id}_door_closed).state) //Door at closed endstop
{
if (id(${id}_door).current_operation == esphome::cover::COVER_OPERATION_OPENING) //We should be opening
{
if (!id(${id}_performing_last_movement)) //Make sure we don't trigger this logic twice otherwise it will do unwanted things
{
delay(1000); //Wait for door to stop in case reed is triggered too early
//Pulse the SBC button to trigger the motion
id(${id}_sbc).turn_on();
delay(500);
id(${id}_sbc).turn_off();
id(${id}_performing_last_movement) = true; //Set flag to indicate we madeknow where the door is
}
}
else if (id(${id}_door).current_operation == esphome::cover::COVER_OPERATION_CLOSING)
{
//We should be closing, so all is good
id(${id}_performing_last_movement) = false;
id(${id}_door).current_operation = esphome::cover::COVER_OPERATION_IDLE;
id(${id}_door).position = COVER_CLOSED;
id(${id}_door).publish_state();
${id}_door_position_sensor->publish_state("Closed");
return COVER_CLOSED;
}
else
{
//No operation in progress, just send state
id(${id}_performing_last_movement) = false;
if (!id(${id}_door).position == esphome::cover::COVER_CLOSED)
{
${id}_door_position_sensor->publish_state("Closed");
id(${id}_door).position = COVER_CLOSED;
id(${id}_door).publish_state();
return COVER_CLOSED;
}
}
}
else if (id(${id}_door_open).state) //Door at open endstop
{
if (id(${id}_door).current_operation == esphome::cover::COVER_OPERATION_CLOSING) //We should be closing
{
if (!id(${id}_performing_last_movement)) //Make sure we don't trigger this logic twice otherwise it will do unwanted things
{
delay(1000); //Wait for door to stop in case reed is triggered too early
//Pulse the SBC button to trigger the motion
id(${id}_sbc).turn_on();
delay(500);
id(${id}_sbc).turn_off();
id(${id}_performing_last_movement) = true; //Set flag to indicate we madeknow where the door is
}
}
else if (id(${id}_door).current_operation == esphome::cover::COVER_OPERATION_OPENING)
{
//We should be opening, so all is good
id(${id}_performing_last_movement) = false;
id(${id}_door).current_operation = esphome::cover::COVER_OPERATION_IDLE;
id(${id}_door).position = COVER_OPEN;
id(${id}_door).publish_state();
${id}_door_position_sensor->publish_state("Open");
return COVER_OPEN;
}
else //Door not at any endstop
{
//No operation in progress, just send state
id(${id}_performing_last_movement) = false;
if (id(${id}_door).position != esphome::cover::COVER_OPEN)
{
${id}_door_position_sensor->publish_state("Open");
id(${id}_door).position = COVER_OPEN;
id(${id}_door).publish_state();
return COVER_OPEN;
}
}
}
else
{
//The door is halfway open, so set it to OPEN
if (id(${id}_door).position != esphome::cover::COVER_OPEN)
{
${id}_door_position_sensor->publish_state("Open");
id(${id}_door).position = COVER_OPEN;
id(${id}_door).publish_state();
return COVER_OPEN;
}
}
return {};
open_action:
- lambda: |-
id(${id}_door).current_operation = esphome::cover::COVER_OPERATION_OPENING;
${id}_door_position_sensor->publish_state("Opening");
if (!id(${id}_door_open).state) {
//Pulse the SBC button to trigger the motion
id(${id}_sbc).turn_on();
delay(500);
id(${id}_sbc).turn_off();
if (id(${id}_door_closed).state) {
id(${id}_performing_last_movement) = true; //Set flag to indicate we know where the door is
}
}
close_action:
- lambda: |-
id(${id}_door).current_operation = esphome::cover::COVER_OPERATION_CLOSING;
${id}_door_position_sensor->publish_state("Closing");
if (!id(${id}_door_closed).state) {
//Pulse the SBC button to trigger the motion
id(${id}_sbc).turn_on();
delay(500);
id(${id}_sbc).turn_off();
if (id(${id}_door_open).state) {
id(${id}_performing_last_movement) = true; //Set flag to indicate we know where the door is
}
}
stop_action:
- lambda: |-
if (id(${id}_door).current_operation == esphome::cover::COVER_OPERATION_CLOSING || id(${id}_door).current_operation == esphome::cover::COVER_OPERATION_OPENING )
${id}_door_position_sensor->publish_state("Stopped");
{
id(${id}_door).current_operation = esphome::cover::COVER_OPERATION_IDLE;
//Stop the door if it is moving
id(${id}_performing_last_movement) = false;
//Pulse the SBC button to trigger the motion
id(${id}_sbc).turn_on();
delay(500);
id(${id}_sbc).turn_off();
}
# LED programmed to know if it is connected to wifi or if it’s also connected to HA.
# “Wifi only”: Steady Flashing
# "HA Connected" Fast Flashing
interval:
- interval: 1s
then:
if:
condition:
wifi.connected:
then:
- if:
condition:
api.connected:
then:
- output.turn_on: ${id}_blue_led
- delay: 250ms
- output.turn_off: ${id}_blue_led
- delay: 250ms
else:
- output.turn_on: ${id}_blue_led
- delay: 500ms
- output.turn_off: ${id}_blue_led
- delay: 500ms
else:
- output.turn_off: ${id}_blue_led
I can do all of it in NodeRed (my goto for automation). But wondering if this is something that I can implement inherently in the ESP itself so it is easier to manage in one place.
The hardware I have:
Ignore the other relays, they are for other loads unrelated to the garage door opener.
I have 3 digital inputs: Open, Closed, and SBC input (that’s the wall button).
One relay to control the SBC (SBC control)
I have another ESP32-Cam module that I have placed for a full automation.
This is the NodeRed flow today.
Someone presses the SBC button, ensure the lights are on so it is lit when camera takes a picture. Send it to my phone with a snapshot of the person in front of the door. I can open the door or ignore. If I accept, then SBC control triggers to open the door.
Response from phone received, or the request is ignored after 1min.