ESP-IDF: ESP32 Capacitive Touch Sensor Pins

This guide shows how to use the ESP32 capacitive touch pins with ESP-IDF. The ESP32 touch pins can sense variations in anything that holds an electrical charge (like when touching the pin with your finger). They are often used to wake up the ESP32 from deep sleep.

ESP-IDF: ESP32 Capacitive Touch Sensor Pins

To read the value of the ESP32 touch pins using Arduino IDE, you can read this guide.

Prerequisites

Before following this guide, you need to install the ESP-IDF extension on VS Code IDE (Microsoft Visual Studio Code). Follow the next guide to install it, if you haven’t already:

You will also need an ESP32 development board model of your choice.

Introducing the ESP32 Touch Sensor

The ESP32 (the original chip) has 10 capacitive touch GPIOs. Other ESP32 versions may have a different number of touch GPIOs. For example, the ESP32-S3 comes with 14 touch sensing GPIOs, and other versions like the C2, C3, C6, and H2 don’t come with touch pins.

These GPIOs can sense variations in anything that holds an electrical charge, like the human skin. So they can detect variations induced when touching the GPIOs with a finger.

These pins can be easily integrated into capacitive pads and replace mechanical buttons. Additionally, the touch pins can also be used as a wake up source when the ESP32 is in deep sleep.

Take a look at your board pinout to locate the different touch pins. In the following diagram (for the ESP32 DevKit board), the touch-sensitive pins are highlighted in pink color and go from Touch 0 to Touch 9.

ESP32 Touch Sensitive Pins GPIOs

Learn more about the ESP32 GPIOs: ESP32 Pinout Reference.

For the ESP32-S3 DevkitC board, the touch pins are highlighted in orange in the following diagram.

ESP32-S3 GPIOs Pinout guide

ESP32-S3 GPIO Reference Guide

Note: in the ESP32-S3 board, the TOUCH8 is GPIO 8. However, in the ESP32 Devkit TOUCH 8 is GPIO 33.

Read Touch Pin with ESP-IDF

Reading the value of a touch pin with ESP-IDF is not really straightforward, unlike when using Arduino Core. You must follow these five steps:

  1. Create the touch controller and channel;
  2. Calibrate the channel: scan an untouched pin and set the real threshold;
  3. Register on_active / on_inactive callbacks;
  4. Set a flag inside each callback to avoid delays;
  5. Start scanning and check the flag in your loop.

Creating an ESP-IDF Template App Project for the ESP32

The ESP-IDF extension provides an easy way to create a project from scratch with all the required files and configurations generated automatically.

To create a new ESP-IDF project on VS Code, follow these steps:

  1. Open the ESP-IDF Espressif extension and expand the “Advanced” menu
  2. Click the “New Project Wizard” option
  3. Choose the “Use ESP-IDF v6.X” to select the ESP-IDF framework version
VS Code Open ESP-IDF Extension New Project Wizard Select ESP-IDF Version

A new window opens, you need to fill in these fields:

  • Project Name: type the desired project name;
  • Enter Project Directory: click the folder icon and select the target folder to save all your project files. You can use any directory. Note: do NOT use a Google Drive / One Drive / Dropbox folder, because it will write/create many files during the building process—if it’s on a cloud folder, this process might be extremely slow;
  • ESP-IDF Target: select the target device chip, I’m using an ESP32 with the esp32s3 chip;
  • ESP-IDF Board: for the esp32s3 chip, I also need to select the configuration: ESP32-S chip (via builtin USB-JTAG);
  • Serial Port: while having your ESP32 board connected to your computer, select the correct COM port number that refers to your ESP32;
  • Choose Template: click the blue button to create a new project using a template.
ESP-IDF ESP32 Create Open New Project Wizard Menu Select Directory Board Template

In the menu, select the “ESP-IDF Templates” sample project and press the “Create project using template sample project” button.

ESP-IDF ESP32 Create New Sample Project using IDF Template

