1. Introduction
In this tutorial (2 parts: part 1: GATT server and part 2: GATT client), I will show you how to use BLE (Bluetooth Low Energy) in Arduino ESP32. Firstly, we need to know some basic concepts.Or you can refer here.
- GAP stands for Generic Access Profile. GAP makes your device visible to the other BLE devices (BLE devices can scan your BLE device), and determines how two devices can interact with each other.
- There are 2 kinds of devices in BLE communication: Central devices and Peripheral devices.
+ Peripheral devices are small, low power, resource constrained devices that can connect and give data to to a powerful central device. Example: a heart rate monitor.
+ Central devices are usually the powerful devices like smart phone or tablet. It can scan and connect to any peripheral device that is advertising information to get data from peripheral device.
- When the connection is established between the peripheral and a central device, the advertising process will generally stop and you will use GATT (Generic Attribute Profile) services and characteristics to communicate in both directions.
- GATT is based on a traditional client-server architecture including GATT Server and GATT Client.
- The peripheral device keeps the role as the GATT Server, and the central device keeps the role as GATT Client, which sends requests to this server.
- Beside that GATT also has some concepts called Profiles, Services and Characteristics.
+ Profiles: is a collection of Services.
+ Services: is a collection of characteristic. Service distinguishes from other services by a unique 16-bit numeric ID called a UUID.
+ Characteristics: is data. Characteristic distinguishes from other Characteristics by a unique 16-bit or 128-bit numeric ID called a UUID.
- In this tutorial, I will make a demo using GATT to turn ON/OFF a LED. So ESP32 will act as a GATT server and a GATT client (I use Raspbbery Pi3 with BLE or if your laptop is equipped with BLE you can use it).
2. Software
- We will use LightBlue on iOS or on Android for testing or Bluez Gatttool for Raspberry Pi3 as a GATT client to connect to our ESP32 GATT server.
2.1 Bluez Gatttool for Raspberry Pi3
If the gatttool was not installed on your RPi3 then you can follow these steps to install it:
+ wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.46.tar.xz
+ tar xvf bluez-5.46.tar.xz
+ sudo apt-get install libglib2.0-dev libdbus-1-dev libusb-dev libudev-dev libical-dev systemd libreadline-dev
+ ./configure --enable-library
+ make -j8 && sudo make install
+ sudo cp attrib/gatttool /usr/local/bin/
- Run a BLE scan: sudo hcitool lescan : It will return the MAC address of BLE device
- Connect to the BLE device: sudo gatttool -b BLE_ADDR -I : then type connect to connect. We use sudo hcitool lescan to get BLE_ADDR
Note: If you could not connect after typing connect, you should try typing connect some times.
- List all uuids of services: primary
- List all available handles (Handles are the «connection points» where you can read and write access data): char-desc
- Read from a handle: char-read-hnd
- Write to a handle: char-write-req
2.2 ESP32 GATT server
The role of GATT server:
- Receive the Write command of GATT client and convert it to LED state
- Sending its temperature to GATT client using BLE notification
The name of our ESP32 BLE device is "ESP_GATTS_IOTSHARING" and we will create 1 service GATTS_SERVICE_UUID_TEST_LED with 2 characteristics: GATTS_CHAR_UUID_LED_CTRL and GATTS_CHAR_UUID_TEMP_NOTI.
The characteristic GATTS_CHAR_UUID_LED_CTRL with read and write permission to write the LED control command to it and to read the data from BLE device (For testing the read request only returns "iotsharing.com" string).
The characteristic GATTS_CHAR_UUID_TEMP_NOTI with notification permission that enable the GATT client to register BLE notification to receive the temperature data of the GATT server.
I also wrote many comments in the code, so you can read and map them with theory above.
3. Result
3.1 Using LightBlue to connect to GATT server
If using Bluez Gatttool for Raspberry Pi3:
- Using sudo hcitool lescan to get the address of my BLE device. It is 30:AE:A4:02:70:76. Then I used sudo gatttool -b 30:AE:A4:02:70:76 -I to establish connection to it.
- Using char-desc command we will see our characteristic uuids that we set in the code, are aa01 and bb01 with handles are 0x002a and 0x002c. So we just operate on these handles with commands below.
In this tutorial (2 parts: part 1: GATT server and part 2: GATT client), I will show you how to use BLE (Bluetooth Low Energy) in Arduino ESP32. Firstly, we need to know some basic concepts.Or you can refer here.
- GAP stands for Generic Access Profile. GAP makes your device visible to the other BLE devices (BLE devices can scan your BLE device), and determines how two devices can interact with each other.
- There are 2 kinds of devices in BLE communication: Central devices and Peripheral devices.
+ Peripheral devices are small, low power, resource constrained devices that can connect and give data to to a powerful central device. Example: a heart rate monitor.
+ Central devices are usually the powerful devices like smart phone or tablet. It can scan and connect to any peripheral device that is advertising information to get data from peripheral device.
- When the connection is established between the peripheral and a central device, the advertising process will generally stop and you will use GATT (Generic Attribute Profile) services and characteristics to communicate in both directions.
- GATT is based on a traditional client-server architecture including GATT Server and GATT Client.
- The peripheral device keeps the role as the GATT Server, and the central device keeps the role as GATT Client, which sends requests to this server.
- Beside that GATT also has some concepts called Profiles, Services and Characteristics.
+ Profiles: is a collection of Services.
+ Services: is a collection of characteristic. Service distinguishes from other services by a unique 16-bit numeric ID called a UUID.
+ Characteristics: is data. Characteristic distinguishes from other Characteristics by a unique 16-bit or 128-bit numeric ID called a UUID.
Figure: Example of Hear Rate Profile
- In this tutorial, I will make a demo using GATT to turn ON/OFF a LED. So ESP32 will act as a GATT server and a GATT client (I use Raspbbery Pi3 with BLE or if your laptop is equipped with BLE you can use it).
2. Software
- We will use LightBlue on iOS or on Android for testing or Bluez Gatttool for Raspberry Pi3 as a GATT client to connect to our ESP32 GATT server.
2.1 Bluez Gatttool for Raspberry Pi3
If the gatttool was not installed on your RPi3 then you can follow these steps to install it:
+ wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.46.tar.xz
+ tar xvf bluez-5.46.tar.xz
+ sudo apt-get install libglib2.0-dev libdbus-1-dev libusb-dev libudev-dev libical-dev systemd libreadline-dev
+ ./configure --enable-library
+ make -j8 && sudo make install
+ sudo cp attrib/gatttool /usr/local/bin/
- Run a BLE scan: sudo hcitool lescan : It will return the MAC address of BLE device
- Connect to the BLE device: sudo gatttool -b BLE_ADDR
- List all uuids of services: primary
- List all available handles (Handles are the «connection points» where you can read and write access data): char-desc
- Read from a handle: char-read-hnd
- Write to a handle: char-write-req
2.2 ESP32 GATT server
The role of GATT server:
- Receive the Write command of GATT client and convert it to LED state
- Sending its temperature to GATT client using BLE notification
The name of our ESP32 BLE device is "ESP_GATTS_IOTSHARING" and we will create 1 service GATTS_SERVICE_UUID_TEST_LED with 2 characteristics: GATTS_CHAR_UUID_LED_CTRL and GATTS_CHAR_UUID_TEMP_NOTI.
The characteristic GATTS_CHAR_UUID_LED_CTRL with read and write permission to write the LED control command to it and to read the data from BLE device (For testing the read request only returns "iotsharing.com" string).
The characteristic GATTS_CHAR_UUID_TEMP_NOTI with notification permission that enable the GATT client to register BLE notification to receive the temperature data of the GATT server.
I also wrote many comments in the code, so you can read and map them with theory above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | #pragma GCC diagnostic push #pragma GCC diagnostic warning "-fpermissive" #include <stdio.h> #include <stdlib.h> #include <string.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_system.h" #include "esp_log.h" #include "nvs_flash.h" #include "bt.h" #include "bta_api.h" #include "esp_gap_ble_api.h" #include "esp_gatts_api.h" #include "esp_bt_defs.h" #include "esp_bt_main.h" #include "esp_bt_main.h" #include "sdkconfig.h" #pragma GCC diagnostic pop /* this function will be invoked to handle incomming events */ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); #define LED 4 #define GATTS_SERVICE_UUID_TEST_LED 0xAABB #define GATTS_CHAR_UUID_LED_CTRL 0xAA01 #define GATTS_CHAR_UUID_TEMP_NOTI 0xBB01 #define GATTS_NUM_HANDLES 8 #define TEST_DEVICE_NAME "ESP_GATTS_IOTSHARING" /* maximum value of a characteristic */ #define GATTS_DEMO_CHAR_VAL_LEN_MAX 0xFF /* profile info */ #define PROFILE_ON_APP_ID 0 /* characteristic ids for led ctrl and temp noti */ #define CHAR_NUM 2 #define CHARACTERISTIC_LED_CTRL_ID 0 #define CHARACTERISTIC_TEMP_NOTI_ID 1 /* value range of a attribute (characteristic) */ uint8_t attr_str[] = {0x00}; esp_attr_value_t gatts_attr_val = { .attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX, .attr_len = sizeof(attr_str), .attr_value = attr_str, }; /* custom uuid */ static uint8_t service_uuid128[32] = { /* LSB <--------------------------------------------------------------------------------> MSB */ //first uuid, 16bit, [12],[13] is the value 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0x00, 0x00, }; static esp_ble_adv_data_t test_adv_data = { .set_scan_rsp = false, .include_name = true, .include_txpower = true, .min_interval = 0x20, .max_interval = 0x40, .appearance = 0x00, .manufacturer_len = 0, .p_manufacturer_data = NULL, .service_data_len = 0, .p_service_data = NULL, .service_uuid_len = 16, .p_service_uuid = service_uuid128, .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), }; //this variable holds advertising parameters esp_ble_adv_params_t test_adv_params; //this structure holds the information of characteristic struct gatts_characteristic_inst{ esp_bt_uuid_t char_uuid; esp_bt_uuid_t descr_uuid; uint16_t char_handle; esp_gatt_perm_t perm; esp_gatt_char_prop_t property; uint16_t descr_handle; }; //this structure holds the information of current BLE connection struct gatts_profile_inst { esp_gatts_cb_t gatts_cb; uint16_t gatts_if; uint16_t app_id; uint16_t conn_id; uint16_t service_handle; esp_gatt_srvc_id_t service_id; struct gatts_characteristic_inst chars[CHAR_NUM]; }; //this variable holds the information of current BLE connection static struct gatts_profile_inst test_profile; /* This callback will be invoked when GAP advertising events come. Refer GAP BLE callback event type here: https://github.com/espressif/esp-idf/blob/master/components/bt/bluedroid/api/include/esp_gap_ble_api.h */ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { switch (event) { case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: esp_ble_gap_start_advertising(&test_adv_params); break; case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: esp_ble_gap_start_advertising(&test_adv_params); break; case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: esp_ble_gap_start_advertising(&test_adv_params); break; case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: //advertising start complete event to indicate advertising start successfully or failed if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { Serial.printf("\nAdvertising start failed\n"); } break; case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) { Serial.printf("\nAdvertising stop failed\n"); } else { Serial.printf("\nStop adv successfully\n"); } break; default: break; } } //process BLE write event ESP_GATTS_WRITE_EVT void process_write_event_env(esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param){ /* check char handle and set LED */ if(test_profile.chars[CHARACTERISTIC_LED_CTRL_ID].char_handle == param->write.handle){ if(param->write.len == 1){ uint8_t state = param->write.value[0]; digitalWrite(LED, state); } } /* send response if any */ if (param->write.need_rsp){ Serial.printf("respond"); esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL); if (response_err != ESP_OK){ Serial.printf("\nSend response error\n"); } } } /* This callback will will be invoked when GATT BLE events come. Refer GATT Server callback function events here: https://github.com/espressif/esp-idf/blob/master/components/bt/bluedroid/api/include/esp_gatts_api.h */ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { switch (event) { //When register application id, the event comes case ESP_GATTS_REG_EVT:{ Serial.printf("\nREGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); test_profile.service_id.is_primary = true; test_profile.service_id.id.inst_id = 0x00; test_profile.service_id.id.uuid.len = ESP_UUID_LEN_16; test_profile.service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_LED; //after finishing registering, the ESP_GATTS_REG_EVT event comes, we start the next step is creating service esp_ble_gatts_create_service(gatts_if, &test_profile.service_id, GATTS_NUM_HANDLES); break; } case ESP_GATTS_READ_EVT: { Serial.printf("\nESP_GATTS_READ_EVT\n"); esp_gatt_rsp_t rsp; memset(&rsp, 0, sizeof(esp_gatt_rsp_t)); rsp.attr_value.handle = param->read.handle; rsp.attr_value.len = 14; rsp.attr_value.value[0] = 105; rsp.attr_value.value[1] = 111; rsp.attr_value.value[2] = 116; rsp.attr_value.value[3] = 115; rsp.attr_value.value[4] = 104; rsp.attr_value.value[5] = 97; rsp.attr_value.value[6] = 114; rsp.attr_value.value[7] = 105; rsp.attr_value.value[8] = 110; rsp.attr_value.value[9] = 103; rsp.attr_value.value[10] = 46; rsp.attr_value.value[11] = 99; rsp.attr_value.value[12] = 111; rsp.attr_value.value[13] = 109; /* When central device send READ request to GATT server, the ESP_GATTS_READ_EVT comes This always responds "iotsharing.com" string */ esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp); break; } /* When central device send WRITE request to GATT server, the ESP_GATTS_WRITE_EVT comes Invoking process_write_event_env() to process and send response if any */ case ESP_GATTS_WRITE_EVT: { Serial.printf("\nESP_GATTS_WRITE_EVT\n"); process_write_event_env(gatts_if, param); break; } // When create service complete, the event comes case ESP_GATTS_CREATE_EVT:{ Serial.printf("\nstatus %d, service_handle %x, service id %x\n", param->create.status, param->create.service_handle, param->create.service_id.id.uuid.uuid.uuid16); // store service handle and add characteristics test_profile.service_handle = param->create.service_handle; // LED controller characteristic esp_ble_gatts_add_char(test_profile.service_handle, &test_profile.chars[CHARACTERISTIC_LED_CTRL_ID].char_uuid, test_profile.chars[CHARACTERISTIC_LED_CTRL_ID].perm, test_profile.chars[CHARACTERISTIC_LED_CTRL_ID].property, &gatts_attr_val, NULL); // temperature monitoring characteristic esp_ble_gatts_add_char(test_profile.service_handle, &test_profile.chars[CHARACTERISTIC_TEMP_NOTI_ID].char_uuid, test_profile.chars[CHARACTERISTIC_TEMP_NOTI_ID].perm, test_profile.chars[CHARACTERISTIC_TEMP_NOTI_ID].property, &gatts_attr_val, NULL); //and start service esp_ble_gatts_start_service(test_profile.service_handle); break; } //When add characteristic complete, the event comes case ESP_GATTS_ADD_CHAR_EVT: { Serial.printf("\nADD_CHAR_EVT, status %d, attr_handle %x, service_handle %x, char uuid %x\n", param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle, param->add_char.char_uuid.uuid.uuid16); /* store characteristic handles for later usage */ if(param->add_char.char_uuid.uuid.uuid16 == GATTS_CHAR_UUID_LED_CTRL){ test_profile.chars[CHARACTERISTIC_LED_CTRL_ID].char_handle = param->add_char.attr_handle; }else if(param->add_char.char_uuid.uuid.uuid16 == GATTS_CHAR_UUID_TEMP_NOTI){ test_profile.chars[CHARACTERISTIC_TEMP_NOTI_ID].char_handle = param->add_char.attr_handle; } //if having characteristic description calling esp_ble_gatts_add_char_descr() here break; } //When add descriptor complete, the event comes case ESP_GATTS_ADD_CHAR_DESCR_EVT:{ Serial.printf("\nESP_GATTS_ADD_CHAR_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n", param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); break; } /* when disconneting, send advertising information again */ case ESP_GATTS_DISCONNECT_EVT:{ esp_ble_gap_start_advertising(&test_adv_params); break; } // When gatt client connect, the event comes case ESP_GATTS_CONNECT_EVT: { Serial.printf("\nESP_GATTS_CONNECT_EVT\n"); esp_ble_conn_update_params_t conn_params = {0}; memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t)); /* For the IOS system, please reference the apple official documents about the ble connection parameters restrictions. */ conn_params.latency = 0; conn_params.max_int = 0x50; // max_int = 0x50*1.25ms = 100ms conn_params.min_int = 0x30; // min_int = 0x30*1.25ms = 60ms conn_params.timeout = 1000; // timeout = 1000*10ms = 10000ms test_profile.conn_id = param->connect.conn_id; //start sent the update connection parameters to the peer device. esp_ble_gap_update_conn_params(&conn_params); break; } default: break; } } static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { /* If event is register event, store the gatts_if for the profile */ if (event == ESP_GATTS_REG_EVT) { if (param->reg.status == ESP_GATT_OK) { test_profile.gatts_if = gatts_if; } else { Serial.printf("\nReg app failed, app_id %04x, status %d\n", param->reg.app_id, param->reg.status); return; } } /* here call each profile's callback */ if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ gatts_if == test_profile.gatts_if) { if (test_profile.gatts_cb) { test_profile.gatts_cb(event, gatts_if, param); } } } void setup(){ Serial.begin(115200); pinMode(LED, OUTPUT); digitalWrite(LED, LOW); /* initialize advertising info */ test_adv_params.adv_int_min = 0x20; test_adv_params.adv_int_max = 0x40; test_adv_params.adv_type = ADV_TYPE_IND; test_adv_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC; test_adv_params.channel_map = ADV_CHNL_ALL; test_adv_params.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; /* initialize profile and characteristic permission and property*/ test_profile.gatts_cb = gatts_profile_event_handler; test_profile.gatts_if = ESP_GATT_IF_NONE; test_profile.chars[CHARACTERISTIC_LED_CTRL_ID].char_uuid.len = ESP_UUID_LEN_16; test_profile.chars[CHARACTERISTIC_LED_CTRL_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_LED_CTRL; test_profile.chars[CHARACTERISTIC_LED_CTRL_ID].perm = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; test_profile.chars[CHARACTERISTIC_LED_CTRL_ID].property = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE; test_profile.chars[CHARACTERISTIC_TEMP_NOTI_ID].char_uuid.len = ESP_UUID_LEN_16; test_profile.chars[CHARACTERISTIC_TEMP_NOTI_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEMP_NOTI; test_profile.chars[CHARACTERISTIC_TEMP_NOTI_ID].perm = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; test_profile.chars[CHARACTERISTIC_TEMP_NOTI_ID].property = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY; esp_err_t ret; /* initialize BLE and bluedroid */ btStart(); ret = esp_bluedroid_init(); if (ret) { Serial.printf("\n%s init bluetooth failed\n", __func__); return; } ret = esp_bluedroid_enable(); if (ret) { Serial.printf("\n%s enable bluetooth failed\n", __func__); return; } // set BLE name and broadcast advertising info so that the world can see you esp_ble_gap_set_device_name(TEST_DEVICE_NAME); esp_ble_gap_config_adv_data(&test_adv_data); // register callbacks to handle events of GAp and GATT esp_ble_gatts_register_callback(gatts_event_handler); esp_ble_gap_register_callback(gap_event_handler); // register profiles with app id esp_ble_gatts_app_register(CHARACTERISTIC_LED_CTRL_ID); } long lastMsg = 0; //send temperature value to registered notification client every 5 seconds via GATT notification void loop(){ long now = millis(); if (now - lastMsg > 5000) { lastMsg = now; uint8_t temp = random(0, 50); esp_ble_gatts_send_indicate(test_profile.gatts_if, test_profile.conn_id, test_profile.chars[CHARACTERISTIC_TEMP_NOTI_ID].char_handle, sizeof(temp), &temp, false); } } |
3.1 Using LightBlue to connect to GATT server
Figure: 2 characteristics with uuid AA01 and BB01
Fifure: Choose Write to write value to GATT server
Figure: Choose 1 or 0 to turn ON/OFF LED
Figure: press Listen for notifications to receive temp data
Figure: Temp data are 0x25, 0x27, 0x04, ...
3.2 Using Bluez Gatttool + Raspberry Pi3 to connect to GATT server If using Bluez Gatttool for Raspberry Pi3:
- Using sudo hcitool lescan to get the address of my BLE device. It is 30:AE:A4:02:70:76. Then I used sudo gatttool -b 30:AE:A4:02:70:76 -I to establish connection to it.
- Using char-desc command we will see our characteristic uuids that we set in the code, are aa01 and bb01 with handles are 0x002a and 0x002c. So we just operate on these handles with commands below.
Figure: Available characteristics
Figure: write data to ESP32 BLE
1 Comments