A tiny Wi-Fi garage door opener built on an ESP32. Tap a button on your phone to open the door and check whether it's open or closed. Your existing wall button keeps working exactly as before.
The whole thing costs about £25–35, takes an afternoon to build, and stays entirely on your local network — nothing is exposed to the internet.
Your garage opener's wall button just shorts two low-voltage wires together for a moment. This project wires a relay in parallel with that button, so when the ESP32 pulses the relay it's electrically identical to a button press. A magnetic reed sensor on the door tells you whether it's open or closed.
The ESP32 runs a small HTTP server on your Wi-Fi. Your phone sends it an authenticated request (via an iOS Shortcut or an Android app), the relay fires, the door moves.
Phone (Shortcut) --Wi-Fi--> ESP32 --> Relay --> Garage opener button terminals
| ^
reed sensor (existing wall button stays wired here too)
The API is deliberately minimal:
| Method & path | Auth | Does |
|---|---|---|
POST /trigger |
Bearer token | Pulses the relay for ~500ms (one door press) |
GET /status |
none | Returns `{"door":"open |
GET / |
none | Plain-text health page for a browser |
The relay is driven inactive on boot and auto-released after the pulse, so a crash, reboot, or stuck request can never hold your garage button down.
garage_esp32.ino Firmware (Arduino core for ESP32)
case/ 3D-printable enclosure (STL)
base.stl Box that holds the ESP32 + relay
lid.stl Snap-on lid
backing_plate.stl Wall mount
LICENSE MIT
Prices are UK/GBP. If you already own a USB charger and cable and skip the enclosure, you can do this for well under £15.
| Item | What to get | ~£ | Notes |
|---|---|---|---|
| ESP32 board | ESP32-WROOM-32 DevKit, 38-pin, USB-C, pre-soldered | 7–11 | A 2–3 pack gives you a spare. HiLetgo / ELEGOO / AZDelivery are fine. |
| USB power | Any 5V phone charger (1A+) + a data USB-C cable | 0–5 | Powers the ESP32. Never wire the ESP32 to mains directly — it's a 5V device. |
| Relay module | 1-channel 3V/3.3V, low-level trigger | 3–4 | Powered and triggered from the ESP32's 3.3V pin. Avoid 5V-only boards — they often won't switch from 3.3V. |
| Reed door sensor | Wired magnetic reed switch, NC (normally closed) | 4 | For open/closed status. Search "wired magnetic reed switch NC door sensor". |
| Jumper wires | Female-to-female Dupont, 20cm multipack | 3 | You'll use 5+. |
| Two-core wire | Bell wire / alarm cable ~0.5mm² | 4 | For the relay-to-opener run. Carries a signal, not power. |
| Item | What to get | ~£ |
|---|---|---|
| Enclosure | Print the files in case/, or an off-the-shelf ~100mm ABS box |
0–5 |
- Pre-soldered pins — confirm the ESP32 listing says the header pins are already soldered, so you can plug jumpers straight in.
- NC sensor — the status logic assumes a normally-closed reed sensor. If
you end up with an NO one, you don't rewire — just flip
INVERT_SENSORin the firmware (see below).
ESP32 → relay module:
| ESP32 pin | Relay pin |
|---|---|
| 3.3V | VCC |
| GND | GND |
| GPIO23 | IN |
Assumes a 3V/3.3V relay board. If you use a 5V-coil board instead, wire VCC to the ESP32's 5V (VIN) pin — but a 3.3V-triggered board is recommended.
Relay → garage opener: use the COM and NO output terminals so the circuit is open by default and only closes on a pulse. Wire them to the same two low-voltage terminals your wall button uses. Polarity doesn't matter.
Relay COM -> one garage button terminal
Relay NO -> other garage button terminal
Your existing wall button stays connected — the relay sits in parallel with it on the same two terminals. Either one triggers the door; neither interferes with the other.
Reed sensor → ESP32: one wire to GPIO22, the other to GND (polarity doesn't matter). Mount the two halves so they're aligned/touching when the door is closed.
Full wiring diagram
ESP32 WROOM-32 DevKit
┌───────────────────────────┐
USB-C <──────┤ USB-C (5V from USB plug) │
│ 3.3V ─────────────┐ │
│ GND ──────────┐ │ │
│ GPIO23 ───┐ │ │ │
│ GPIO22 ─┐ │ │ │ │
│ GND ──┐ │ │ │ │ │
└────────┼─┼─┼───┼───┼───────┘
│ │ │ │ │
reed sensor │ │ │ │ │
┌──────┐ │ │ │ │ │
│ magnet on door │ │ │ │ │
│ switch on frame│ │ │ │ │
│ ├─────────┘ │ │ │ │
│ ├───────────┘ │ │ │
└──────┘ │ │ │
┌───┴───┴───┴────┐
│ IN GND VCC │ Relay module
│ │
│ COM NO NC │
└───┬────┬───────┘
│ │ ┌─────────────────────┐
│ └──────┤ Garage opener │
└───────────┤ button terminals A/B │
Existing wall button ────────────┤ (same terminals A/B) │
(leave connected!) ─────────────┤ │
└─────────────────────┘
You flash the ESP32 once from a computer over USB-C. After that it runs on its own.
- Install the Arduino IDE — https://www.arduino.cc/en/software.
- Add ESP32 board support. In Settings → Additional Boards Manager URLs
add:
Then Tools → Board → Boards Manager, search esp32, and install "esp32 by Espressif Systems".
https://espressif.github.io/arduino-esp32/package_esp32_index.json - Open
garage_esp32.inoand edit the values at the top:WIFI_SSID/WIFI_PASSWORD— your Wi-Fi.AUTH_TOKEN— a long random secret. Generate one withopenssl rand -hex 24and keep it private.- Leave
HAS_SENSOR = trueif you're fitting the reed sensor. - (Optional) set
USE_STATIC_IP = trueand fill in addresses for a fixed IP, or leave it and reserve the IP in your router later.
- Select the board & port. Plug in the ESP32, choose
Tools → Board → ESP32 Arduino → "ESP32 Dev Module", then pick the new port
under Tools → Port (
/dev/cu.usbserial-…on Mac,COM3on Windows). No port showing? Install the USB driver for your board's chip — CP2102 (Silicon Labs CP210x) or CH340. - Upload. Click the upload arrow. If it stalls at "Connecting…", hold the board's BOOT button for a couple of seconds, then release.
- Find its IP. Open Tools → Serial Monitor at 115200 baud and press
the board's EN/RST button. You'll see:
Write this down — your phone shortcuts need it. Visit
Connected. IP address: 192.168.1.xxhttp://THAT_IP/in a browser on the same Wi-Fi to confirm the server is up.
Mount the switch body to the fixed frame and the magnet to the moving door, within ~15–20mm of each other when the door is fully closed.
Then test:
- With the door closed, visit
http://YOUR_ESP32_IP/status→ should return{"door":"closed", ...}. - Open the door and refresh → should flip to
"open". - Reads backwards? Set
INVERT_SENSOR = truein the firmware and re-flash. (This also handles an NO sensor with no rewiring.)
Open Garage (the trigger):
- Shortcuts → + → add Get Contents of URL.
- URL
http://YOUR_ESP32_IP/trigger, tap Show More, set Method: POST. - Add a header: key
Authorization, valueBearer YOUR_TOKEN(the same token from the firmware — mind the wordBearerand the space). - Name it "Open Garage", then Share → Add to Home Screen for a one-tap button, or trigger it with "Hey Siri, Open Garage".
Garage Status (read-only, no token):
- Get Contents of URL →
http://YOUR_ESP32_IP/status(GET). - Get Dictionary Value → key
door. - Show Result. Tapping it shows "open" or "closed".
Want a single shortcut that checks status and asks for confirmation before closing? It's a few extra steps around the two above — open an issue if you'd like a worked example.
Use the free HTTP Shortcuts app (or Tasker):
- Trigger: POST to
http://YOUR_ESP32_IP/triggerwith headerAuthorization: Bearer YOUR_TOKEN. - Status: GET
http://YOUR_ESP32_IP/status, display thedoorvalue. - Add either as a home-screen widget.
A router reboot can hand the ESP32 a new IP and break your shortcuts. Pick one:
- DHCP reservation (easiest): in your router admin, find the ESP32 and reserve/bind its current IP to its MAC address. No firmware change.
- Static IP: set
USE_STATIC_IP = truein the firmware with addresses that match your network (outside the DHCP range) and re-flash.
- Test the relay before wiring it to the opener. Power the ESP32 and hit
/triggerwhile listening — you should hear one click and release. Confirm it's a single momentary pulse. - Only then connect COM/NO to the opener terminals.
- Test the door from a safe spot where you can see it move and stop.
- Confirm your existing wall button still works — it should, unchanged.
- Never defeat your opener's built-in safety features (auto-reverse, photo-eye sensors). Keep them all intact.
| Symptom | Fix |
|---|---|
| Relay clicks but door doesn't move | Check COM/NO are on the same two opener terminals the wall button uses. |
| Relay never clicks, or clicks inverted | Flip RELAY_ACTIVE_LOW in the firmware and re-flash. |
| Status reads backwards | Flip INVERT_SENSOR (or confirm the sensor is NC) and re-flash. |
| Phone shortcut does nothing | Phone must be on your home Wi-Fi (not mobile data / guest network); check the IP is current. |
401 unauthorised |
Token mismatch — the header must be exactly Bearer <your token>. |
| No serial port when flashing | Install the CP2102 or CH340 USB driver for your board. |
This setup is local-only by design, which is the safest default. Do not port-forward the ESP32 to the internet. To reach it remotely, put both your phone and a small always-on device at home on a Tailscale network — the same shortcuts then work from anywhere — or broker the connection through Home Assistant.
/triggerrequires a bearer token;/statusand/are read-only and open.- Traffic is plain HTTP on your LAN — fine for a local-only device, but don't expose it publicly.
- Keep your
AUTH_TOKENout of screenshots and public forks.
Issues and pull requests are welcome — improvements to the firmware, the case, or these instructions especially. If something in the setup tripped you up, that's worth an issue too.
MIT.