Opening the ESP-IDF Project on VS Code

After a few seconds, a notification will appear in a new window in VS Code. You can click “Open Project” to open the newly created ESP-IDF sample project template.

ESP-IDF ESP32 Open New Project Sample

IMPORTANT: if you didn’t see the notification that allows you to automatically open the ESP-IDF project on VS Code, you can easily do it by following these instructions:

Go to File > Open Folder…

ESP-IDF ESP32 Open Project Folder VS Code File Menu

Browse on your computer for the esp-idf-project folder (your project folder name that you’ve previously defined) and “Select Folder“.

ESP-IDF ESP32 Open Project VS Code Select Folder

That’s it! Your new ESP-IDF project template has been successfully created and opened.

ESP-IDF generates many files, folders, and subfolders for your project. For this guide, I recommend keeping all the default files unchanged; we will only modify the main.c file.

The example codes will be written in the main.c file. To open it, follow these instructions:

  1. Open the project explorer by clicking the first icon on the left sidebar.
  2. Select your project folder name, in my case it’s “ESP-IDF-PROJECT“.
  3. Expand the “main” folder.
  4. Click the “main.c” file.
  5. The default main.c template file loads in the code window.
ESP-IDF ESP32 Open Project in a VS Code Browse to Main C File

Code – ESP-IDF: ESP32 Capacitive Touch Sensor Pins

Let’s see how you can trigger an event with the ESP32 using the touch pins. In this simple example, we’ll turn on an LED when you touch a pin.

Copy the following code to your main.c file in VS Code.

