Controlling your garage doors with an ESP32 - Part 1



Four years ago, I got to wire up a Raspberry Pi to a 2 channel relay and a couple of sensors, and hook it up to my garage door openers. This allowed me to open/close any of the doors, as well as to see if the doors were open or closed. Here is blog post I wrote then explaining all I did: (Spanish). This setup suffered a couple evolutions, adding into the picture an MQTT broker (mosquitto), an Android app and even an application for my good old Pebble watch. Although I never published any of theses evolutions, here you can watch a video opening my garage door (as you can see is also a different house… military life…):

Although the setup worked pretty nicely, during this time I had to replace the SD Card at least twice, plus sometimes due to power outages, I had some issues with network connectivity, requiring a device restart. Because of that and the fact you don’t really need much power for driving a relay this way, I decided to go with an ESP32 micro controller, in particular with this development board. Also I would like to mention, the boot up time in the micro controller is way better, since there is not operating system.

The wiring is pretty simple. We need four wires, the power of the relay (VCC) will connect to the 5V output pin in our board, the ground (GND) to one of the GND pins in the board, and then we need to more wires for each channel, in my case I connected the left channel to GPIO 32 and the right one to GPIO 33. Here is the schema:


*ESP32-relay wiring*

To program the micro controller, I used the ESP-IDF (Espressif IoT Development Framework).

The way we’ll communicate with our micro controller, will be through an MQTT broker, in this case I’m using Mosquitto, but it should work with any other broker. All the source code is also published on this Github repository, and lastly, I am using this esp-mqtt component, which you will have to install separately following their installation process.

Assuming you already have installed the ESP-IDF and the esp-mqtt component mentioned above, the first thing you need to do is to clone the repository:

git clone

Once you have done that, you need to configure your project by running:

make menuconfig

And you should see something like this:


*make menuconfig*

The first thing you want to do here is to configure your Serial communication, device and speed (the development board I am using accepts up to 921600 baud).


*Serial configuration*

The next you want to configure are the parameters for our project (Garage Door Opener option), in particular you need to provide an SSID and its password, and an MQTT broker, MQTT username and password (in this case, for testing purposes, I’m using mqtt://, which doesn’t required authentication, so we can leave the the username and password blank).

Garage Door Opener menu option

*Garage Door Opener menu option*

Once you have done that if everything is working properly, then your ESP32 will be listening (subscribed) to two topics: /garage/door/left and /garage/door/right. When a message arrives to any of these channels, we’ll check the value of such message and if the value is PUSH, then we close the relay for .5 seconds, otherwise we discard the message and do nothing.

Let’s go through some of the important parts of the code.

static const char *LEFT_DOOR_TOPIC = "/garage/door/left";
static const char *RIGHT_DOOR_TOPIC = "/garage/door/right";

#define LEFT_DOOR_GPIO 32
#define RIGHT_DOOR_GPIO 33

These are some of the constants where we define the topic names and the GPIO ports our relay is connected.

During the initialization part, besides connecting to the WIFI, etc. We need to set the LEFT_DOOR_GPIO and RIGH_DOOR_GPIO as output and high.

void app_main()

    /* Set the GPIO as a push/pull output */
    gpio_set_direction(LEFT_DOOR_GPIO, GPIO_MODE_OUTPUT);
    gpio_set_direction(RIGHT_DOOR_GPIO, GPIO_MODE_OUTPUT);
    /* Set these PINs high */
    gpio_set_level(LEFT_DOOR_GPIO, 1);
    gpio_set_level(RIGHT_DOOR_GPIO, 1);


Finally, inside our handling function is where we process the messages we receive to any of the channels we mentioned before:

static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
    esp_mqtt_client_handle_t client = event->client;
    int msg_id;
    switch (event->event_id) {
        case MQTT_EVENT_DATA:
            // Get the topic name
            char *topic = malloc(event->topic_len);
            memcpy(topic, event->topic, event->topic_len);
            topic[event->topic_len] = '\0';

            // Get the data
            char *data = malloc(event->data_len);
            memcpy(data, event->data, event->data_len);
            data[event->data_len] = '\0';

            if (strcmp(topic, LEFT_DOOR_TOPIC) == 0) {
                if (strcmp(data, "PUSH") == 0) {
                    gpio_set_level(LEFT_DOOR_GPIO, 0);
                    vTaskDelay(500 / portTICK_PERIOD_MS);
                    gpio_set_level(LEFT_DOOR_GPIO, 1);

            } else if (strcmp(topic, RIGHT_DOOR_TOPIC) == 0) {
                if (strcmp(data, "PUSH") == 0) {
                    gpio_set_level(RIGHT_DOOR_GPIO, 0);
                    vTaskDelay(500 / portTICK_PERIOD_MS);
                    gpio_set_level(RIGHT_DOOR_GPIO, 1);
    return ESP_OK;

The next step will be to test our setup. For that you can use any MQTT client, but first we need to upload our code to chip. Make sure your device is connected to your computer and run:

    make flash

or if you want to see the log messages and what’s going on:

    make monitor

or you can just do both in one shot:

    make flash monitor

I’m using the mosquitto_pub application. Which I run the following commands:

mosquitto_pub -h -t "/garage/door/right" -m "PUSH"

mosquitto_pub -h -t "/garage/door/left" -m "PUSH"

The first command sends the message PUSH to the right door, and second one to the left door.

Here is short video showing these commands running:

In the next parts of this series, we’ll add some sensors, install the device in the garage and create a mobile application to interact with it. Stay tuned!

Esta entrada también está disponible en español.