The ESP8266 micro-controller makes a great Internet-of-Things device. It’s cheap, easy to use (especially via the Arduino IDE), and has been quite reliable for me. Here’s a description of how I used one to allow remote control of my garage door via the Internet.


My primary motivation for create a WiFi/IOT garage door opener was that I store my bicycle in the garage, but don’t keep a garage door remote in my backpack, so often had to go back and get the remote after getting my bike out of the house. However, I always carry my phone, so if I could use that instead, I would no longer have a problem controlling the garage door. Since the project worked so well, I installed it on my other garage door, which was lucky since I purchased a new car that didn’t have an integrated garage door remote, so I now use my phone to close/open the door every time I leave or come home.

Here’s how the project looks installed:

Project installed

As you can tell, I used a NodeMCU ESP8266 board for the web interface, created a custom PCB to mount that board to the wall and provide connectors for the other components, used a relay board to interface with the existing garage door opener, and added ultrasound sensors to enable reporting the position of the door.

Project Files

You can find all source code and design files for this project in my github repo.

ESP8266 Software

The ESP8266 supports a few different software stacks. One of which is the Arduino IDE. I chose this because it’s extremely simple to use, works similarly across a variety of hardware, and the ESP8266 board support comes with a slew of simple libraries allowing control over the WiFi configuration, management of filesystems in flash, and serving a website including pretty easy form/POST handling.

The ESP8266 hosts a website with just one page that contains buttons to activate each connected garage door; the software supports either 1 or 2 doors. Each button is a simple HTML form that HTTP POSTs back to the server to activate a door, which then re-directs the user back to the same page in case they want to activate the door again later. Each door is controlled using a single GPIO output signal that connects to a relay, which simply shorts the wires that are otherwise connected to the “manual” push button that controls the door. This method of interfacing with the door controller minimizes the possibility of interfering with the existing electronics in any way; the motor system can’t tell whether a human or a device “pressed the button”.

Web User

The software has a few features beyond this basic operation:

WiFi Setup

WiFi configuration is stored in a file in a flash-based filesystem. If this file is missing, the ESP8266 will act as a WiFi base station with obvious ESSID and known password. This allows the user to connect using a web browser and provide credentials for the WiFi network that the device should connect to. Once entered, the device will connect to the specified network, at which point the user can confirm the settings and save them to flash. The user can clear the settings by holding a push button for 10 seconds, which can be useful when moving the device to another WiFi network, or for testing the configuration setup mechanism. The implementation is extremely basic at present; just enough to make the system work, but not pretty or flashy.

Door State Sensing

I figured that a WiFi door remote should report the position of the door as well as trigger it to open and close. I didn’t want to hook into the existing motor limit switches for this purpose, to avoid interfering with the existing electronics in any way. I decided to use an HC-SR04 ultrasound range sensor for this purpose. I attached (half of) an old plastic ruler to the door’s lock/latch pin (using cable ties and hot glue!) as an ultrasound reflector, and made sure this stuck out from the side of the door. I mounted the HC-SR04 on the wall behind it. When the door is closed, the ultrasound range is about 10cm, and when open it’s tens of feet to the other side of the garage, which is probably counted as “no reflection” or “maximum range” by the sensor. The software pings the ultrasound every few seconds, applies a little hysteresis to avoid any measurement fluctuations, and reports the status in the main web page.

The one quirk here was that the ultrasound sensor output a 5V logic signal, whereas the ESP8266 GPIO inputs are technically only rated for 3.3V. To solve this, I used a simple voltage divider between the ultrasound output and the ESP8266 GPIO pin to lower the signal voltage.

One cunning aspect of the ultrasound logic is its used of interrupts to measure the length of the echo pulse. This avoids any kind of busy loop to measure the echos, which allows the system to quickly respond to network packets all the time.

Hostname Discovery

