Bluetooth Serial on ESP32
The BluetoothSerial library makes the ESP32’s Bluetooth Classic radio behave like a serial port — the same read(), print(), and println() methods you already know from Serial. This is perfect for replacing an HC-05/HC-06 module, building a wireless serial monitor, or controlling an ESP32 from an Android app.
Echo Server — Send What You Receive
#include "BluetoothSerial.h"
BluetoothSerial SerialBT;
void setup() {
Serial.begin(115200);
SerialBT.begin("ESP32-Device"); // Bluetooth device name
Serial.println("Bluetooth started — pair with 'ESP32-Device'");
}
void loop() {
// Forward USB Serial → Bluetooth
if (Serial.available()) {
SerialBT.write(Serial.read());
}
// Forward Bluetooth → USB Serial
if (SerialBT.available()) {
char c = SerialBT.read();
Serial.write(c);
SerialBT.write(c); // echo back
}
}
Command Parser
A practical pattern: read a full line of text and parse it as a command:
#include "BluetoothSerial.h"
BluetoothSerial SerialBT;
const int LED = 2;
void handleCommand(String cmd) {
cmd.trim();
cmd.toLowerCase();
if (cmd == "on") {
digitalWrite(LED, HIGH);
SerialBT.println("LED turned ON");
}
else if (cmd == "off") {
digitalWrite(LED, LOW);
SerialBT.println("LED turned OFF");
}
else if (cmd == "status") {
SerialBT.printf("LED: %s | Uptime: %lus\n",
digitalRead(LED) ? "ON" : "OFF", millis() / 1000);
}
else {
SerialBT.println("Unknown command. Try: on, off, status");
}
}
void setup() {
Serial.begin(115200);
pinMode(LED, OUTPUT);
SerialBT.begin("ESP32-Control");
Serial.println("Bluetooth ready");
}
void loop() {
if (SerialBT.available()) {
String line = SerialBT.readStringUntil('\n');
handleCommand(line);
}
}
Setting a Pairing PIN
#include "BluetoothSerial.h"
BluetoothSerial SerialBT;
void setup() {
Serial.begin(115200);
SerialBT.setPin("1234"); // set before begin()
SerialBT.begin("SecureESP32");
Serial.println("PIN: 1234");
}
ESP32 as Bluetooth Master (Connect to HC-05)
#include "BluetoothSerial.h"
BluetoothSerial SerialBT;
// Replace with your HC-05 MAC address (printed on module or found via scan)
uint8_t target_mac[6] = {0x00, 0x21, 0x09, 0x00, 0xBE, 0xEF};
void setup() {
Serial.begin(115200);
SerialBT.begin("ESP32-Master", true); // true = master mode
Serial.println("Connecting to HC-05...");
bool connected = SerialBT.connect(target_mac);
if (connected) {
Serial.println("Connected!");
} else {
Serial.println("Failed — check MAC and pairing");
}
}
void loop() {
if (SerialBT.available()) Serial.write(SerialBT.read());
if (Serial.available()) SerialBT.write(Serial.read());
}
Connection Event Callback
void btCallback(esp_spp_cb_event_t event, esp_spp_cb_param_t* param) {
if (event == ESP_SPP_SRV_OPEN_EVT) {
Serial.println("Client connected");
SerialBT.println("Welcome to ESP32!");
}
if (event == ESP_SPP_CLOSE_EVT) {
Serial.println("Client disconnected");
}
}
// In setup(), before SerialBT.begin():
SerialBT.register_callback(btCallback);
Android Apps for Testing
- Serial Bluetooth Terminal (Google Play) — clean terminal, supports newline modes, timestamps
- Bluetooth Serial Monitor — shows raw bytes and ASCII side-by-side
- MIT App Inventor — build a custom app with buttons that send commands over BT Classic
Transitioning to BLE
If you need iOS support, lower power consumption, or compatibility with modern wearables, migrate to the BLE guide which uses GATT services instead of SPP.