Battery Level from Beacon?

Hi
just started with ESPHome on ESP32 for my presence detection project.

Just received the beacons using a nRF52810 chipset and simple on/off detection is working fine. Nevertheless I could not use ble_presence as binary sensor platform because the off-state isn´t published in time and could not find any detailed information. So realized by using ble advertisting and lambda this way:

sensor:
  # RSSI based on MAC address
  - platform: ble_rssi
    mac_address: D2:xx:60:33:51:xx
    name: "RSSI value Beacon1"

binary_sensor:
  - platform: template
    device_class: presence
    name: "BLE beacon1"
    id: beacon1
    filters:
    - delayed_off: 10s

esp32_ble_tracker:
  scan_parameters:
    interval: 2s
    window: 500ms
    active: false
  on_ble_advertise:
  - mac_address: D2:xx:60:33:51:xx
    then:
      - lambda: |-
            bool beacon1_status = false;
            
            for (auto data : x.get_manufacturer_datas()) {
              if (strcmp(hexencode(data.data).c_str(), "02.15.FD.xx.06.93.A4.E2.4F.xx.AF.CF.C6.EB.07.64.xx.25.27.1B.xx.B9.C9 (23)") == 0) {
                ESP_LOGD("ble_adv", "Beacon1 found");
                beacon1_status = true;
              }
              ESP_LOGD("ble_adv", "    - %s", hexencode(data.data).c_str());
            }
            
            id(beacon1).publish_state(beacon1_status);


But now it would be great also to get the battery level from the beacon to send an alarm for replacement but I´m not sure how to solve and could not find any examples. By logging level Very_Verbose I can see that there are additional service information but not identifiable as 0180f → battery service for me yet.

Do you know what to look for or have any examples how this has been solved?

Big Thx!

Hey so I got this working with my BLE trackers.

Pastebin here

The Pastebin link above doesn’t work any longer. I needed this example code, so I found it via the wayback machine. Pasted below just in case anyone else needs it. Credit to @Swamp-Ig

 
esp32_ble_tracker:
  id: ble_tracker_id
  scan_parameters:
    interval: 10s
    window: 1100ms
    active: false
# Uncomment this to log the BLE advertisement data.
  #  on_ble_advertise:
  #  - mac_address: CA:9B:32:2A:47:84
  #    then:
  #      - lambda: |-
  #            for (auto data : x.get_service_datas()) 
  #              ESP_LOGI("main", "Data Update UUID: %s Data: %s", 
  #                   data.uuid.to_string().c_str(), format_hex_pretty(data.data).c_str());
  on_ble_service_data_advertise:
    # Use the above logging to find the UUID of the device and service. Will need to
    # do an active scan, press the active scan button.
    - mac_address: CA:9B:32:2A:XX:XX
      service_uuid: "52XX"
      then:
        # I figured out it was x[1] by comparing the output from the above with the
        # known battery data across two different buttons by the manufacturer's app
        # One was 100% = 0x64, the other was %97 = 0x61. It was the only byte of 
        # state that was different.
        - lambda: |-
            id(mazda_battery).publish_state(x[1]);
 
binary_sensor:
  - platform: ble_presence
    mac_address: CA:9B:32:2A:47:84
    id: mazda
    name: "Mazda"
    device_class: "presence"
    on_press:
    - script.execute: ble_active_scan      
sensor:
  - platform: ble_rssi
    mac_address: CA:9B:32:2A:XX:XX
    id: mazda_rssi
    name: "Mazda RSSI"
    entity_category: "diagnostic"
  - platform: template
    id: mazda_battery
    name: "Mazda Battery"
    device_class: "battery"
    entity_category: "diagnostic"
    accuracy_decimals: 0
 
# This script switches to active scan mode, waits 30 seconds for the data to arrive
# then switches back to passive. It gets activated every 6h, whenever the iBeacon 
# becomes active, or when the HA button is pressed.
script:
  - id: ble_active_scan
    mode: single
    then:
    - lambda: |-
        id(ble_tracker_id).stop_scan();
    - delay: 2s
    - lambda: |-
        id(ble_tracker_id).set_scan_active(true);
        id(ble_tracker_id).start_scan();
    - logger.log: 
        format: Active scan started
        level: INFO
    - delay: 30s
    - logger.log: 
        format: Active scan stopped
        level: INFO
    - lambda: |-
        id(ble_tracker_id).stop_scan();
    - delay: 2s
    - lambda: |-
        id(ble_tracker_id).set_scan_active(false);
        id(ble_tracker_id).start_scan();
 
interval:
  - interval: 6h
    then:
    - script.execute: ble_active_scan
 
