Cultivate Curiosity, Inspire Imagination.

ESP32 Tutorial: Wireless Doorbell Logger


This tutorial showcases the construction of a Wireless Doorbell using 2 ESP32 Development Boards. It uses ESP-NOW, a protocol developed by Espressif to allow 2 ESP32s to communicate with each other without the need for WiFi connections.


Hardware Required

You may purchase the individual components here:

  1. Solderless Breadboard 400 Tie Point
  2. WiFi Bluetooth Module ESP32-WROOM-32E
  3. LCD TFT 2.4 inch 3.2 inch inch Resistive Touch
  4. Button with Cap Module
  5. Clock Module RTC DS3231
  6. Active Buzzer Module
  7. Rainbow LED 1x5 Module
  8. Jumper Wire Male-Male 40x


Connecting the Hardware

The doorbell transmitter sends a signal to the doorbell receiver when someone presses the button. Connect one leg of the button to the GND pin of an ESP32 and connect the other leg to pin 23.


We will begin assembling the doorbell receiver by connecting the LCD TFT module to the ESP32. The LCD TFT module will display the date, time, and the information to say that the doorbell has been pressed. Connect the LCD TFT to the ESP32 as shown in the diagram below:

  • The following pins allow communications between the ESP32 and the LCD TFT Module
    • LCD TFT (SDO MISO) - ESP32 (19)
    • LCD TFT (SCK) - ESP32 (18)
    • LCD TFT (SDI MOSI) - ESP32 (23)
    • LCD TFT (D/C) - ESP32 (2)
    • LCD TFT (RESET) - ESP32 (4)
    • LCD TFT (CS) - ESP32 (15)
  • LCD TFT (LED) - ESP32 (3V3): This powers the LCD screen on the LCD TFT
  • LCD TFT (GND) - ESP32 (GND): This grounds the LCD TFT
  • LCD TFT (VCC) - ESP32 (VCC): This powers the LCD TFT

The Rainbow LED lights up whenever the doorbell receiver receives a signal when the doorbell transmitter's button is pressed. Connect the Rainbow LED to the ESP32 as shown in the diagram below:

  • Rainbow LED (DIN) - ESP32 (25): This allows the ESP32 to send a signal to tell the Rainbow LED to light up
  • Rainbow LED (5V) - ESP32 (3V3): This powers the Rainbow LED
  • Rainbow LED (GND) - ESP32 (GND): This grounds the Rainbow LED

The Clock RTC DS3231 module allows us to log the time that the doorbell transmitter's button is pressed. Connect the Clock module to the ESP32 as shown in the diagram below:

  • Clock Module (SCL) - ESP32 (22): The SCL (Serial Clock) on the clock module will send signals at regular intervals to the ESP32. This allows time intervals to be recorded.
  • Clock Module (SDA) - ESP32 (21): The SDA (data) pin on the clock module allows the Clock Module to communicate by sending data to the ESP32.
  • Clock Module (3V3) - ESP32 (3V3): This powers the Clock Module
  • Clock Module (GND) - ESP32 (GND): This grounds the Clock Module

The Active Buzzer module produces an audible buzz when the doorbell receiver receives a signal to indicate that it has been pressed. Connect the Active Buzzer module to another ESP32 as shown in the diagram below:

  • Active Buzzer (GND) - ESP32 (GND): This grounds the Active Buzzer
  • Active Buzzer (I/O) - ESP32 (14): This allows the Active Buzzer to receive signals sent by the ESP32
  • Active Buzzer (VCC) - ESP32 (3V3): This powers the Active Buzzer


Install the ESP32 Extension for Arduino

Install the ESP32 extension for Arduino. A tutorial on how to install can be found here.


Install the Libraries

There are 3 libraries that are required for this project, namely:

  • TFT_eSPI: Library and driver for the TFT LCD Module
  • RTClib: Library for the Clock Module
  • Adafruit Neopixel: Library for the LED strip