The device runs both MDNS and LLMNR to allow systems attached to the local network to dynamically convert “.local” hostnames to IP addresses. this allows the device to be found without requiring manually created DNS entries, or servers for dynamic DNS such as dyndns. This combination of protocols works great from Linux, Windows, and MacOS. However, Android doesn’t seem to support any of them:-( I resorted to using an application named “Pea Finder”, which implements MDNS and can launch a web browser for any discovered device.

Exposing to the Internet

The ESP8266 software doesn’t implement any form of authentication. I figure that anyone connected to my WiFi is probably already in the house, or could break in if they wanted anyway. However, I could imagine checking the door status remotely, and thus Internet access was desirable. I certainly wasn’t going to just port-forward the ESP8266 to the Internet and let any old script kiddy port-scan their way to control of my garage door. To address the security issue while still allowing Internet access, I made my existing Linux home server reverse-proxy HTTP requests from the Internet to the ESP8266, while requiring authentication to access those URLs. Here are the relevant parts of the Apache configuration:

<VirtualHost *:443>
    SSLEngine on
    SSLCertificateFile /path/to/
    SSLCertificateKeyFile /path/to/
    SSLCertificateChainFile /path/to/
    <Location />
        AuthType Basic
        AuthName ""
        AuthBasicProvider file
        AuthUserFile "/path/to/passwd"
        AuthGroupFile "/path/to/group"
    <Location /garage-door-main/>
        Require group garage_door
        ProxyHTMLEnable On
        ProxyHTMLURLMap / /garage-door-main/
        ProxyPass "http://garage-door-main.local/"
        ProxyPassReverse "/"

Simple Android Shortcuts

While opening a web browser to control the door is pretty quick, I wanted something even faster; something close to the speed of a dedicated garage door remote. My current car has bluetooth, so I set my phone to stay unlocked when in the car, which speeds up access - typically I have to unlock it via a PIN code every time I use it. I used an application named “Tasker” to create a task for each garage door, which simply performs the “activate door N” password-protected HTTP POST to the Internet-visible site, and created a desktop icon/shortcut for each task. Opening a door is easy now; press the power button to turn on the screen, swipe up to “unlock” the phone, and click/touch a single icon on the home screen. The only issue is that when I leave the house, the phone is slow to disconnect from WiFi when the signal drops, so sometimes I have to manually disconnect WiFi first. I expect Tasker can automate disabling WiFi as part of a task’s actions, so I’ll look into that in the near future.

Kicad PCB

My first prototype system hung the ESP8266 from a nail in the wall by the 5V USB power cable. Wiring was manual point-to-point using individual wires. This worked, but was messy.

The ESP8266 board does have some mounting holes, but they’re pretty tiny. A better mounting solution was needed; one with larger holes. I also wanted to provide nicely laid out dedicated connectors for the ultrasound sensors and relay board, rather than having to connect all the pins one-by-one into various wiring harnesses. Finally, constructing the ultrasound voltage divider inline with a wiring harness was a bit annoying.

I ended up creating a PCB in Kicad; the first real use I’ve made of Kicad. Ordering the PCB from was a breeze since they now allow direct upload of Kicad PCB files:-)

Ultrasound Mounts

The ultrasound sensors also needed mounting on the wall. A custom PCB wasn’t the answer here, since the ultrasound boards have a right-angle connector which couldn’t easily plug into a PCB that was mounted flat to the wall. Instead, I designed a simple plastic mount the encapsulate the sensor, and attached that to the wall.

On my main garage doors, I wanted to point the ultrasound straight out from the wall, and reflects off a ruler sticking out from door as I described above. On my third garage door, I plan to mount the ultrasound sensor so the sound travels parallel to the wall and reflects off the side of the door. Rather than design two different mounts for these two configurations, I designed a single primary mount that encapsulates the ultrasound sensor, and two different sets of flanges that glue to the end of the mount, and allow the mount to be attached to the wall at different 90 degree angles. I also designed a small clip that tightly fits over the front of the mount and the ultrasound PCB and holds everything tightly in place.

Ultrasound mounts


As I mentioned in a previous blog post, I chose the wrong ESP8266 GPIOs for the relay control; when power is first applied to the board, some of the GPIOs glitch, and for just long enough to trigger the relays and cause the door to open. This is fine when I’m standing next to the garage doors installing the system, but I didn’t fancy that happening during a power outage when I might not be home. Consequently, I worked out which GPIOs had this problem and which didn’t, and designed a rev 2 PCB to avoid connecting the problematic GPIOS to the relays. The new PCBs should arrive in a few days, so I’ll soon be able to tell if this problem is fixed!

Future Work

I have some ESP8266 projects that have been running for months or even years without issue. However, I noticed just today that my garage door controller wasn’t responding correctly so I had to reset it. Some kind of automated watchdog or periodic reboot might be a good idea.

The WiFi setup in my code works, but is extremely rudimentary. It only allows the device to operate in station mode (not as an access point) after setup. If I re-write the software, I’ll investigate any existing ESP8266 WiFi manager projects. I didn’t look for one when I first created the project because I (a) wanted to create the whole project myself the first time around, and (b) wanted to hack it into existence as quickly as possible, without getting bogged down integrating 3rd-party code.

The user interface (web pages) are very bland. Some style-sheets and AJAX would improve the user-experience a lot.

Sometimes the garage door will just “open itself”. This happened before I implemented the ESP8266 system, so I suspect it’s a matter of wireless noise accidentally triggering the existing door opener protocol. I’d like the ESP8266 to email me whenever the door opens or closes, or perhaps any time it’s been open for more than some duration such as 5 minutes.

The current software hard-codes the set of GPIOs and door names. I’d like to store this information in a configuration file in the flash filesystem instead, and allow editing of the pin assignments via the web. With a bit of work, this could turn into a generic ESP8266 web-based GPIO control system, not just something for garage doors.

Bill of Materials

  • NodeMCU ESP8266 board. This is available for $8-$10 on from a variety of sellers. For example:

    Note: These are cheap devices without much markup. As such, you’ll probably see quality issues on some devices. Order a few more than you need and everything will work out. The good thing is that Amazon has easy returns or replacements, and free Prime shipping from at least the sellers linked above. I prefer the NodeMCU board to the Adafruit Huzzah because it’s got built-in USB-serial, plus is a tad cheaper and ships faster/cheaper.

  • USB 5v power supply or charger.

  • TTL-controlled relay board. Again I got this from Amazon via the link below. I’m sure there are plenty of other similar devices available. Amazon link

  • HC-SR04 ultrasound transceivers. Amazon link

  • Various 0.1” connectors and wires that I had hanging around.

  • PCB ordered from

  • 3D-printed HC-SR04 mounts.


2017/04/21: Change code highlighter to pygments; rouge elides some Apache keywords.

2017/04/25: Simplified Apache reverse proxy configuration snippet.