DavesCodeMusings / BLE-Battery-Beacon

A proof of concept for using custom Bluetooth Low Energy devices to integrate with Home Assistant
BSD 2-Clause "Simplified" License
0 stars 0 forks source link

Battery level is often "unknown" in Home Assistant #1

Closed DavesCodeMusings closed 2 weeks ago

DavesCodeMusings commented 3 weeks ago

Because the device goes into deep sleep periodically, and sometimes in the middle of polling, ESPHome returns NaN (not a number) for the battery level and Home Assistant shows it as Unknown.

# Sample Log Entries from ESPHome (with Comments)

# ESPHome is polling the Battery Beacon, but is interrupted.
# The Battery Beacon went into deep sleep before the battery level information was fetched.
[12:56:35][D][esp32_ble_client:306]: [0] [1D:EC:AF:CO:FF:EE] Event 46
[12:56:36][D][esp32_ble_client:110]: [0] [1D:EC:AF:CO:FF:EE] ESP_GATTC_SEARCH_CMPL_EVT
[12:56:36][I][esp32_ble_client:227]: [0] [1D:EC:AF:CO:FF:EE] Connected
[12:56:36][D][ble_client:058]: All clients established, services released
[12:56:36][D][esp32_ble_client:188]: [0] [1D:EC:AF:CO:FF:EE] cfg_mtu status 0, mtu 242
[12:57:29][D][esp32_ble_client:110]: [0] [1D:EC:AF:CO:FF:EE] ESP_GATTC_READ_CHAR_EVT
[12:57:29][W][ble_sensor:078]: Error reading char at handle 12, status=133
[12:57:29][D][esp32_ble_client:172]: [0] [1D:EC:AF:CO:FF:EE] ESP_GATTC_DISCONNECT_EVT, reason 8
[12:57:29][D][esp32_ble_client:110]: [0] [1D:EC:AF:CO:FF:EE] ESP_GATTC_CLOSE_EVT
[12:57:29][W][ble_sensor:037]: [ESP32DevkitV1 Battery Level] Disconnected!
[12:57:29][D][sensor:094]: 'ESP32DevkitV1 Battery Level': Sending state nan % with 0 decimals of accuracy
[12:58:24][W][ble_sensor:123]: [ESP32DevkitV1 Battery Level] Cannot poll, not connected

# When the Battery Beacon awoke 2 minutes later, everything was copacetic.
[12:59:23][D][esp32_ble_client:110]: [0] [1D:EC:AF:CO:FF:EE] Found device
[12:59:23][D][esp32_ble_tracker:669]: Found device 1D:EC:AF:CO:FF:EE RSSI=-44
[12:59:23][D][esp32_ble_tracker:690]:   Address Type: PUBLIC
[12:59:23][D][esp32_ble_tracker:692]:   Name: 'ESP32DevkitV1'
[12:59:23][D][esp32_ble_tracker:219]: Pausing scan to make connection...
[12:59:23][D][esp32_ble_tracker:219]: Pausing scan to make connection...
[12:59:23][I][esp32_ble_client:067]: [0] [1D:EC:AF:CO:FF:EE] 0x00 Attempting BLE connection
[12:59:23][D][esp32_ble_client:110]: [0] [1D:EC:AF:CO:FF:EE] ESP_GATTC_CONNECT_EVT
[12:59:23][D][esp32_ble_client:110]: [0] [1D:EC:AF:CO:FF:EE] ESP_GATTC_OPEN_EVT
[12:59:23][I][ble_sensor:031]: [ESP32DevkitV1 Battery Level] Connected successfully!
[12:59:23][D][esp32_ble_tracker:270]: Starting scan...
[12:59:24][W][ble_sensor:123]: [ESP32DevkitV1 Battery Level] Cannot poll, not connected
[12:59:35][D][esp32_ble_client:306]: [0] [1D:EC:AF:CO:FF:EE] Event 46
[12:59:36][D][esp32_ble_client:110]: [0] [1D:EC:AF:CO:FF:EE] ESP_GATTC_SEARCH_CMPL_EVT
[12:59:36][I][esp32_ble_client:227]: [0] [1D:EC:AF:CO:FF:EE] Connected
[12:59:36][D][ble_client:058]: All clients established, services released
[12:59:36][D][esp32_ble_client:188]: [0] [1D:EC:AF:CO:FF:EE] cfg_mtu status 0, mtu 242