On the Arduino IDE, go to Tools > Manage Libraries and install ”TFT_eSPI”, “RTClib” and “Adafruit Neopixel”.


Modifying the TFT_eSPI Library Setup Files

Open the file Arduino libraries > TFT_eSPI > User_Setup.h. We will be modifying some codes to match our ESP32 setup. Our TFT screen is using ILI9341 driver, so check line 39 to make sure it’s active.

Comment lines 161 to 163 as we are not using ESP8266 setup

Uncomment lines 196 to 201 for our ESP32 pin connections. OK, we are now ready to program our doorbell transmitter and receiver!


Programming The Doorbell Transmitter

We will be using ESP-Now to communicate wirelessly between our Doorbell Transmitter and Receiver. ESP-NOW is a protocol developed by Espressif, which enables multiple devices to communicate with one another without using Wi-Fi, similar to the low-power 2.4GHz wireless connectivity that is often deployed in a wireless mouse.

On the Arduino IDE, select the "ESP32 Dev Module".

Open Examples > ESP32 > ESPNow > Basic > Master.

We will replace the following sample codes from the Master program:

// Global copy of slave
esp_now_peer_info_t slave;
#define CHANNEL 3

Replace the MAC address (0x00, 0x00, 0x00, 0x00, 0x00, 0x00) with the MAC address of the ESP32 that you are using for the Doorbell Receiver. The Doorbell Receiver program that we are developing in the next section will display the ESP32's MAC address on the TFT LCD screen.

