Busy light button
I had a couple of ESP32 laying around and I’ve been waiting for an excuse to put them to work. I’m working from home and one of the issues I had was to let my wife and child know that I’m in a conference, so I don’t want to be disturbed.
I found out about ESP-NOW, the protocol developed by Espressif, and I immediately thought about making a notification system that will show a red light when I press a button. We’re talking about 2 devices, one sits at my desk - the button, and another one sits in the living room - the red light. When I’m in a conference, I press the button, which will turn on the red light.
ESP-NOW is yet another protocol developed by Espressif, which enables multiple devices to communicate with one another without using Wi-Fi. The protocol is similar to the low-power 2.4GHz wireless connectivity that is often deployed in wireless mouses. So, the pairing between devices is needed prior to their communication. After the pairing is done, the connection is secure and peer-to-peer, with no handshake being required. link
We’ll have 2 ESP32 boards: the first one listens for a button press and send a message to the second ESP32 board to turn on/off the lights.
In order to communicate, we need to find out the MAC address of the receiver ESP32. To do this we can run the following code on the ESP32:
#include "WiFi.h"
void setup(){
Serial.begin(115200);
WiFi.mode(WIFI_MODE_STA);
Serial.println(WiFi.macAddress());
}
void loop(){
}
ESP-NOW has a couple of functions that we can use, full documentation here:
Function | Description |
---|---|
esp_now_init(void) | Initialize ESPNOW function. |
esp_now_register_send_cb(esp_now_send_cb_tcb) | Register callback function of sending ESPNOW data. |
esp_now_add_peer(constesp_now_peer_info_t *peer) | Add a peer to peer list. |
esp_now_send(const uint8_t *peer_addr, const uint8_t *data, size_t len) | Send ESPNOW data. |
esp_now_register_recv_cb(esp_now_recv_cb_tcb) | Register callback function of receiving ESPNOW data. |
Project code
For this project, the setup it’s quite easy:
On the ESP32 that listens for button presses we’ll need the following code:
#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>
#include <OneButton.h>
// #############################################
// Sender
// #############################################
#define LED_PIN 14
OneButton button(GPIO_NUM_13);
// replace with MAC address of ESP32 receiver
uint8_t broadcastAddress[] = {0x.., 0x.., 0x.., 0x.., 0x.., 0x..};
bool isBusy = false;
int led_status = LOW;
void sendMessage()
{
char payload[50];
int len = snprintf(payload, sizeof(payload), "%d", !isBusy ? 1 : 0);
esp_err_t result = esp_now_send(broadcastAddress, reinterpret_cast<const uint8_t *>(payload), len);
if (result == ESP_OK) {
Serial.println("Sent with success");
}
else {
Serial.println("Error sending the data");
}
}
void buttonClick()
{
sendMessage();
}
void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
if (status == ESP_NOW_SEND_SUCCESS) {
isBusy = !isBusy;
led_status = led_status == HIGH ? LOW : HIGH;
digitalWrite(LED_PIN, led_status);
}
}
void setup()
{
Serial.begin(115200);
Serial.println();
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_register_send_cb(onDataSent);
// Register peer
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
button.attachClick(buttonClick);
pinMode(LED_PIN, OUTPUT);
Serial.print("MAC address of this node is ");
Serial.println(WiFi.softAPmacAddress());
Serial.println("Press the button to send a message");
}
void loop()
{
button.tick();
}
And on the receiver ESP32 we’ll need the following code:
#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>
#include <Adafruit_NeoPixel.h>
// #############################################
// Receiver
// #############################################
static const int LED_PIN = 13;
#define PIN 14
#define NUMPIXELS 16
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
void turnOnLights()
{
for (uint16_t i = 0; i < pixels.numPixels(); i++)
{
pixels.setPixelColor(i, pixels.Color(255, 0, 0));
}
pixels.show();
}
void turnOffLights()
{
pixels.clear();
pixels.show();
}
// callback function that will be executed when data is received
void onDataReceived(const uint8_t * mac, const uint8_t *incomingData, int len) {
String payload = "";
for (size_t i = 0; i < len; ++i)
{
payload += (char)incomingData[i];
}
bool isBusy = payload == "1";
if (isBusy)
{
turnOnLights();
}
else
{
turnOffLights();
}
}
void setup()
{
Serial.begin(115200);
Serial.println();
// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// register callback method
esp_now_register_recv_cb(onDataReceived);
pixels.begin();
pixels.setBrightness(100);
pixels.clear();
pixels.show();
}
void loop()
{
}
Now all we have left to do is power on the devices and press the button :-)