# ESPHome is trying to poll the Battery Beacon when it's in deep sleep, and fails.
[13:10:24][W][ble_sensor:123]: [ESP32DevkitV1 Battery Level] Cannot poll, not connected

# The Battery Beacon wakes up a minute later and polling is successful.
[13:11:25][D][esp32_ble_client:110]: [0] [1D:EC:AF:CO:FF:EE] Found device
[13:11:25][D][esp32_ble_tracker:669]: Found device 1D:EC:AF:CO:FF:EE RSSI=-41
[13:11:25][D][esp32_ble_tracker:690]:   Address Type: PUBLIC
[13:11:25][D][esp32_ble_tracker:692]:   Name: 'ESP32DevkitV1'
[13:11:25][D][esp32_ble_tracker:219]: Pausing scan to make connection...
[13:11:25][D][esp32_ble_tracker:219]: Pausing scan to make connection...
[13:11:25][I][esp32_ble_client:067]: [0] [1D:EC:AF:CO:FF:EE] 0x00 Attempting BLE connection
[13:11:26][D][esp32_ble_client:110]: [0] [1D:EC:AF:CO:FF:EE] ESP_GATTC_CONNECT_EVT
[13:11:26][D][esp32_ble_client:110]: [0] [1D:EC:AF:CO:FF:EE] ESP_GATTC_OPEN_EVT
[13:11:26][I][ble_sensor:031]: [ESP32DevkitV1 Battery Level] Connected successfully!
[13:11:26][D][esp32_ble_tracker:270]: Starting scan...
[13:11:38][D][esp32_ble_client:306]: [0] [1D:EC:AF:CO:FF:EE] Event 46
[13:11:39][D][esp32_ble_client:110]: [0] [1D:EC:AF:CO:FF:EE] ESP_GATTC_SEARCH_CMPL_EVT
[13:11:39][I][esp32_ble_client:227]: [0] [1D:EC:AF:CO:FF:EE] Connected
[13:11:39][D][ble_client:058]: All clients established, services released
[13:11:39][D][esp32_ble_client:188]: [0] [1D:EC:AF:CO:FF:EE] cfg_mtu status 0, mtu 242
DavesCodeMusings commented 3 weeks ago

Similar experiments with other GATT characteristics, like Temperature, had the same "unknown" values.

DavesCodeMusings commented 2 weeks ago

The solution most BLE beacons use is to send broadcast data in the advertising header. There is a "manufacturer data" field that can be used for this purpose. There's no standard format. The following code communicates a battery level in the advertisement.

// Manufacturer Data field must include the company ID as the first two octets. Data follows.
// It needs to be in little endian format, so 0x09A3, registered to Arduino SA is 0xA3, 0x09.
// Company ID source: https://www.bluetooth.com/specifications/assigned-numbers/
// Below is the Arduino company ID followed by "BATT:100%" in ASCII.
byte data[11] = { 0xA3, 0x09, 0x42, 0x41, 0x54, 0x54, 0x3A, 0x31, 0x30, 0x30, 0x25};
BLE.setManufacturerData(data, 11);

Using a BLE scanner, like Nordic Semiconductor's nRF, will reveal the Manufacturer Data in the advertisement. Changing the format to Text(UTF-8) shows the "BATT:100%" message.

ESPHome can access it via logging information. https://community.home-assistant.io/t/esp32-ble-tracker-how-to-log-look-at-bluetooth-advertising-data/693925/2

DavesCodeMusings commented 2 weeks ago

Removed ble_client and sensor from ESPHome yaml definition. New version is in: devkitv1_2.yml