I installed 2 infrared barriers on the garage opening. The low barrier detects cars / people that may happen to not block the overhead garage door’s sensor and the high barrier detects lift gate doors of SUVs that would otherwise be damaged if the overhead garage door was operated while open. The operation principle is simple… when the barriers are blocked, the default sensor is disconnected stopping the overhead garage door from closing (it will still open for obvious safety reasons, but will refuse to close or if closing, it will revert and open). In other words I have NOT made this any less secure.
While I was at it, I added a reed sensor (dry contact) to the door (screwed into the floor) so I can detect whether it is open or closed. This is way better than the zwave sensor on the door as it is faster and more reliable. I was getting really frustrated by the zwave sensor battery replacements, and the delays & failures in having lights and parking lasers turn on when the door was opening. Since I installed this, it is immediate and reliable.
I can tell the system to ignore the barriers but still report their state. I can turn power off to any one barrier and therefore ignore its state. I can manually disable the door sensor so that nobody can operate the door (we can open/close it from any spot on the globe so this opens up the chances that something is in the way as the default sensor is low to the ground (mostly meant not to squish kids… by law). And of course I can just turn it all off.
All connections are done using the COM/NC connections on the relay. Why? The power ones would be on 100% of the time… so I inverted their operation. When at rest the barriers are powered. If for any reason I want to turn one off, the relay will turn on. Saves power and the relay this way.
The relay that disables the door sensor is connected the same way… for the same reason and also to allow unplugging the system in case things were to stop working.
The ethernet wiring is not ethernet… I assigned a function/purpose to each one of the 8 wires so to make all the connections all I needed to do was wire everything in parallel. It therefore does not matter how the barriers are connected to the white splitters on the wall or to the control box.
This is the YAML I wrote… some of the stuff that looks ‘weird’ is me trying to restore settings when stuff reboots. It works, but I am not certain there wasn’t a simpler way of doing it. I have not tested some changes I made last night so there may be bugs… will update YAML if I find any.
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}
# Automatically add the mac address to the name
# so you can use a single firmware for all devices
# name_add_mac_suffix: true
on_boot:
then:
- lambda: |-
id(infrared_barrier_ha).publish_state(id(infrared_barrier));
id(disable_door_closure_ha).publish_state(id(disable_door_closure));
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: infrared_barrier
type: bool
restore_value: yes
initial_value: 'true' # When false, the system has no effect on the door operation
- id: disable_door_closure
type: bool
restore_value: yes
initial_value: 'false' # When false, the the door sensor relay (#1) is on and disables the sensor
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
device_class: motion
on_press:
then:
- lambda: |-
if (id(infrared_barrier)) {
id(delayed_barrier_blocked).execute();
}
on_release:
then:
- lambda: |-
if (id(infrared_barrier)) {
if (id(delayed_barrier_blocked).is_running()) {
ESP_LOGI("main", "Stopping disable door relay trigger timer!");
id(delayed_barrier_blocked).stop();
}
id(barrier_clear).execute();
}
#Just shows whether door sensor is disabled or not. "On" = disabled.
- platform: template
name: "${friendly_devicename}: Door Sensor Override"
id: door_sensor_override
lambda: !lambda |-
if (id(relay1).state) {
return true;
} else {
return false;
}
- platform: gpio
pin:
number: 27
inverted: true
mode:
input: true
pullup: true
name: "${friendly_devicename}: Low Barrier"
id: low_barrier
device_class: motion
on_press:
then:
- lambda: |-
if (id(infrared_barrier)) {
id(delayed_barrier_blocked).execute();
}
on_release:
then:
- lambda: |-
if (id(infrared_barrier)) {
if (id(delayed_barrier_blocked).is_running()) {
ESP_LOGI("main", "Stopping disable door relay trigger timer!");
id(delayed_barrier_blocked).stop();
}
id(barrier_clear).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
id: relay1
internal: true #Do not allow direct control of relay1
- platform: template
name: "${friendly_devicename}: Disable Door Closure"
id: disable_door_closure_ha
optimistic: true
turn_on_action:
- globals.set:
id: disable_door_closure
value: 'true'
- script.execute: disable_sensor_on
turn_off_action:
- globals.set:
id: disable_door_closure
value: 'false'
- script.execute: disable_sensor_off
# 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: infrared_barrier_ha
name: "${friendly_devicename}"
optimistic: true
turn_on_action:
- globals.set:
id: infrared_barrier
value: 'true'
turn_off_action:
- globals.set:
id: infrared_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: 25
# 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: barrier_blocked
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: barrier_clear
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.");
};
- id: delayed_barrier_blocked
then:
- delay: 2000ms
- script.execute: barrier_blocked
- id: disable_sensor_on
then:
- lambda: |-
id(relay1).turn_on();
- id: disable_sensor_off
then:
- lambda: |-
id(relay1).turn_off();