The ESP8266 is a legendary Wi-Fi microcontroller, but it has a hard hardware limitation: it lacks native Bluetooth Low Energy (BLE) silicon. If you want to build an ESP8266 BTLE beacon, you cannot do it with the chip alone. You must pair it with an external UART-based BLE module like the HM-10 (based on the TI CC2541) or the AT-09 (CC2640).
In this guide, we will wire a NodeMCU v3 (ESP8266) to an HM-10 module, configure it as an iBeacon via AT commands over software serial, and debug the most common UART handshake failures that stall this build on the bench.
Estimated Time: 45 minutes
Estimated Cost: $7 - $10 (NodeMCU + HM-10 module)
Hardware Reality Check & Parts List
Before wiring anything, let's clear up a common forum misconception. The ESP32 has native BLE. The ESP8266 does not. To broadcast a BTLE beacon payload from an ESP8266, the microcontroller acts as a UART bridge, sending configuration strings to a dedicated BLE radio module. Once configured, the BLE module broadcasts the beacon independently, freeing the ESP8266 to handle Wi-Fi telemetry or sensor polling.
Required Components
- Microcontroller: NodeMCU v3 (ESP-12E variant). Ensure it is the 3.3V logic version (almost all are, but avoid rare 5V-tolerant carrier boards).
- BLE Module: HM-10 (CC2541) or JDY-08. Note: Avoid the AT-09 (CC2640) for this specific code, as its AT command set for iBeacon mode differs slightly.
- Power: High-quality USB cable and a 5V/2A power brick. The ESP8266 Wi-Fi stack combined with the BLE module's TX bursts can cause brownouts on weak PC USB ports.
- Wiring: 4x male-to-female or male-to-male jumper wires (22 AWG stranded).
BLE Beacon Protocol Specifications
When configuring your beacon, you must choose a protocol. The HM-10 module natively supports Apple's iBeacon format via simple AT commands. Below is a data-dense breakdown of the common beacon protocols to help you decide which payload structure fits your application.
| Protocol | ID Structure | Payload Size | Primary Use Case | Default Tx Power |
|---|---|---|---|---|
| iBeacon | 128-bit UUID + 16-bit Major + 16-bit Minor | 21 bytes | Indoor positioning, retail proximity triggers | 0 dBm (adjustable) |
| Eddystone-UID | 10-byte Namespace + 6-byte Instance | 18 bytes | Asset tracking, cross-platform (Android/iOS) | -10 dBm to +4 dBm |
| Eddystone-URL | 17-byte compressed URL (e.g., https://...) | 19 bytes max | Physical web links, digital signage | 0 dBm |
| AltBeacon | 16-byte UUID + 2-byte Major/Minor + 1-byte Mfg Reserved | 24 bytes | Open-source alternative to iBeacon | -20 dBm to +4 dBm |
For this build, we will configure the HM-10 as an iBeacon. The HM-10's firmware has a dedicated AT+IBEA1 command that automatically formats the BLE advertising packet to Apple's specification without requiring the ESP8266 to manually construct the raw BLE headers.
Pin Mapping and Wiring Steps
Because both the ESP8266 and the HM-10 operate at 3.3V logic levels, you do not need a logic level converter. Connecting an HM-10 directly to a 5V Arduino Uno will fry the module's RX pin, but the NodeMCU is perfectly safe for direct connection.
| NodeMCU (ESP8266) Pin | HM-10 / JDY-08 Pin | Wiring Notes & Constraints |
|---|---|---|
| 3V3 | VCC | Do NOT connect to VIN or 5V. The module's internal LDO will overheat. |
| GND | GND | Ensure a solid common ground to prevent UART bit errors. |
| D5 (GPIO14) | TXD | ESP RX listens to BLE TX. GPIO14 is safe for SoftwareSerial RX. |
| D6 (GPIO12) | RXD | ESP TX drives BLE RX. GPIO12 has no boot-strapping conflicts. |
Step-by-Step Wiring Procedure
- De-energize the board: Unplug the NodeMCU from USB before wiring.
- Power connections: Connect NodeMCU 3V3 to HM-10 VCC, and NodeMCU GND to HM-10 GND.
- UART Crossover: Connect NodeMCU D5 to HM-10 TXD. Connect NodeMCU D6 to HM-10 RXD. (Remember: TX always goes to RX).
- Verify: Double-check that no bare wire strands are bridging the 3V3 and GND pins on the HM-10 header.
- Power up: Plug the NodeMCU into your PC. The HM-10 LED should blink rapidly (unconnected state).
Complete Arduino IDE Configuration Code
This code targets the NodeMCU 1.0 (ESP-12E) board variant in the Arduino IDE. It uses SoftwareSerial to communicate with the HM-10. We include a robust sendATCommand helper function with timeout handling and yield() calls to prevent the ESP8266 Watchdog Timer (WDT) from resetting the board during UART delays.
#include <SoftwareSerial.h>
// Target Board: NodeMCU 1.0 (ESP-12E)
// Pin Definitions
#define BLE_RX D5 // GPIO14
#define BLE_TX D6 // GPIO12
SoftwareSerial bleSerial(BLE_RX, BLE_TX);
// Helper function to send AT commands and verify responses
bool sendATCommand(const char* cmd, const char* expected, int timeout_ms) {
bleSerial.print(cmd);
Serial.print("Sent: "); Serial.println(cmd);
unsigned long start = millis();
String response = "";
while (millis() - start < timeout_ms) {
if (bleSerial.available()) {
char c = bleSerial.read();
response += c;
}
yield(); // Prevent ESP8266 WDT reset during wait
}
Serial.print("Recv: "); Serial.println(response);
if (response.indexOf(expected) != -1) {
return true;
}
return false;
}
void setup() {
Serial.begin(115200); // Debug serial
delay(1000);
Serial.println("\n--- ESP8266 BTLE Beacon Configurator ---");
// HM-10 default baud rate is 9600
bleSerial.begin(9600);
// 1. Handshake Test
if (!sendATCommand("AT", "OK", 1000)) {
Serial.println("Error: BLE module timeout - no response to AT handshake");
Serial.println("Check TX/RX crossover and baud rate.");
while(1) { yield(); } // Halt execution safely
}
// 2. Set Role to iBeacon Mode
if (!sendATCommand("AT+IBEA1", "OK", 1000)) {
Serial.println("Error: Failed to enable iBeacon mode.");
}
// 3. Set UUID (Example: Standard proximity UUID)
sendATCommand("AT+UUID0xE2C56DB5DFFB48D2A070C09C010EF501", "OK", 1000);
// 4. Set Major and Minor IDs
sendATCommand("AT+MAJOR0x0001", "OK", 1000);
sendATCommand("AT+MINOR0x0002", "OK", 1000);
// 5. Set Transmit Power (0 = 0dBm, max range)
sendATCommand("AT+POWE0", "OK", 1000);
// 6. Reset module to apply beacon advertising
sendATCommand("AT+RESET", "OK", 2000);
Serial.println("Configuration complete. Module is now broadcasting as an iBeacon.");
Serial.println("Use a BLE scanner app (e.g., nRF Connect) to verify.");
}
void loop() {
// Beacon broadcasting is handled entirely by the HM-10 hardware.
// The ESP8266 is now free to handle Wi-Fi, MQTT, or sensor tasks.
yield();
}
SoftwareSerial if Wi-Fi is actively transmitting. If you plan to add Wi-Fi MQTT code to the loop() later, consider using the hardware Serial.swap() feature to move UART0 to GPIO13/GPIO15 for more reliable BLE communication, though this requires careful management of GPIO15's boot-strapping pull-down resistor.
Debugging: "BLE Init Failed" and Common Errors
If your serial monitor outputs the exact error string: Error: BLE module timeout - no response to AT handshake, the ESP8266 sent the "AT" ping but received no "OK" reply within 1000ms. Do not rewrite the code; this is almost always a physical layer or firmware mismatch.
The First Three Things to Check
- TX/RX Crossover & Baud Rate Mismatch: The HM-10 defaults to 9600 baud. However, many cheap JDY-08 or clone modules ship from the factory configured at 115200 baud. If the handshake fails, change
bleSerial.begin(9600);tobleSerial.begin(115200);and re-upload. Also, verify with a multimeter that continuity exists from D6 to RXD, and D5 to TXD. - Power Supply Brownout: When the HM-10 powers on, it draws a startup spike. If your PC USB port is limited to 500mA and the ESP8266 is simultaneously initializing its Wi-Fi radio, the voltage on the 3V3 rail can drop below 2.8V, causing the BLE module's internal microcontroller to hang before it can initialize the UART peripheral. Plug the NodeMCU into a dedicated 5V/2A wall adapter.
- Firmware Clone Limitations: Genuine HM-10 modules (based on the TI CC2541) support the
AT+IBEA1command. Many sub-$1 clones use a stripped-down firmware that only supports basic SPP (Serial Port Profile) data transmission and ignores beacon commands. If the handshake succeeds (you get "OK") but the module refuses to broadcast as an iBeacon, you have a clone with locked firmware. You must either flash a custom CC2541 firmware via a CC-Debugger or buy a verified genuine module.
Ranked Causes for "Unexpected Response" Errors
If the handshake succeeds but subsequent commands fail (e.g., Error: Failed to enable iBeacon mode):
- Cause 1 (Most Likely): The module is currently in a connected state. If your phone's BLE scanner is actively connected to the HM-10, it will reject AT configuration commands. Disconnect your phone from the module via the app before running the script.
- Cause 2: Missing carriage return. Some firmware revisions require
\r\nat the end of AT commands. ChangebleSerial.print(cmd);tobleSerial.println(cmd);in the helper function. - Cause 3: Corrupted EEPROM on the BLE module. Send
AT+RENEWto factory-reset the HM-10 before attempting the iBeacon configuration sequence.
Simplifying and Extending the Build
The ESP8266 + HM-10 combination is a fantastic learning exercise for UART protocols and BLE advertising payloads, but it requires extra wiring and external components. Here is how to pivot based on your project's end goal.
How to Simplify: Switch to the ESP32
If you are not locked into the ESP8266 hardware, switch to an ESP32 DevKit v1. The ESP32 includes native BLE 4.2 silicon alongside Wi-Fi. You can eliminate the HM-10 module entirely and use the ESP32 BLE Arduino library to broadcast iBeacon or Eddystone payloads directly from the microcontroller's internal radio. This reduces BOM cost by $3, saves breadboard space, and eliminates all SoftwareSerial jitter issues.
How to Extend: Add I2C Telemetry
A static iBeacon only broadcasts IDs. To make this a smart beacon, wire a BME280 I2C sensor to the ESP8266's D1 (SCL) and D2 (SDA) pins. You can read the temperature and humidity, and then use the HM-10's AT+CHAR or custom characteristic commands to inject the sensor data into the BLE advertising payload (using the Eddystone-URL or a custom manufacturer data field). This allows a passing smartphone to read the room's temperature without ever establishing a full BLE connection, saving massive amounts of battery on both the beacon and the receiving device.
For detailed GPIO limitations and strapping pin requirements when adding I2C devices, always consult the official Espressif ESP8266 Pin List documentation to ensure your sensor wiring doesn't conflict with the boot sequence.