uint8_t broadcastAddress[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

Declare a button for the doorbell receiver

// declare pin
const int buttonPin = 23;

Declare the variables that we will be using in the Doorbell Transmitter program.

// declare pin
const int buttonPin = 23;

Declare the variables that we will be using in the Doorbell Transmitter program.

// declare variables
int buttonState, lastButtonState, debounceDelay;
unsigned long lastDebounceTime;
uint8_t data;

Declare an object for ESP-Now so that we can call it later.

// declare object
esp_now_peer_info_t peerInfo;

Delete the methods ScanForSlave(), manageSlave() and deletePeer() as we will not be needing them.

Add a readButton() method with debounce to filter out noise when it is pressed. When the button is pressed, we will call the sendData() method to send a message to our other ESP32 device.

// send message to other ESP32
if (buttonState == LOW) {
// Send message via ESP-NOW

In our main loop, call method readButton() to detect it when the button is pressed.

void loop() {

That’s it! Now our doorbell transmitter is ready. We can move on to program our doorbell receiver.


Programming The Doorbell Receiver

On the Arduino IDE, select the "ESP32 Dev Module".

Include the required libraries for the program. “Free_Fonts.h” can be found from Arduino libraries > TFT_eSPI > examples > 320x240 > All_Free_Fonts_Demo. Copy “Free_Fonts.h” and put it into the same folder as your program so your program can find the file to compile.

// include libraries
#include <esp_now.h>
#include <WiFi.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
#include "Free_Fonts.h"
#include "RTClib.h"
#include <Adafruit_NeoPixel.h>

We declare a LED_COUNT variable for the number of Neopixels and a BRIGHTNESS variable for the brightness of Neopixel. 150 is a nice balance between brightness and power consumption.

// declare user variables
#define LED_COUNT 5
#define BRIGHTNESS 150 // NeoPixel brightness, 0 (min) to 255 (max)

Next, we declare our pins, variables, and objects. We keep an array of 5 data sets to keep track of the most recent 5 data received from our doorbell transmitter.

// declare pins
const int buzzerPin = 14;
const int neopixelPin = 25;

// declare variables
uint8_t data;
char logArray[5][22];

// declare objects
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
RTC_DS3231 rtc;
Adafruit_NeoPixel strip(LED_COUNT, neopixelPin, NEO_GRB + NEO_KHZ800);

The drawStartScreen() method will draw the start-up screen on the TFT LCD, with the mac address of the Doorbell Receive displayed at the bottom of the screen. When we run the program, the MAC address of the ESP32 will be displayed on the TFT LCD screen. We may then copy and enter this MAC address into the codes for the Doorbell Transmitter mentioned in the section "Programming the Doorbell Transmitter" above.

void drawStartScreen() {
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawString("DOORBELL LOGGER", 5, 5, GFXFF);
tft.drawRect(0, 40, 320, 160, TFT_WHITE);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawString("MAC Address :", 5, 220, GFXFF);
tft.setTextColor(TFT_ORANGE, TFT_BLACK);
tft.drawString(WiFi.softAPmacAddress(), 135, 220, GFXFF);

The drawDoorbellLog() method updates the LCD TFT screen with the date and time when the doorbell is pressed to keep a log of the exact date and time that the doorbell was pressed. It will show the most recent log at the top, and up to a total of 5 logs.

void drawDoorbellLog() {
char strBuffer[22];
DateTime now =;
// format datetime to become hh:mm:ss (dd/mm/yyyy)
sprintf(strBuffer, "%02i:%02i:%02i (%02i/%02i/%04i)", now.hour(), now.minute(), now.second(),, now.month(), now.year());

// shift array 1 position down
memcpy(logArray, &logArray[1], sizeof(logArray) - sizeof(char) * 22);
// update array with latest value
memcpy(logArray[4], strBuffer, sizeof(char) * 22);

tft.fillRect(1, 41, 318, 158, TFT_BLACK);
// draw data in array to screen
for (int i = 4; i >= 0; i--) {
if (strcmp(logArray[i], "") != 0) {
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawNumber(5 - i, 5, ((4 - i) * 30) + 50, GFXFF);
tft.drawString(". Doorbell @", 17, ((4 - i) * 30) + 50, GFXFF);
tft.setTextColor(TFT_RED, TFT_BLACK);
tft.drawString(logArray[i], 125, ((4 - i) * 30) + 50, GFXFF);

The alarm() method sends an instruction to the Rainbow LED strip to blink and to sound the buzzer.

void alarm() {
for (int i = 0; i < 4; i++) {
digitalWrite(buzzerPin, LOW);
strip.fill(strip.Color(255, 0, 0, strip.gamma8(255)));; // Send the updated pixel colors to the hardware.
digitalWrite(buzzerPin, HIGH);
strip.fill(strip.Color(0, 0, 0, strip.gamma8(255)));; // Send the updated pixel colors to the hardware.

The InitESPNow() method will initialize ESPNow's wireless feature.

// Init ESP Now with fallback
void InitESPNow() {
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
else {
Serial.println("ESPNow Init Failed");

Whenever new data is received, the OnDataRecv() method redraws the latest log onto the LCD screen and blinks the Neopixels, and sounds the buzzer to alert the user.

// callback when data is recv from Master
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
Serial.print("Last Packet Recv Data: "); Serial.println(*data);

Edit the setup() method to initialize our pin and to call InitESPNow() to initialize ESP-Now on the ESP32.

// initialize pins
pinMode(buzzerPin, OUTPUT);
digitalWrite(buzzerPin, HIGH);

// Set device as a Wi-Fi Station

// This is the mac address of the Slave in AP Mode
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());

// Init ESPNow with a fallback logic

// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info.

Initialize the Clock Module and set the date and time.

// initialize clock module
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1) delay(10);

if (rtc.lostPower()) {
Serial.println("RTC lost power, let's set the time!");

// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));

Finally, initialize our TFT and rotate it to landscape mode, then draw the start screen. Initialize our Neopixel and set its brightness.

// initialize tft

// initialize neopixel
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED); // Turn OFF all pixels ASAP

Upload the programs to both the Doorbell Transmitter and Receiver. Now press the button on the Doorbell Transmitter.

Watch the data log appear on the TFT screen! Now you know if you missed any package from the courier while you are away!