Automated Garage Door Remote

A device to help me be certain that I closed the garage door on my way out of the house – sync’ed with Home Assistant!
Author

Gaelen Guzman

Published

May 1, 2025

Overview

My wife and I just moved into a new apartment and we now have a surprising new responsibility: a garage. I imagine that this isn’t a problem for most people, but I’ve struggled to close the door a few times as I drive away… and now I have a new-found anxiety that I’ve left the door open a lot of the time.

I thought that maybe I could use one of my ESP32s as a sensor to report the closed/open state of the door so I can check in the middle of the night without getting up. I figured that while I was at it, I may as well automate it such that the door can close itself if left open for too long (Update: after a few months of the door closing itself chaotically on Madeleine, I’ve decided this was a bad move – it now just sends a push notification to let me know if the door has been open too long!).

The original script I wrote to control the door was in pure C++, and was pretty janky. It had an internally-defined timer set to 10 minutes, such that if the door was open for >10 minutes it would close itself. It accepted an input_number from a slider input in Home Assistant which allowed me to manually change the auto-close time, but it would revert to 10 minutes every time the door closed. After a while this got pretty annoying!

I was recently able to sit down and set the whole thing up in ESPhome – something I didn’t even know about when I wrote the first iteration. It’s insane how much easier it was!

Materials & Components

  • ESP32-C3 super mini
  • A cheap garage door remote (make sure it matches signal type of the opener!)
  • A Hall effect sensor
  • A spare USB data cable
  • A little plastic box to house the device and mount it to the wall

Assembly

As usual, I forgot to take very many pictures while this was a work in progress…

I started this project by trying to find a way to activate the remote with the ESP32. At first I tried using some input pins on the remote PCB (see the picture below), but I couldn’t get the signal to work properly with these – I think because the voltage going into the “CLK” pinout wasn’t correct.

My first testing board – not the final wiring schematic

My first testing board – not the final wiring schematic

After some testing with a breadboard, I found that the most reliable way to do this was to add a transistor that could close the activation button using a 3.3 V GPIO output signal. Interestingly, I also noticed that this transistor needed an additional load LED going to the ESP32 ground in order to work – which I think suggests that the button typically uses a pull-down resistor?

My next step was to start testing the WiFi and MQTT connections so that I could get the ESP32 to publish the door state to my HomeAssistant setup – and to subscribe to a command topic which would allow me to open and close the door on command. I did a lot of testing with the battery removed from the door remote so I didn’t open and close the door 10,000x – instead, I added an extra external button so I could manually trigger the ESP32 to detect an open/close signal. I used the ESP32’s on-board RGB LED as a reporter signal of the WiFi/MQTT connection and the trigger signal (note the bright red signal when I push the button in the video below).

An external button triggers the ESP32 to update an “open”/“closed” boolean which HomeAssistant reads as “Unlocked”/“Locked”. This also works in reverse: triggering a state change in HomeAssistant updates the state onboard the ESP32. However, without an external sensor, the ESP32 has no way to record the real state of the door.

An external button triggers the ESP32 to update an “open”/“closed” boolean which HomeAssistant reads as “Unlocked”/“Locked”. This also works in reverse: triggering a state change in HomeAssistant updates the state onboard the ESP32. However, without an external sensor, the ESP32 has no way to record the real state of the door.

Adding a Hall effect sensor allows me to detect the true state of the door. I wanted this sensor to be on a long cord so I’d have options on where to mount it – cue me destroying a spare USB-C cable and attaching 3-pin connectors to each end.

The final ESP32/door remote setup, featuring the can used to build the mount.

The final ESP32/door remote setup, featuring the can used to build the mount.

Definitely not my best work, and it was up on the wall like this for an embarrassingly long time.

Definitely not my best work, and it was up on the wall like this for an embarrassingly long time.

A little cleaner! Now the board isn’t being suspended from extremely delicate connections that kept breaking! The slightly opaque box also makes the status light look pretty good.

A little cleaner! Now the board isn’t being suspended from extremely delicate connections that kept breaking! The slightly opaque box also makes the status light look pretty good.

I next needed to craft a stable mount for this sensor sit close enough to a magnet on the garage door. I thought very carefully about my options and decided that an aluminum can would be the perfect source material for this mount. I got out my tin snips, a metal ruler, and some super adhesive mounting tape to build a little mount. I then drilled some holes in order to screw the Hall effect sensor to the mount and fixed the whole thing to the wall close enough to my magnet to be triggered when the door is closed.

