My motivation for this project was mainly to explore controlling an ESP32 board via a Bluetooth Low Energy (BLE) connection. A possible use case might be, for example, to call your children by activating a buzzer or vibration motor using a smartphone app. Another use case could be to indicate that you are busy and do not want to be disturbed e.g. by activating a red light.
For such purposes, there is a predefined Bluetooth service called Immediate Alert. This service defines a variable with three states: no alert
, mild alert
, and high alert
.
As hardware, I used an M5Stack Atom Lite ESP32 pico device which comes already equipped with a button and an RGB Led.
Features- The Atom Lite acts as BLE server and advertises the
Immediate Alert
service. - A client can connect to the Atom Lite and set the
Alert Level
characteristic. - Alternatively, a client can connect using a
WiFi TCP socket
. - The Atom Lite signals an active alert by flashing of the internal Led and a vibration motor. There are two alert levels, which are distinguished by different Led colors and different vibration frequencies.
- The alert can be deactivated by pressing the button of the Atom Lite.
- The client is notified about the deactivation of the alert.
I used Visual Studio Code
with the PlatformIO IDE
extension for the project. Unlike in Arduino IDE, there is no need to install an ESP32 package or required libraries. Instead, the setup of the development board and the library dependencies are accomplished by means of a configuration file named platformio.ini
:
[env:pico32]
platform = espressif32
board = pico32
framework = arduino
upload_speed = 115200
lib_deps =
JC_Button
FastLED
ESP32 BLE Arduino
monitor_speed = 115200
Source Code of the ESP32 ApplicationThe commented source code is available in the GitHub repository of this project. The repository contains two versions of the project, the original "BLE only" version, and a configurable version that allows to choose between BLE and WiFi. More details are given below.
Implementation of the BLE Alert ServiceIn the code, the following constants contain the UUIDs (Universally Unique Identifiers) of the Immediate Alert
service and the Alert Level
characteristic. The UUIDs, i.e. 0x1802 and 0x2A06, are defined by the Bluetooth standard.
const uint16_t BLE_UUID_SERVICE_IMMEDIATE_ALERT = 0x1802;
const uint16_t BLE_UUID_CHARACTERISTIC_ALERT_LEVEL = 0x2A06;
In addition, the Client Configuration Characteristic Descriptor (CCCD) is used in order to allow the server to notify clients about value changes. The CCCD has the UUID 0x2902 and is created in the application as follows:
pAlertLevelCharacteristic->addDescriptor(new BLE2902());
Switching from BLE to WiFi ImplementationSince the range of BLE is quite limited, it can be favorable, to use a WiFi connection instead. Therefore, I have extended the project to be able to choose between a BLE and WiFi interface. For this purpose, the abstact base class AlertService
and the two derived classes AlertServiceBLE
and AlertServiceWifi
have been introduced.
class AlertService {
public:
// Sets the alert level to the specified value
virtual bool setAlertLevel(uint8_t alertLevel, bool notify) = 0;
// Returns the current alert level
virtual uint8_t getAlertLevel() = 0;
// Initializes and starts the service
virtual void start() = 0;
bool isValidLevel(uint8_t level);
};
The extended version of the project is available in the WiFi branch of the Github repository. In this version, you can switch between the BLE and the WiFi alert service by setting the default_envs
option in the platformio.ini file to either pico32_wifi
or pico32_ble
.
[platformio]
default_envs = pico32_wifi
#default_envs = pico32_ble
According to the chosen build environment, either the build flag ALERT_SERVICE_WIFI
or the build flag ALERT_SERVICE_BLE
is set. The instantiation of the corresponding sub class of the AlertService
class is accomplished by means of the #ifdef
preprocessor directive:
// Instantiate the service according to the chosen build configuration
#ifdef ALERT_SERVICE_WIFI
pAlertService = new AlertServiceWifi(WifiCredentials::SSID,
WifiCredentials::PASSWORD, WifiCredentials::PORT);
#endif
#ifdef ALERT_SERVICE_BLE
pAlertService = new AlertServiceBLE();
#endif
Implementation of the WiFi Alert ServiceTo build the WiFi variant of the application, you additonally need to create a WifiCredentials.cpp
file in the src
folder, with the following content:
#include "WifiCredentials.h"
char *WifiCredentials::SSID = "Your WiFi SSID";
char *WifiCredentials::PASSWORD = "Your WiFi password";
The TCP port to which the client must connect, is defined in the WiFiCredentials.h
file and can be changed according to your needs:
static const uint16_t PORT = 12321;
The activation of WiFi and connection to an access point follows the basic steps as described in the Arduino WiFi reference, e.g.:
WiFi.begin(ssid_, password_);
The WiFiServer
class is used to create a server socket, listen on the chosen TCP port and wait for client connections:
alertServer_.begin(port);
The communication between the alert server and its client is handled by the alertServiceTask
function of the AlertServiceWifi
class. In order to peform the communication concurrently to the main loop()
function of the ESP32 application, a task is created:
xTaskCreate(alertServiceTask, "AlertServiceTask", 4096, this, 5, NULL);
The actual communication happens through read
and write
commands, e.g.:
int rxValue = client.read();
Therein, a similar logic is implemented as for the BLE alert level characteristic, i.e.:
- The client can write an alert level 0 (no alert), 1 (mild alert), or 2 (high alert).
- The client can request reading the current alert level.
- In case the alert level changes because the user presses the ESP32 button, the server notifies the client about the change of the alert level.
// If the notification flag is active, send an update to the client
if (pAlertService->isServerNotification_) {
uint8_t level = pAlertService->alertLevel_;
client.write(level);
pAlertService->isServerNotification_ = false;
}
Implementation of the Alarm OutputTo generate a periodic vibration alarm pattern, I use the PWM (Pulse Width Modulation) output capability of the ESP32. The following code fragments create a periodic output signal with the desired frequency, e.g. 1 Hz or 2 Hz, depending on the alert level:
// Attach PWM channel 0 to the GPIO pin to be controlled
ledcAttachPin(PIN_GROVE_YELLOW, 0);
// Activate vibration alarm with desired frequency on PWM channel 0
ledcWriteTone(0, ALARM_FREQ[level]);
AdjustmentsIf you use a different board or a different hardware setup, you need to adjust the hardware pin assignments in the code:
// HW: Pin assignments
const byte PIN_BUTTON = 39; // M5Stack Atom Lite: internal button
const byte PIN_LEDATOM = 27; // M5Stack Atom Lite: internel Neopixel LED
const byte PIN_GROVE_YELLOW = 32; // M5Stack Atom Lite: grove port, yellow cable
Testing the Application using a BLE ClientFor testing the ESP32 BLE alarm application, you need a client application that connects to the ESP32 via Bluetooth Low Energy and writes the Alert Level
characteristic of the Immediate Alert
service. To accomplish this, I used the nRF Connect for Mobile app.
Using this app, you need to perform the following steps:
- Tab
SCANNER
: ActivateSCAN
and connect to theESP32_Alert
device. - Tab
ESP32_Alert
: Unfold theImmediate Alert
service (UUID 0x1802). TheAlert Level
characteristic (UUID 0x2A06) is shown. Activate server notifications, i.e. the icon with three arrows at the right. ActivateWrite value
, select Alert level0x01 (Mild alert)
or0x02 (High alert)
and presssend
. - After the ESP32 has started signalling the alarm, press the button of the ESP32 in order to deactivate the alarm. Thanks to the server notification, the nRF Connect app shows the value
No Alert
again after pressing the ESP32 button.
When the WiFi variant of the application is used, a TCP client is needed to connect to the ESP32. You need to know the IP address and the port to connect to. The IP address and port can be found out e.g. from the Serial Monitor
output of the application.
After the connection is established, you can send the requested alert level as hex value. When sending a different value than 00, 01, or 02 the server reports back the current alert level as hex value.
Second Part of the Project: Android AppPart 2 of this project deals with the development of an Android app that connects to the alarm device and allows the user to change the alarm state. The link to the project description will be included here soon. Its source code is already available here.
LiteratureTo get familiar with Bluetooth Low Energy concepts such as services, characteristics, and descriptors, I found the book Getting Started with Bluetooth Low Energy (O'Reilly) quite helpful, especially Chapter 4.
Comments