button:
  - platform: template
    name: "BLE Active Scan"
    id: run_active_scan
    on_press:
    - script.execute: ble_active_scan

Which beacon are you using? Ive been using BlueCharmBeacons. They are very configurable, have a button for triggering automations(which i still cant get dialed in) or it can be a motion sensor and broadcast UUID on motion.

If your doing room presence, Espresence is probably still the best. This repo has been useful to me for BT tracking things and getting battery level without using Espresence.


1 Like

Thanks! That looks great. I’m using BlueCharm beacons as well. Mind sharing your code for them? I’m having trouble identifying the battery level bits. I’ve got one beacon in TLM mode and I’m getting the advertisement data. Right now the BlueCharm app reports battery level of 100%, so I’d expect to find 64 or 0x64 somewhere in the advertisement, but I’m not seeing that.

I don’t remember how I figured it out but I do know there isn’t any info floating the web for how to do it, atleast for Bluecharmbeacons. I made some posts in this Esphome home forum to share this information and posted my whole config there. He did warn me that polling for the battery level would significantly reduce the battery life and I did notice it start dropping after the first couple months. I think they hit in the 70% range… It’s not a major drain but, it’s not quite minor either.

esp32_ble_tracker:
  on_ble_advertise:
    then:
      - lambda: |-
          parseAdvertisement(x);

  on_ble_service_data_advertise:
    - mac_address: DD:34:02:07:E3:D8
      service_uuid: '2080'
      then:
        - lambda: 'id(beacon1battery).publish_state(x[0]);'    

    - mac_address: DD:34:02:07:E1:37
      service_uuid: '2080'
      then:
        - lambda: 'id(beacon2battery).publish_state(x[0]);'   

sensor:
  - platform: template
    name: "Sam Beacon Battery"
    id: sam_beacon_battery
    icon: 'mdi:battery'
    unit_of_measurement: '%'
    device_class: "Battery"
  
  - platform: template
    name: "Extra Beacon 1 Battery"
    id: beacon1battery
    icon: 'mdi:battery'
    unit_of_measurement: '%'
    device_class: "Battery"
1 Like

That’s very helpful. I’ll find your posts in esphome also. Thank so much!

Also, you might want to take a look at the Bermuda integration. I’ve just started using it with BlueCharm beacons and while it’s not perfect yet, it’s really easy to setup, and it seems to work really well. It also leaves your beacons open in esphome for whatever additional config you like.

Ya, i actually saw that here recently and meant to fheck it out but I forget. Thanks for reminding me.

The one I sent you as well is basically the same. Its BT room presence for esphome and doesnt make you dedicate the esp32 to a firmware like espresence.

It works pretty good for the most part as well. One thing that ive noticed is theres no setting or way to deal with walls/obsteuctuons like there is in espresence with the Absorption setting. If a beacon is within line of sight its very accurate. You shut a bedroom door between beacon and base station and the distance will double sometimes

The active scanning drains the battery. If you turn on and off active scanning like in my script as posted by sdholden28 above and only scan once an hour or whatever, then the battery life doesn’t go down that fast.

I scan the beacons in my car when the garage door gets opened or closed, do it a few times for like 10 mins then go back to passive.

Good idea, but I would add that you don’t need to check the battery level every ten minutes or even every ten hours. How about switching it to once every ten days?

Yeh, like use it as your use case requires. The active scan pings the beacon, what I actually want to know is is the beacon (and thus the car or my garbage bin) nearby or not. The battery information comes for free. The beacon will send out advertisements periodically, but the update frequency is turned down. For fast updates I do an active scan.

Interesting!

So you have the beacon half sleeping (saving lots of beacon battery power), maybe shooting out a broadcast every 5 seconds or so just to confirm it’s alive. Then when you really really want to know the rssi, you actively ask. That’s really smart!

I’m supposedly a beacon expert and have never thought of doing this before!

1 Like

Got my brand new BC04P beacon working with a ESPHome presence detector in the garage with a minor update to @Fallingaway24’s YAML.

esp32_ble_tracker:
  on_ble_service_data_advertise:
    - mac_address: DD:34:02:XX:YY:ZZ
      service_uuid: '2080'
      then:
        - lambda: 'id(car_beacon_battery).publish_state(x[0]>100 ? 100 : x[0]);'

binary_sensor:
  # Presence based on MAC address
  - platform: ble_presence
    mac_address: DD:34:02:XX:YY:ZZ
    name: "Honda Fit"

sensor:
  - platform: template
    name: "Honda Fit Beacon Battery"
    id: car_beacon_battery
    icon: 'mdi:battery'
    unit_of_measurement: '%'
    device_class: "Battery"