Custom Smart Garage Door Opener
Overview
Cloud-based garage openers like MyQ add latency, subscription fees, and a hard dependency on a third-party server. I wanted something fully local: reliable, private, and tightly integrated with my existing Home Assistant setup.
I built the opener around an ESP8266 (NodeMCU v2) running ESPHome, with a relay wired directly into a standard garage remote. A Zigbee door sensor tracks the physical state of the door. Everything runs locally over Wi-Fi, with no cloud, no subscription, and no dependency on anything outside your own network.
Hardware
- › ESP8266 NodeMCU v2: the microcontroller running ESPHome firmware, connected to Wi-Fi and the Home Assistant API
- › Relay module: wired to GPIO pin D7; simulates a physical button press by briefly closing the circuit inside the garage remote
- › Existing garage remote: modified to accept relay control; no need to replace the original opener unit
- › Zigbee door sensor: provides accurate open/closed state via Home Assistant, allowing the ESPHome cover entity to reflect true door position rather than relying on optimistic state
How It Works
ESPHome exposes two key entities to Home Assistant: a GPIO switch on D7 and a cover template that wraps them into a proper garage door entity.
Relay Pulse
When Home Assistant triggers an open or close action, ESPHome turns the relay on, waits 100 ms, then turns it off. This 100 ms pulse mimics a human pressing the garage remote button.
State from Zigbee
ESPHome pulls the Zigbee door sensor state directly from Home Assistant using the homeassistant binary sensor platform. The cover template reads this state to report COVER_OPEN or COVER_CLOSED accurately.
Local API + OTA
Communication happens over the encrypted Home Assistant API on the local network. OTA updates let you push new firmware wirelessly without ever unplugging the device.
ESPHome Configuration
The full config is a single opener.yaml file. The cover template handles open and close identically: one relay pulse toggles the door either way, since the remote button is stateless.
switch:
- platform: gpio
pin: D7
name: "Garage Door Button"
id: garage_door_button
cover:
- platform: template
name: "Garage Door"
device_class: garage
lambda: |-
if (id(zigbee_garage_door_sensor).state) {
return COVER_OPEN;
} else {
return COVER_CLOSED;
}
open_action:
- switch.turn_on: garage_door_button
- delay: 0.1s
- switch.turn_off: garage_door_button
close_action:
- switch.turn_on: garage_door_button
- delay: 0.1s
- switch.turn_off: garage_door_button
optimistic: false Demo
Full Build Tutorial
Wiring, ESPHome setup, and Home Assistant integration from scratch.