I installed 2 infrared barriers (1m long) on my overhead garage door opening that will detect cars, people, or an open SUV’s liftgate that would get damaged if the garage door were to close. A typical overhead garage door has a sensor low to the ground that would not detect a person standing in the opening if the legs were not in the way of the sensor.
For the project I used this Lilygo T-Relay board I just discovered. Both the barrier contacts (ir barriers have relays) and the magnetic floor mounted contact provide 12V to an optocoupler (based on PC817) board that is connected to the GPIO on the header.
The overhead garage door opener is disabled from closing the overhead garage door simply by opening the circuit to the included sensors. Relay 1 turns on breaking the circuit (this way if this system is powered down, the overhead garage door opener will keep working) between the sensor and the garage door opener.
Question: Everything works beautifully… BUT, I’d like to add a 1 or 2 second delay between the barrier being interrupted and Relay 1 being activated to break the sensor circuit. I want to see the barrier being blocked immediately, but if it doesn’t stay blocked for the threshold I pick, I do not want the relay to get triggered. I did see the delayed_on
option but that would also delay me seeing the barrier being triggered… I’ve used on_click
that allows timing of a click but it forces you to select a max too so it won’t work.
Suggestions?
The part I likely need to edit to add this is:
binary_sensor:
- platform: gpio
pin:
number: 23
inverted: true
mode:
input: true
pullup: true
name: "${friendly_devicename}: High Barrier"
id: high_barrier
on_press:
then:
- lambda: |-
if (!id(disable_barrier)) {
id(on_barrier_on).execute();
}
on_release:
then:
- lambda: |-
if (!id(disable_barrier)) {
id(on_barrier_off).execute();
}
- platform: gpio
pin:
number: 27
inverted: true
mode:
input: true
pullup: true
name: "${friendly_devicename}: Low Barrier"
id: low_barrier
on_press:
then:
- lambda: |-
if (!id(disable_barrier)) {
id(on_barrier_on).execute();
}
on_release:
then:
- lambda: |-
if (!id(disable_barrier)) {
id(on_barrier_off).execute();
}
All the code:
substitutions:
devicename: overhead-garage-door-barrier
devicename_no_dashes: overhead_garage_door_barrier
friendly_devicename: "Overhead Garage Door Barrier"
device_description: "Overhead Garage Door Barrier"
update_interval_s: "60s"
#Only reason not to set it much longer is for wifi troubleshooting ease
update_interval_wifi: "120s"
esphome:
name: ${devicename}
comment: ${device_description}
esp32:
board: esp32dev
framework:
type: arduino
wifi:
ssid: !secret iot_wifi_ssid
password: !secret iot_wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "${devicename}"
password: !secret iot_wifi_password
#Faster than DHCP. Also use if can't reach because of name change
manual_ip:
static_ip: 192.168.3.207
gateway: 192.168.3.1
subnet: 255.255.255.0
dns1: 192.168.1.25
dns2: 192.168.1.26
#Manually override what address to use to connect to the ESP.
#Defaults to auto-generated value. Example, if you have changed your
#static IP and want to flash OTA to the previously configured IP address.
use_address: 192.168.3.207
logger:
baud_rate: 0 #disabled
api:
ota:
web_server:
port: 80
include_internal: true
# Sync time with Home Assistant
time:
- platform: homeassistant
id: ha_time
globals:
- id: active_barrier
type: int
restore_value: no
initial_value: '3' # 0 Disabled; 1 Low Barrier; 2 High Barrier; 3 Both Barriers
- id: disable_barrier
type: bool
restore_value: yes
initial_value: 'true' # When true, the system has no effect on the door operation
text_sensor:
- platform: wifi_info
ip_address:
name: "${friendly_devicename}: IP"
icon: "mdi:ip-outline"
update_interval: ${update_interval_wifi}
ssid:
name: "${friendly_devicename}: SSID"
icon: "mdi:wifi-settings"
update_interval: ${update_interval_wifi}
bssid:
name: "${friendly_devicename}: BSSID"
icon: "mdi:wifi-settings"
update_interval: ${update_interval_wifi}
mac_address:
name: "${friendly_devicename}: MAC"
icon: "mdi:network-outline"
scan_results:
name: "${friendly_devicename}: Wifi Scan"
icon: "mdi:wifi-refresh"
disabled_by_default: true
sensor:
- platform: wifi_signal
name: "${friendly_devicename}: WiFi Signal"
update_interval: ${update_interval_wifi}
device_class: signal_strength
binary_sensor:
- platform: gpio
pin:
number: 23
inverted: true
mode:
input: true
pullup: true
name: "${friendly_devicename}: High Barrier"
id: high_barrier
on_press:
then:
- lambda: |-
if (!id(disable_barrier)) {
id(on_barrier_on).execute();
}
on_release:
then:
- lambda: |-
if (!id(disable_barrier)) {
id(on_barrier_off).execute();
}
- platform: gpio
pin:
number: 27
inverted: true
mode:
input: true
pullup: true
name: "${friendly_devicename}: Low Barrier"
id: low_barrier
on_press:
then:
- lambda: |-
if (!id(disable_barrier)) {
id(on_barrier_on).execute();
}
on_release:
then:
- lambda: |-
if (!id(disable_barrier)) {
id(on_barrier_off).execute();
}
- platform: gpio
pin:
number: 22
mode:
input: true
pullup: true
name: "${friendly_devicename}: Door Contact"
id: door_contact
device_class: garage_door
on_press:
then:
- output.turn_on: onboard_led
on_release:
then:
- output.turn_off: onboard_led
- platform: gpio
pin:
number: 26
inverted: true
mode:
input: true
pullup: true
name: "${friendly_devicename}: Spare Contact"
id: spare_contact
on_press:
then:
- output.turn_on: onboard_led
on_release:
then:
- output.turn_off: onboard_led
switch:
- platform: restart
name: "${friendly_devicename}: Restart"
# COM-NC closes safety sensor circuit so GD Opener works normally. To disable door closing, relay is turned on thus breaking circuit.
# GD Opener will just see it as a bad sensor.
- platform: gpio
pin:
number: 21
name: "${friendly_devicename}: Disable Door"
id: relay1
# Sensors are wired through COM-NC of relay. To disable door, turn relay on so door sensors are disconnected disabling the door.
- platform: gpio
pin:
number: 19
inverted: true # To save relay and energy, turning off barrier will turn on relay. Inverting to make it more intuitive.
name: "${friendly_devicename}: High Barrier Power"
id: relay2
restore_mode: RESTORE_DEFAULT_ON
on_turn_on:
then:
- script.execute: set_active_barrier
on_turn_off:
then:
- script.execute: set_active_barrier
# Sensors are wired through COM-NC of relay. To disable door, turn relay on so door sensors are disconnected disabling the door.
- platform: gpio
pin:
number: 18
inverted: true # To save relay and energy, turning off barrier will turn on relay. Inverting to make it more intuitive.
name: "${friendly_devicename}: Low Barrier Power"
id: relay3
restore_mode: RESTORE_DEFAULT_ON
on_turn_on:
then:
- script.execute: set_active_barrier
on_turn_off:
then:
- script.execute: set_active_barrier
- platform: gpio
pin:
number: 5
name: "${friendly_devicename}: Spare Relay"
id: relay4
- platform: template
id: disable_barrier_ha
name: "${friendly_devicename}: Disable Barrier"
optimistic: true
turn_on_action:
- globals.set:
id: disable_barrier
value: 'true'
turn_off_action:
- globals.set:
id: disable_barrier
value: 'false'
button:
- platform: safe_mode
name: "${friendly_devicename}: Restart (Safe Mode)"
#deep_sleep:
# id: ${devicename_no_dashes}_deep_sleep
# sleep_duration: 30min
#status_led:
# pin:
# number: 2
# inverted: false
output:
- id: onboard_led
platform: gpio
pin: 25
inverted: true
script:
# 0 Disabled; 1 Low Barrier (relay3); 2 High Barrier (relay2); 3 Both Barriers
- id: set_active_barrier
then:
- lambda: |-
if(id(relay2).state && id(relay3).state) {
id(active_barrier) = 3;
}
if(id(relay2).state && !id(relay3).state) {
id(active_barrier) = 2;
}
if(!id(relay2).state && id(relay3).state) {
id(active_barrier) = 1;
}
if(!id(relay2).state && !id(relay3).state) {
id(active_barrier) = 0;
}
ESP_LOGD("DEBUG", "Active Barrier: %d", int(id(active_barrier)));
# Disabled barriers can't be triggered as they have no power so state can be ignored
- id: on_barrier_on
then:
# 0 Disabled; 1 Low Barrier (relay3); 2 High Barrier (relay2); 3 Both Barriers
- lambda: |-
if(id(active_barrier) == 3) {
if(id(low_barrier).state || id(high_barrier).state) {
id(relay1).turn_on();
id(onboard_led).turn_on();
}
};
if(id(active_barrier) == 2) {
if(id(high_barrier).state) {
id(relay1).turn_on();
id(onboard_led).turn_on();
}
};
if(id(active_barrier) == 1) {
if(id(low_barrier).state) {
id(relay1).turn_on();
id(onboard_led).turn_on();
}
};
if(id(active_barrier) == 0) {
ESP_LOGD("DEBUG", "Impossible condition as both barriers are disabled.");
};
- id: on_barrier_off
then:
# 0 Disabled; 1 Low Barrier (relay3); 2 High Barrier (relay2); 3 Both Barriers
- lambda: |-
if(id(active_barrier) == 3) {
if(!id(low_barrier).state && !id(high_barrier).state) {
id(relay1).turn_off();
id(onboard_led).turn_off();
}
};
if(id(active_barrier) == 2) {
if(!id(high_barrier).state) {
id(relay1).turn_off();
id(onboard_led).turn_off();
}
};
if(id(active_barrier) == 1) {
if(!id(low_barrier).state) {
id(relay1).turn_off();
id(onboard_led).turn_off();
}
};
if(id(active_barrier) == 0) {
ESP_LOGD("DEBUG", "Impossible condition as both barriers are disabled.");
};