What is Bluetooth?
The tinyCore ESP32-S3 has built-in Bluetooth Low Energy (BLE) — a wireless protocol designed for low-power, short-range communication with phones, computers, and other devices. BLE is how fitness trackers send step counts to your phone, how wireless game controllers connect to PCs, and how smart home sensors report data.
Why This Matters for Your Projects
Section titled “Why This Matters for Your Projects”BLE lets your tinyCore talk to phones and computers without WiFi or a router. Build a phone-controlled RGB light, stream sensor data to a custom app, or turn the tinyCore into a wireless game controller that any PC or phone recognizes as a standard Bluetooth device. All without installing special drivers.
BLE vs Classic Bluetooth
Section titled “BLE vs Classic Bluetooth”How BLE Works
Section titled “How BLE Works”Peripheral vs Central
Section titled “Peripheral vs Central”BLE defines two primary roles:
- Peripheral (your tinyCore) — advertises its presence and accepts connections
- Central (your phone) — scans for peripherals and initiates connections
Your tinyCore broadcasts short advertising packets saying “I’m here, this is what I do.” A phone scanning nearby detects these packets and can connect.
Services and Characteristics (GATT)
Section titled “Services and Characteristics (GATT)”Once connected, data is organized into a hierarchy called GATT (Generic Attribute Profile):
| Level | What It Is | Example |
|---|---|---|
| Service | A group of related data, identified by a UUID | ”Environmental Sensing” |
| Characteristic | A single data value with read/write/notify properties | ”Temperature” |
| Descriptor | Metadata about the characteristic | ”Enable notifications” |
Your tinyCore acts as the GATT Server — it holds the data. Your phone acts as the GATT Client — it reads, writes, or subscribes to updates.
When a characteristic has the Notify property, the tinyCore pushes updates to the phone automatically — no polling needed. This is how fitness trackers stream heart rate data in real time.
Advertising
Section titled “Advertising”Before any connection happens, the tinyCore broadcasts advertising packets on three dedicated channels. These packets carry up to 31 bytes of data — enough for a device name, service UUIDs, and basic info. The advertising interval is configurable (20 ms to 10.24 seconds): shorter = faster discovery but higher power draw.
What You Can Build
Section titled “What You Can Build”Phone-controlled hardware. The tinyCore exposes a writable characteristic; your phone app sends color values, speed commands, or control signals. The firmware reads them and drives LEDs, motors, or relays.
Sensor data streaming to phone. Read a sensor on the tinyCore, update a characteristic, and notify the connected phone in real time. This is how commercial fitness trackers and environmental monitors work.
Wireless game controllers. Using the HID over GATT profile, the tinyCore can appear as a standard BLE gamepad or keyboard to PCs, phones, and TVs. The ESP32-BLE-Gamepad library supports up to 128 buttons and multiple axes.
Proximity triggers. Scan for BLE advertisements and read the RSSI (signal strength). When a known device gets close enough, trigger an action — unlock a door, turn on lights, start a display.
BLE sensor gateway. The tinyCore can also act as a Central, connecting to external BLE sensors (heart rate monitors, environmental sensors) and aggregating their data.
Phone Apps for BLE
Section titled “Phone Apps for BLE”nRF Connect (Nordic Semiconductor) — the standard BLE debugging tool. Scans devices, shows raw advertising data, lets you browse services, read/write characteristics, and subscribe to notifications. Free on Android and iOS. Start here when testing your BLE project.
LightBlue (Punch Through) — similar to nRF Connect, plus a virtual peripheral mode that turns your phone into a simulated BLE device. Free on iOS, macOS, and Android.
MIT App Inventor — build custom Android apps with drag-and-drop blocks that talk to your tinyCore over BLE. Uses an official BluetoothLE extension.
Flutter / React Native — for production apps, use flutter_reactive_ble (maintained by Philips Hue) or react-native-ble-plx for cross-platform BLE.
On the tinyCore (ESP32-S3)
Section titled “On the tinyCore (ESP32-S3)”BLE 5.0
Section titled “BLE 5.0”The ESP32-S3 supports BLE 5.0 with 2M PHY (2 Mbps for faster transfers), Coded PHY (extended range at lower speed), and extended advertising.
NimBLE vs Bluedroid
Section titled “NimBLE vs Bluedroid”Two BLE stacks are available. NimBLE is strongly recommended — it uses roughly half the flash space and frees ~100 KB more RAM than Bluedroid:
| Bluedroid | NimBLE | |
|---|---|---|
| Flash usage | ~1,216 KB | ~617 KB |
| Free heap after connection | ~171 KB | ~270 KB |
| Max connections | 7 | 9 |
For Arduino, install the NimBLE-Arduino library (by h2zero) as a drop-in replacement for the default BLE library.
| State | Current |
|---|---|
| Deep sleep | ~8 µA |
| BLE TX (0 dBm) | ~100–130 mA |
| Advertising (between packets) | ~100 mA without light sleep |
Typical indoor range is 10–30 meters with standard 1M PHY.
Common Problems and Fixes
Section titled “Common Problems and Fixes”Device not showing up on phone scans
- Verify
startAdvertising()is actually being called in your code - Keep device names under 15 characters (the 31-byte advertising packet fills up fast)
- Android requires Location permission (
BLUETOOTH_SCANon Android 12+) — without it, scans silently return nothing
GATT stale cache (the invisible killer) When you change your firmware’s services or characteristics and re-flash, the phone still uses its cached GATT layout from before. Everything looks connected but data doesn’t flow correctly.
- Android fix: Settings → Apps → Bluetooth → Storage → Clear Cache
- iOS fix: “Forget This Device” in Bluetooth settings, then reconnect
Connection drops
- Increase supervision timeout to 2–4 seconds
- Check for 2.4 GHz interference (WiFi, microwaves)
- Don’t call
delay()inside BLE callbacks — it can trigger watchdog resets - Check Serial Monitor for reboot messages
iOS quirks
- iOS does not show BLE devices in system Bluetooth settings — users must connect through your app or nRF Connect
- iOS hides the real MAC address, assigning a random per-app identifier instead
- iOS aggressively caches GATT tables with no user-facing way to clear
- MTU negotiation: iOS handles it automatically, but on Android you must call
requestMtu(). Default MTU is 23 bytes (20 usable) — if you’re sending more than 20 bytes per write without negotiating a larger MTU, data gets silently truncated
Quick Reference
Section titled “Quick Reference”| Feature | ESP32-S3 |
|---|---|
| BLE version | 5.0 |
| Classic Bluetooth | Not supported |
| PHY modes | 1M, 2M, Coded |
| Max TX power | 20 dBm |
| Indoor range | 10–30 m (1M PHY) |
| Recommended stack | NimBLE |
| Max connections (NimBLE) | 9 |
| Arduino library | NimBLE-Arduino (by h2zero) |
Learn More
Section titled “Learn More”- Connect to Bluetooth — hands-on BLE tutorial
- Dabble App — phone app for BLE control
- What is WiFi? — when you need internet instead
- What is ESP-NOW? — when you need board-to-board communication
Video: ESP32 Bluetooth Overview
Section titled “Video: ESP32 Bluetooth Overview”DroneBot Workshop — ~38 minutes. Covers BLE vs Classic differences, GAP/GATT concepts, and hands-on Arduino IDE examples for BLE server and client. Companion article with downloadable code at dronebotworkshop.com.