/*  
  Rui Santos & Sara Santos - Random Nerd Tutorials
  https://RandomNerdTutorials.com/esp-idf-esp32-touch-sensor-pins/
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/touch_sens.h"

static const char *TAG = "touch_led";

#define TOUCH_CH 8
#define LED_PIN  2

// Touch sensor configuration
#if SOC_TOUCH_SENSOR_VERSION == 1       // ESP32
    #define SAMPLE_CONFIG       TOUCH_SENSOR_V1_DEFAULT_SAMPLE_CONFIG(5.0, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_1V7)
    #define ACTIVE_THRESH_RATIO 0.98

    #define CHAN_CFG_DEFAULT()  { \
        .abs_active_thresh = {1000}, \
        .charge_speed = TOUCH_CHARGE_SPEED_7, \
        .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, \
        .group = TOUCH_CHAN_TRIG_GROUP_BOTH, \
    }
#elif SOC_TOUCH_SENSOR_VERSION == 2     // ESP32-S2 / S3
    #define SAMPLE_CONFIG       TOUCH_SENSOR_V2_DEFAULT_SAMPLE_CONFIG(500, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_2V2)
    #define ACTIVE_THRESH_RATIO 0.02

    #define CHAN_CFG_DEFAULT()  { \
        .active_thresh = {2000}, \
        .charge_speed = TOUCH_CHARGE_SPEED_7, \
        .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, \
    }
#elif SOC_TOUCH_SENSOR_VERSION == 3     // ESP32-P4
    #define SAMPLE_CONFIG       TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG2(3, 29, 8, 3), \
                                TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG2(2, 88, 31, 7), \
                                TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG2(3, 10, 31, 7)
    #define ACTIVE_THRESH_RATIO 0.02

    #define CHAN_CFG_DEFAULT()  { \
        .active_thresh = {1000, 2500, 5000}, \
    }
#else
    #error "Board target not supported"
#endif

// Calibrate touch sensor: take a benchmark reading and set the active threshold
static void calibrate_touch(touch_sensor_handle_t sens, touch_channel_handle_t chan)
{
    ESP_ERROR_CHECK(touch_sensor_enable(sens));
    for (int i = 0; i < 3; i++) {
        ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(sens, 2000));
    }
    ESP_ERROR_CHECK(touch_sensor_disable(sens));

    uint32_t benchmark = 0;
#if SOC_TOUCH_SUPPORT_BENCHMARK
    touch_channel_read_data(chan, TOUCH_CHAN_DATA_TYPE_BENCHMARK, &benchmark);
#else
    touch_channel_read_data(chan, TOUCH_CHAN_DATA_TYPE_SMOOTH, &benchmark);
#endif

    touch_channel_config_t chan_cfg = CHAN_CFG_DEFAULT();

#if SOC_TOUCH_SENSOR_VERSION == 1
    chan_cfg.abs_active_thresh[0] = (uint32_t)(benchmark * ACTIVE_THRESH_RATIO);
#else
    chan_cfg.active_thresh[0]     = (uint32_t)(benchmark * ACTIVE_THRESH_RATIO);
#endif

    ESP_ERROR_CHECK(touch_sensor_reconfig_channel(chan, &chan_cfg));
    ESP_LOGI(TAG, "Benchmark: %lu - threshold set", benchmark);
}

// Set by the touch driver's event callbacks, read by the main task loop
static volatile bool touch_active = false;

// Called from the touch driver when the channel becomes active (touch dectected)
static bool IRAM_ATTR on_touch_active(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx)
{
    touch_active = true;
    return false;
}

// Called from the touch driver when the channel becomes inactive (touch released)
static bool IRAM_ATTR on_touch_inactive(touch_sensor_handle_t sens_handle, const touch_inactive_event_data_t *event, void *user_ctx)
{
    touch_active = false;
    return false;
}

void app_main(void)
{
    // Configure LED GPIO as output
    gpio_config_t led_cfg = {
        .pin_bit_mask = 1ULL << LED_PIN,
        .mode = GPIO_MODE_OUTPUT,
    };
    gpio_config(&led_cfg);
    gpio_set_level(LED_PIN, 0);

    touch_sensor_handle_t sens = NULL;
    touch_channel_handle_t chan = NULL;

    // Touch sensor controller
    touch_sensor_sample_config_t sample_cfg[TOUCH_SAMPLE_CFG_NUM] = { SAMPLE_CONFIG };
    touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(TOUCH_SAMPLE_CFG_NUM, sample_cfg);

    ESP_ERROR_CHECK(touch_sensor_new_controller(&sens_cfg, &sens));

    // Configure touch sensor channel
    touch_channel_config_t chan_cfg = CHAN_CFG_DEFAULT();
    ESP_ERROR_CHECK(touch_sensor_new_channel(sens, TOUCH_CH, &chan_cfg, &chan));

    // Filter
    touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG();
    ESP_ERROR_CHECK(touch_sensor_config_filter(sens, &filter_cfg));

    // Calibrate touch sensor
    calibrate_touch(sens, chan);

    // Register touch active/inactive event callbacks
    touch_event_callbacks_t callbacks = {
        .on_active = on_touch_active,
        .on_inactive = on_touch_inactive,
    };
    ESP_ERROR_CHECK(touch_sensor_register_callbacks(sens, &callbacks, NULL));

    // Start continuous touch sensor scanning
    ESP_ERROR_CHECK(touch_sensor_enable(sens));
    ESP_ERROR_CHECK(touch_sensor_start_continuous_scanning(sens));

    ESP_LOGI(TAG, "Touch GPIO %d to turn on LED on GPIO %d", TOUCH_CH, LED_PIN);

    // Flag to hold current LED state
    bool led_on = false;
    while (1) {
        // Read the touch_active flag set by the touch driver's callbacks
        bool touched = touch_active;
        if (touched && !led_on) {
            // Turn on LED when touch is detected
            gpio_set_level(LED_PIN, 1);
            led_on = true;
            ESP_LOGI(TAG, "Touch detected, LED ON");
        } else if (!touched && led_on) {
            // Turn off LED when touch is released
            gpio_set_level(LED_PIN, 0);
            led_on = false;
            ESP_LOGI(TAG, "Touch released, LED OFF");
        }
        vTaskDelay(pdMS_TO_TICKS(20));
    }
}

View raw code

How the Code Works

In this section, we’ll take a look at the code to see how it works.

Libraries

We start by including the required libraries:

  • stdio.h – the standard C library will be used for the printf function that prints the debugging information in the serial monitor;
  • FreeRTOS.h – provides the core FreeRTOS types and functions;
  • task.h – allows to use of the non-blocking delay function vTaskDelay;
  • esp_log.h – offers a framework to format log messages in the serial monitor for debugging;
  • gpio.h – includes the functions required to configure and control GPIOs;
  • touch_sens.h – capacitive touch sensor driver functions required to configure, calibrate and read the touch channel.
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/touch_sens.h"

Touch Channel

First, define the touch channel you want to use. On ESP32-S3, channel 8 corresponds to GPIO 8, but it might be different for other ESP32 boards with different ESP32 chips.

#define TOUCH_CH 8

LED Pin

We’ll control an LED connected to GPIO 2. You can change it to any other suitable GPIO.

#define LED_PIN  2

Touch Sensor Configuration

This code is automatically compatible with different ESP32 chips, you don’t need to modify these default thresholds and voltage limits.

#if SOC_TOUCH_SENSOR_VERSION == 1       // ESP32
    #define SAMPLE_CONFIG       TOUCH_SENSOR_V1_DEFAULT_SAMPLE_CONFIG(5.0, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_1V7)
    #define ACTIVE_THRESH_RATIO 0.98

    #define CHAN_CFG_DEFAULT()  { \
        .abs_active_thresh = {1000}, \
        .charge_speed = TOUCH_CHARGE_SPEED_7, \
        .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, \
        .group = TOUCH_CHAN_TRIG_GROUP_BOTH, \
    }
#elif SOC_TOUCH_SENSOR_VERSION == 2     // ESP32-S2 / S3
    #define SAMPLE_CONFIG       TOUCH_SENSOR_V2_DEFAULT_SAMPLE_CONFIG(500, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_2V2)
    #define ACTIVE_THRESH_RATIO 0.02

    #define CHAN_CFG_DEFAULT()  { \
        .active_thresh = {2000}, \
        .charge_speed = TOUCH_CHARGE_SPEED_7, \
        .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, \
    }
#elif SOC_TOUCH_SENSOR_VERSION == 3     // ESP32-P4
    #define SAMPLE_CONFIG       TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG2(3, 29, 8, 3), \
                                TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG2(2, 88, 31, 7), \
                                TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG2(3, 10, 31, 7)
    #define ACTIVE_THRESH_RATIO 0.02

    #define CHAN_CFG_DEFAULT()  { \
        .active_thresh = {1000, 2500, 5000}, \
    }
#else
    #error "Board target not supported"
#endif

Touch Sensor Calibration

The calibrate_touch() function is necessary to prepare your touch pins and here’s how it works:

  • Enables the sensor and takes a couple of oneshot measurements;
  • Reads the benchmark value when the pin is untouched;
  • Calculates an active threshold (benchmark depends on the ESP32 chip);
  • Reconfigures the channel with the new threshold, so it’s only triggered with accurate signals.
static void calibrate_touch(touch_sensor_handle_t sens, touch_channel_handle_t chan)
{
    ESP_ERROR_CHECK(touch_sensor_enable(sens));
    for (int i = 0; i < 3; i++) {
        ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(sens, 2000));
    }
    ESP_ERROR_CHECK(touch_sensor_disable(sens));

    uint32_t benchmark = 0;
#if SOC_TOUCH_SUPPORT_BENCHMARK
    touch_channel_read_data(chan, TOUCH_CHAN_DATA_TYPE_BENCHMARK, &benchmark);
#else
    touch_channel_read_data(chan, TOUCH_CHAN_DATA_TYPE_SMOOTH, &benchmark);
#endif

    touch_channel_config_t chan_cfg = CHAN_CFG_DEFAULT();

#if SOC_TOUCH_SENSOR_VERSION == 1
    chan_cfg.abs_active_thresh[0] = (uint32_t)(benchmark * ACTIVE_THRESH_RATIO);
#else
    chan_cfg.active_thresh[0]     = (uint32_t)(benchmark * ACTIVE_THRESH_RATIO);
#endif

    ESP_ERROR_CHECK(touch_sensor_reconfig_channel(chan, &chan_cfg));
    ESP_LOGI(TAG, "Benchmark: %lu - threshold set", benchmark);
}

Auxiliary variable

The touch_active is an auxiliary variable that stores a flag to tell us whether the touch channel is currently active or not.

static volatile bool touch_active = false;

on_touch_active()

The on_touch_active() is an ISR callback that sets the touch flag to true when the sensor detects touch (read our ESP-IDF Interrupts Guide).

static bool IRAM_ATTR on_touch_active(touch_sensor_handle_t sens_handle, 
                                     const touch_active_event_data_t *event, void *user_ctx)
{
    touch_active = true;
    return false;
}

on_touch_inactive()

The on_touch_inactive() is also an ISR callback, but it changes the flag to false when it detects the touch sensor has been released.

static bool IRAM_ATTR on_touch_inactive(touch_sensor_handle_t sens_handle, 
                                         const touch_inactive_event_data_t *event, void *user_ctx)
{
    touch_active = false;
    return false;
}

Set the LED Pin as an output

In the app_main() function, start by configuring the LED_PIN as an output and set it to LOW when the code first runs (learn more about ESP-IDF GPIO Outputs).

gpio_config_t led_cfg = {
    .pin_bit_mask = 1ULL << LED_PIN,
    .mode = GPIO_MODE_OUTPUT,
};
gpio_config(&led_cfg);
gpio_set_level(LED_PIN, 0);

Touch Controller

Next, create the main touch sensor hardware controller with correct sampling settings for each ESP32 chip version.

touch_sensor_sample_config_t sample_cfg[TOUCH_SAMPLE_CFG_NUM] = { SAMPLE_CONFIG };
touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(...);

ESP_ERROR_CHECK(touch_sensor_new_controller(&sens_cfg, &sens));

Configure Touch Sensor Channel

Attach the touch channel that is connected to your GPIO to the touch controller created previously.

touch_channel_config_t chan_cfg = CHAN_CFG_DEFAULT();
ESP_ERROR_CHECK(touch_sensor_new_channel(sens, TOUCH_CH, &chan_cfg, &chan));

Noise Filter

Enable a noise filter to make touch detection more stable and reduce false triggers.

touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG();
ESP_ERROR_CHECK(touch_sensor_config_filter(sens, &filter_cfg));

calibrate_touch()

The calibration function measures the current untouched value of the pad and automatically sets a reliable detection threshold.

calibrate_touch(sens, chan);

Register touch callbacks

Register your ISR functions for the touch sensor to automatically call on_touch_active() and on_touch_inactive() when touch is detected or released.

touch_event_callbacks_t callbacks = {
    .on_active = on_touch_active,
    .on_inactive = on_touch_inactive,
};
ESP_ERROR_CHECK(touch_sensor_register_callbacks(sens, &callbacks, NULL));

Touch sensor scanning

The next two lines enable the touch sensor and start scanning for touch sensor changes:

ESP_ERROR_CHECK(touch_sensor_enable(sens));
ESP_ERROR_CHECK(touch_sensor_start_continuous_scanning(sens));

Finally, this next loop continuously checks the touched flag variable (which is updated by the ISR callbacks). If the flag is true, it turns GPIO 2 on, and when the touch sensor is released, it turns the GPIO off

bool led_on = false;
while (1) {
    bool touched = touch_active;
    if (touched && !led_on) {
        gpio_set_level(LED_PIN, 1);
        led_on = true;
        ESP_LOGI(TAG, "Touch detected, LED ON");
    } else if (!touched && led_on) {
        gpio_set_level(LED_PIN, 0);
        led_on = false;
        ESP_LOGI(TAG, "Touch released, LED OFF");
    }
    vTaskDelay(pdMS_TO_TICKS(20));
}

Wiring the Circuit

If you’re using ESP32-S3 model, to test this example, wire a cable to GPIO 8 and an LED to GPIO 2, as shown in the schematic below.

ESP-IDF ESP32 Capacitive Touch Pin Sensor Wiring Circuit Diagram

Build and Flash Code to the ESP32 Board

To build and flash ESP-IDF code to the ESP32, you always need to follow this procedure. You need to select the flash method (UART), the COM port number, the target device (ESP32), build the code, and finally, flash it to the board. All these commands are available in the bottom menu bar of VS Code.

Make sure all your options are correct (they may already be properly configured if you used the project wizard).

VS Code ESP-IDF Check All the Configured Settings UART COM Port Target Board

However, if your setup is not correct, follow the next instructions to ensure everything is set up correctly. First, click the “Star” icon and select the flash method as UART.

VS Code ESP-IDF Select Flash UART Option to Program Flash ESP32

While the ESP32 board is connected to your computer, click the COM Port (plug icon) and select the correct port number that refers to your ESP32.

VS Code ESP-IDF Programming ESP32 Board Select Correct COM Port Number

You also need to select the target device. Click on the chip icon at the bottom bar. In my case, I have an ESP32 with the esp32s3 chip.

VS Code Select the ESP32 S3 or Correct Target Device ESP-IDF

For this board, I also need to select the configuration: ESP32-S3 chip (via builtin USB-JTAG).

VS Code ESP-IDF Select the ESP32 S3 chip via built in USB JTAG Target Device

Finally, your command bar at the bottom of VS Code should have similar options selected.

VS Code ESP-IDF Check All the Configured Settings UART COM Port Target Board

Now, you can build the project by clicking the wrench icon (Build Project) as shown in the image below.

VS Code Build Project Example Code ESP32 ESP-IDF

The first time you build a project, it usually takes a bit more time. Once completed, it should print a similar message in the Terminal menu and show a “Build Successfully” message.

VS Code Build Example Project ESP32 ESP-IDF Success Message

This is the final step. You can now flash the ESP-IDF project to the ESP32 by clicking the “Flash Device” button (thunder icon).

VS Code Flash Hello World Code Project to ESP32 ESP-IDF

Depending on your board, you might need to hold down the on-board BOOT button on your ESP32 to put it into flashing mode. Once the process is completed, it will pop up an info message saying “Flash Done“.

VS Code Flash Hello World Project to ESP32 ESP-IDF Done Success Message

Testing the Touch Sensor

Upload the code to your ESP32 and open the Terminal window. Touch the wire connected to GPIO 8 touch pin, and the LED attached to GPIO 2 will stay on as long as you hold/touch the wire with your finger. It will automatically turn off when you release it.

ESP-IDF ESP32 Touch Pad GPIO Wakeup Demonstration

When you touch or release the pin, the ESP32 logs a message on the Terminal window showing what’s happening.

ESP-IDF ESP32 Capacitive Touch Sensor Pins Demonstration

Wrapping Up

In this tutorial, you’ve learned how to use the ESP32 touch pins with the ESP-IDF framework using VS Code. You might find it helpful to read other ESP-IDF guides:

Meanwhile, you can check our ESP32 resources to learn more about the ESP32 with ESP-IDF board:

Thanks for reading.



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Recommended Resources

Build a Home Automation System from Scratch » With Raspberry Pi, ESP8266, Arduino, and Node-RED.

Home Automation using ESP8266 eBook and video course » Build IoT and home automation projects.

Arduino Step-by-Step Projects » Build 25 Arduino projects with our course, even with no prior experience!

What to Read Next…


Enjoyed this project? Stay updated by subscribing our newsletter!

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.