Skip to main content

Bluetooth Low Energy (BLE)

BLE

This example uses the Bluetooth Low Energy (BLE) function of ESP32. Since there is no special library for BLE, BLE communication is performed using the AT parser. In ESP32's initial firmware, the following GATT profile is prepared.


GATT Profile

UUID Access Property Size (Bytes) Characteristic Number
A002 Read 2 -
C300 Read 1 1
C301 Read 512 2
C302 Write 1 3
C303 Write Without Response 3 4
C304 Write 2 5
C305 Notify 5 6
C306 Indicate 5 7

Example

In this example, the GR-LYCHEE board is a server and a smartphone acts as a client. After executing the program, try using the iPhone application Light Blue.


#include <Arduino.h>
#include "ESP32.h"
    
BufferedSerial esp32(P7_1, P0_1, 1024);
ATParser_os esp_parser(esp32);
DigitalOut esp_en(P5_3);
DigitalOut esp_io0(P3_14);
DigitalOut led_green(LED1);
DigitalOut led_yellow(LED2);
DigitalOut led_orange(LED3);
DigitalOut led_red(LED4);
InterruptIn button0(USER_BUTTON0);
InterruptIn button1(USER_BUTTON1);
Semaphore event_sem(0);
    
const char ble_name[] = "GR-LYCHEE";
bool ble_advertizing;
bool ble_connected;
uint8_t ble_conn_index;
uint8_t ble_srv_index;
    
bool button0_flag = false;
bool button1_flag = false;
uint8_t ble_notification_on = false;
    
void esp32_event() {
    event_sem.release();
}
    
void ble_client_read() {
    uint8_t mac[6] = {0};
    led_yellow = 1;
    esp_parser.recv("%hhd,\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\"", &ble_conn_index, &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
    printf("%d, mac[%x:%x:%x:%x:%x:%x]\r\n", ble_conn_index, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    led_yellow = 0;
}
    
void ble_client_write() {
    uint8_t char_index, desc_index;
    led_orange = 1;
    esp_parser.recv("%hhd,%hhd,%hhd,", &ble_conn_index, &ble_srv_index, &char_index);
    printf("conn=%d srv=%d char=%d\r\n", ble_conn_index, ble_srv_index, char_index);
    char c = esp_parser.getc();
    if( c != ','){
        desc_index = c;
        esp_parser.getc(); // to read ',' after desc_index.
        printf("desc=%d\r\n", desc_index);
    }
    uint16_t len;
    esp_parser.recv("%hhd,", &len);
    printf("length=%d\r\n", len);
    for (int i = 0; i < len; i++) {
        uint8_t value = esp_parser.getc();
        printf("%x\r\n", value);
    }
    led_orange = 0;
}
    
void ble_client_disconn(){
    led_green = 0;
    ble_connected = false;
}
    
void ble_client_conn(){
    uint8_t mac[6] = {0};
    esp_parser.recv("%hhd,\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\"", &ble_conn_index, &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
    printf("connected client %d, mac[%x:%x:%x:%x:%x:%x]\r\n", ble_conn_index, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    
    led_green = 1;
    ble_advertizing = false;
    ble_connected = true;
}
    
void ub0_interrupt(){
    if(button0_flag == false){
        button0_flag = true;
        event_sem.release();
    }
}
    
void ub1_interrupt(){
    if(button1_flag == false){
        button1_flag = true;
        event_sem.release();
    }
}
    
void setup() {
    
    printf("Bluetooth sample started\r\n");
    led_green = 0;
    led_yellow = 0;
    led_orange = 0;
    led_red = 0;
    ble_advertizing = false;
    ble_connected = false;
    button0.fall(ub0_interrupt);
    button1.fall(ub1_interrupt);
    
    // Initializing esp32 access
    esp32.baud(115200);
    esp32.attach(Callback(esp32_event));
    esp_io0 = 1;
    esp_en = 0;
    Thread::wait(10);
    esp_en = 1;
    esp_parser.setTimeout(1500);
    if (esp_parser.recv("ready")) {
        printf("ESP32 ready\r\n");
    } else {
        printf("ESP32 error\r\n");
        led_red = 1;
        while (1);
    }
    
    // Initializing esp32 as a server with GATT service
    esp_parser.setTimeout(5000);
    if (esp_parser.send("AT+BLEINIT=2") && esp_parser.recv("OK")
            && esp_parser.send("AT+BLENAME=\"%s\"", ble_name) && esp_parser.recv("OK")
            && esp_parser.send("AT+BLEGATTSSRVCRE") && esp_parser.recv("OK")
            && esp_parser.send("AT+BLEGATTSSRVSTART") && esp_parser.recv("OK")){
        printf("GATT initialized\r\n");
    } else {
        printf("fail to initialize");
        led_red = 1;
        while (1);
    }
    esp_parser.oob("+READ:", ble_client_read);
    esp_parser.oob("+WRITE:", ble_client_write);
    esp_parser.oob("+BLEDISCONN:", ble_client_disconn);
    esp_parser.oob("+BLECONN:", ble_client_conn);
    
    while (1) {
        if (esp_parser.send("AT+BLEADVSTART") && esp_parser.recv("OK")){
            printf("Advertising started, please connect to any client\r\n");
        } else {
            printf("fail to start advertising");
            led_red = 1;
            while (1);
        }
    
        ble_advertizing = true;
    
        uint8_t start, type;
        uint16_t uuid;
        esp_parser.send("AT+BLEGATTSSRV?");
        if(esp_parser.recv("+BLEGATTSSRV:%hhd,%hhd,%hhx,%hhd\r\nOK", &ble_srv_index, &start, &uuid, &type)){
            printf("srv_index=%d\r\n", ble_srv_index);
        } else {
            printf("fail to get service");
            led_red = 1;
        }
    
        while (ble_connected || ble_advertizing) {
            event_sem.wait();
            esp_parser.setTimeout(5);
            esp_parser.recv(" ");  //dummy read for parser callback
    
            if(button0_flag){
                static uint8_t data = 1; // write data
                esp_parser.setTimeout(5000);
                if(esp_parser.send("AT+BLEGATTSSETATTR=%d,1,,1", ble_srv_index) && esp_parser.recv(">")){
                    if(esp_parser.putc(data) && esp_parser.recv("OK")){
                        printf("success to send\r\n");
                    } else {
                        printf("fail to send\r\n");
                    }
                } else {
                    printf("fail to command AT");
                }
                esp_parser.flush();
                button0_flag = false;
                data++;
            }
        }
    }
}
    
void loop() {
    
}