ESP32 BLE UART lamp
A Bluetooth LE server with the Nordic UART service: connect from the Bluetooth tab, write on or off to RX, and turn on TX notifications for the reply. The whole build, an ESP32 DevKit and 2 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate Runs in your browser. Free, and no account needed.
The parts retail for about $9.15. On Mokxi they're free.
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// BLE UART lamp: a Bluetooth LE server with the Nordic UART service.
//
// Simulated Bluetooth: a phone in Mokxi, not a real radio. Press Run, open
// the Bluetooth tab and connect to "ESP32 BLE Lamp", like nRF Connect on a
// phone: write on or off to the RX characteristic, and turn on notifications
// on TX to hear back. The same sketch runs on a real ESP32 (Arduino-ESP32 3.x).
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define RX_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define TX_UUID "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
const int kLed = 4; // an LED and a resistor to ground
BLEServer *server = nullptr;
BLECharacteristic *tx = nullptr;
bool connected = false;
bool wasConnected = false;
void say(const String &text)
{
tx->setValue(text);
tx->notify();
}
class ServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer *) override
{
connected = true;
Serial.println("A phone connected.");
}
void onDisconnect(BLEServer *) override
{
connected = false;
Serial.println("The phone disconnected.");
}
};
class RxCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *c) override
{
String value = c->getValue();
value.trim();
value.toLowerCase();
Serial.print("Phone wrote: ");
Serial.println(value);
if (value == "on") {
digitalWrite(kLed, HIGH);
say("lamp on");
} else if (value == "off") {
digitalWrite(kLed, LOW);
say("lamp off");
} else {
say("send on or off");
}
}
};
void setup()
{
Serial.begin(115200);
pinMode(kLed, OUTPUT);
BLEDevice::init("ESP32 BLE Lamp");
server = BLEDevice::createServer();
server->setCallbacks(new ServerCallbacks());
BLEService *service = server->createService(SERVICE_UUID);
tx = service->createCharacteristic(TX_UUID, BLECharacteristic::PROPERTY_NOTIFY);
tx->addDescriptor(new BLE2902());
BLECharacteristic *rx = service->createCharacteristic(RX_UUID, BLECharacteristic::PROPERTY_WRITE);
rx->setCallbacks(new RxCallbacks());
service->start();
BLEAdvertising *advertising = BLEDevice::getAdvertising();
advertising->addServiceUUID(SERVICE_UUID);
BLEDevice::startAdvertising();
Serial.println("Advertising as ESP32 BLE Lamp: connect from the Bluetooth tab.");
}
void loop()
{
// The board stops advertising when a phone connects. Start again once it
// has gone, or nothing can find the board a second time.
if (!connected && wasConnected) {
delay(500);
server->startAdvertising();
Serial.println("Advertising again.");
}
wasConnected = connected;
delay(20);
}
Parts list
3 parts, plus the jumper wires. They retail for about $9.15; on Mokxi they're free.
- 1 × ESP32 DevKit V1
- 1 × Resistor, 220 Ω
- 1 × LED, yellow
How it is wired
3 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.
- ESP32 DevKit V1 pin D4; Resistor, 220 Ω pin 1
- Resistor, 220 Ω pin 2; LED, yellow pin A
- Ground: LED, yellow pin C
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.