For a good few months I left this little board dangling from the connection cable leading to the Hall effect sensor – a truly janky look. I finally took the time to squeeze it into a little plastic box that kind of obscures the jank and now it looks slightly less like a IED hooked up to the door.

Code

Update, as I wrote above, this code section is now out of date! This project is my first which has a real connection with the real world. I need to be confident that this little device won’t end up spazzing out and opening the garage door while we’re away.

My ideas for this include: using a GeoFence to disable it when I’m away for some amount of time (i.e. reporting my location to HomeAssistant, and putting it into a hard off state) and not actually giving it any of its own automation ability (I had originally wanted it to automatically trigger the door to close after some amount of time, instead I might have it send a push notification to me via HomeAssistant).

I had a fun round of debugging when the sensor got dislodged and the remote got activated every 2 seconds for the 10+ minutes it took for my wife to come down and unplug it following the first time I left the house after installing the device… The solutions were to find a better spot to mount the sensor and to add a 15 second delay after the trigger function to give the door sufficient time to actually close.

New ESPhome yaml: My original iteration was truly too bad to include here. But I’m happy enough with my final product that I can show it off here!


esphome:
  name: garagedoorcontroller
  friendly_name: GarageDoorController

esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: !secret garagedoor_api

ota:
  - platform: esphome
    password: !secret garagedoor_ota

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  manual_ip:
    static_ip: !secret garagedoor_ip
    gateway: !secret gateway
    subnet: !secret subnet

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: !secret garagedoor_ap_ssid
    password: !secret garagedoor_ap_password

captive_portal:
  
# Hall effect sensor, reports whether magnet on door is engaged
binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO5
      # inverted: True
    name: "Garage Door Sensor"
    id: garage_door_sensor
    device_class: garage_door
    on_state:
      then:
        - if:
            condition:
              binary_sensor.is_on: garage_door_sensor
            then:
              - light.turn_on:
                  id: status_light
                  red: 10%
                  green: 0%
                  blue: 0%
            else:
              - light.turn_off: status_light

# Status light, only illuminated if the door is open
light:
  - platform: neopixelbus
    type: RGB
    pin: GPIO10
    variant: ws2812x
    num_leds: 1
    id: status_light
    name: "Garage Status Light"
    internal: True

# The relay pin that triggers the door clicker
output:
  - platform: gpio
    pin: GPIO0
    id: garage_relay

# As recommended by my friend Britt, a cover is definitely the way to go for this door
  # In HA, this allows for an "open", "close", and "stop" command -- allowing the door to be part-way open
  # After triggering a change, the Hall effect sensor is queried and returns its state to HA to report the state of the door
cover:
  - platform: template
    name: "Garage Door"
    id: garage_door
    open_action:
      - output.turn_on: garage_relay
      - light.turn_on:
          id: status_light
          red: 0%
          green: 0%
          blue: 100%
      - delay: 500ms
      - light.turn_off:
          id: status_light
      - output.turn_off: garage_relay
    close_action:
      - output.turn_on: garage_relay
      - light.turn_on:
          id: status_light
          red: 0%
          green: 0%
          blue: 100%
      - delay: 500ms
      - light.turn_off:
          id: status_light
      - output.turn_off: garage_relay
    stop_action:
      - output.turn_on: garage_relay
      - light.turn_on:
          id: status_light
          red: 0%
          green: 0%
          blue: 100%
      - delay: 500ms
      - light.turn_off:
          id: status_light
      - output.turn_off: garage_relay
    optimistic: False
    assumed_state: False
    lambda: |-
      if (id(garage_door_sensor).state) {
        return COVER_OPEN;
      } else {
        return COVER_CLOSED;
      }

I do feel like the arcane magic of yaml is still very mysterious to me – like it seems like there’s no obvious resources where you can see all the possible options for every type of entity… I have to admit that I had to ask ChatGPT to help me build the right settings for things like the cover, where I just couldn’t find clear instructions online.

Home Assistant integration

After deciding that the device shouldn’t have the authority to close the door on its own, I set up an automation in Home Assistant that logs how long the door has been in the “open” state and sends a push notification to my phone. And from the HA app, I can trigger the door to close! No more input_number that you have to adjust every time you want the door open!