Garage Door Controller and Sensor
Let's make a dumb garage door smart! The usual consumer solution is the myQ controller, but I generally dislike being dependent on some company's cloud service staying online. Instead, I will DIY a solution using ESPHome and Home Assistant.
Requirements
Setting some ground rules for what I care about.
Must be able to tell if the door is opened or closed.
Can open/close the door.
Long-lasting set-and-forget.
No batteries.
No moving parts.
Impervious to the dirty environment of a garage.
No dependence on some company's cloud service staying online.
No subscription model.
Note: The way the myQ solution can tell if the door is open is by having you attach a sensor to the door itself, but that sensor is battery-powered. No good!
Design
Control
I will need to be able to tell my garage door to open/close. But how?
The Button Side
The dead simple way is to understand that all a button does is short two wires when pressed. If we disassemble the button on the wall, we can connect two more wires to that button and use our microcontroller to simulate a button press by shorting those wires.
But there's a catch. My wall button is not just a button like this:
Mine has additional functions including light control and a motion sensor:
Note: The main button cap was already removed when I took this photo.
So, I couldn't simply connect two wires to the two "W" and "R" wires coming from the wall since they are not the correct wires we need to short:
Instead, I will need to solder my wires to the button itself. Specifically these pins:
Solder from the back:
Route the new wires out the side, and we're done with modding the wall control!
The Microcontroller Side
For some reason, the wall button is powered by something close to 20 volts AC. The microcontroller (a Raspberry Pi Pico W) operates at 3.3 volts DC on its GPIO, so we can't connect the wires directly to the microcontroller. Instead, we need to use a relay. The microcontroller tells the relay when to short the wires while being isolated from the 20VAC power thanks to the relay.
Let's 3D print a case for the microcontroller:
The relay is on the bottom-left and the microcontroller is on the right, but let's get to what the thing at the top is next!
Sensing the Door
My go-to for this would be an accelerometer sensor that can detect when it's vertical (closed) or horizontal (opened). Such a sensor would need to attach to the door itself. Since the door moves, we wouldn't be able to (easily) power a door-mounted sensor via wire. The logical answer is to use a battery-powered sensor like the myQ does, but I refuse to be beholden to dealing with low batteries. How can we sense that the door is open without needing to attach a sensor to the door?
How about putting a sensor on the wall near the door? It could work, but how would we sense the door? The options are...
Use an Ultrasonic Distance Sensor to sense if something (the door) is nearby. But that doesn't have long-term reliability. The sensing element can be blocked by dirt over time or a spider could move into just the wrong place.
Use light-based sensors to do fundamentally the same thing as the ultrasonic sensor. It carries all the same issues plus one more: a bright sunny day could overload the sensor's ability to see its own light beacon.
A mechanical switch could be triggered by the door being in position or not. But anything with moving parts will wear down so that won't last forever.
Lastly, magnets! I can just place a magnet on the door and have a sensor on the wall to detect if a magnet is nearby. It is impervious to dirt, bugs, and light. The clear choice!
Let's go with this magnet sensor and magnet. But that sensor is tiny and bare, how can we mount it? How would we wire it?
As you can see, the sensor has 3 pins, so we would need to run a cable with at least 3 wires, and the cable would have to be relatively long to reach the microcontroller that I will install near the garage door wall button. Does anything fit the bill? How about a regular 3.5mm audio cable!
Let's also get this 3.5mm jack breakout board. We can then solder the sensor to it along with a pullup resistor like so:
3D print a case for it to position the sensor at the right spot:
Oh yeah, remember that third thing at the top in the microcontroller box? It's the jack for the other end of the audio cable!
There's a hiccup though, this angle turns out to be bad:
Not a big deal, just needed to use a wedge shape to give it an angle:
Final Hardware
Now all we need to do is mount everything else and wire it all up!
Closeup of my crude wiring:
The box on the wall:
You can see the two wires from the wall button going to the relay in the box, the audio cable plugging into the top, a microUSB cable to power the microcontroller, and hey, what's that bunch of wires coming out of the bottom of the box?
Not going to get into it for this article, but I figure I might as well have a temperature and humidity sensor for the garage. It just hangs out of the box to guarantee that the heat from the microcontroller will not impact the thermometer.
Before you say it, I didn't care to organize anything since the garage is already a mess. Sorry, not sorry. ๐
Software
As I said at the beginning, I will use ESPHome and Home Assistant. ESPHome is a microcontroller firmware that abstracts away boilerplate logic for most IoT needs and allows you to easily configure something like my garage controller using just a YAML config.
Here is the full basic YAML (scroll to the bottom to skip the boilerplate):
esphome:
name: garage-controller
rp2040:
board: rpipicow
framework:
# Required until https://github.com/platformio/platform-raspberrypi/pull/36 is merged
platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "<your key>"
ota:
password: "<your password>"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
substitutions:
name: "Garage"
garage: "Garage Door"
i2c:
- id: i2c_a
sda: GPIO20
scl: GPIO21
sensor:
- platform: sht3xd
temperature:
name: "${name} Temperature"
accuracy_decimals: 2
humidity:
name: "${name} Humidity"
accuracy_decimals: 2
address: 0x44
update_interval: 1s
switch:
- platform: gpio
pin:
number: GPIO22
id: garage_door_relay
name: "${garage} Remote"
icon: "mdi:garage"
on_turn_on:
- delay: 200ms
- switch.turn_off: garage_door_relay
binary_sensor:
- platform: gpio
pin:
number: GPIO8
id: garage_door_status
name: "${garage} Status"
device_class: garage_door
filters:
- delayed_on: 200ms
The switch:
and binary_sensor:
sections are all we needed to add to support toggling the garage door and know if the door is open. Simple!
Here they are in the Home Assistant UI:
And they're fully available for automation, such as automatically closing the door if it's been open for too long.
I can also see a timeline of when the door's been open!
Perfect, all I've ever wanted for my garage!