ESPHome component for ESPresense-like room tracking

Hi all,

I recently added room presence tracking via BLE to my setup, and the common solutions didn’t really suit my needs. Room Assistant requires raspberry pis, and ESPresense has limited support for adding additional sensors to nodes, and doesn’t integrate with the ESPhome dashboard. The main value adds of ESPresense over ESPhome’s ble_rssi sensor are 1) fingerprinting for non iBeacon devices with randomized Macs, and 2) filtering on the edge node to prevent large spikes in reported distance.

I’ve put together a small header file for ESPhome that solves the second problem by borrowing the filtering implementation from ESPresense. It currently only works with iBeacons and doesn’t solve the fingerprinting problem because I don’t have to deal with Apple watches, but it should be easy enough to extend, and PRs that keep the code simple would be welcome. I hope this is useful for those trying to do presence detection with existing ESPhome nodes, and feedback would be welcome. If it becomes prudent, I might package this as a proper ESPhome custom sensor, but it’s been working fine for me as is.

This also ties into another project, for broadcasting iBeacons from Wear OS watches. This is much more a work in progress.

13 Likes

Hello, your project is very intriguing. Would especially love to see something like this for iPhones and Apple watches. However, it appears a custom app would need to be developed for iOS and watchos. Thanks for sharing!

I didn’t look too deeply at the ESPresense code about fingerprinting, but it probably wouldn’t be too difficult to extract it into its own file and integrate it here. If anyone who has an apple watch wants to do so, I’d happily accept a PR.

If I understood correctly it only works with iBeacon right?
Do you think is it possible to connect an android phone? Based on MAC address, for example.

How is this implemented in ESP-Home?
What do I need to add to the yaml to get this working?

@Hellis81
At least this:

esphome:
  name: example
  platform: ESP32
  includes:
    - custom_components/lib/OneEuro.h
    - custom_components/ble_dist.h
  on_boot:
    then:
      lambda: |-
        addTracker("phone", "D66CFF56-CCB4-47DE-B148-6667181AB156");

and this:

esp32_ble_tracker:
  scan_parameters:
    duration: 60s
    active: false
  on_ble_advertise:
    then:
      - lambda: |-
          parseAdvertisement(x);
sensor:
  - platform: template
    name: "Phone Distance"
    id: phone_dist
    update_interval: 30s
    unit_of_measurement: "ft"
    device_class: ""
    state_class: "measurement"
    accuracy_decimals: 1
    entity_category: "diagnostic"
    lambda: |-
      return getTracker("phone").get_dist();

You can find an example here:

2 Likes

@Hellis81 The details are in the readme in the github repo, ALeksei has copied the relevant parts here.

@Aleksei_Piatkin The home assistant companion app produces iBeacons on Android phones.

1 Like

@rpatel3001 Totally forgot about it… Thank you for the tip, I’ll test it soon :slight_smile:

I have issues with the oneeuro.

I get this:

In file included from src/main.cpp:48:0:
src/ble_dist.h:23:5: error: 'OneEuro' does not name a type
     OneEuro filter;
     ^
src/ble_dist.h: In constructor 'BeaconTracker::BeaconTracker(std::__cxx11::string, std::__cxx11::string, float, float)':
src/ble_dist.h:34:7: error: class 'BeaconTracker' does not have any field named 'filter'
     , filter(1.0, fcmin, beta, DCUTOFF)
       ^
src/ble_dist.h: In member function 'void BeaconTracker::update(int, int)':
src/ble_dist.h:58:83: error: 'filter' was not declared in this scope
       filt_dist = filter(temp[std::max(0u,(unsigned)(dist_buf.size()/3.0-1))], now);
                                                                                   ^

I have tried these two versions:

I added the code as a new .h file in esphome folder.

NEver mind… I see the file is in the lib folder of your github

I get nan

[18:31:13][D][sensor:125]: 'Andreas BLE Distance': Sending state nan m with 1 decimals of accuracy

Using:

esphome:
  name: thirtytwo
  platform: ESP32
  board: esp32dev
  includes:
    - OneEuro.h
    - ble_dist.h
  on_boot:
    then:
      lambda: |-
        addTracker("phone", "e24fa42a-055d-4920-9f03-c5d9855f8e74");
        
        
# Enable logging
logger:
#  level: VERY_VERBOSE

# Enable Home Assistant API
api:


esp32_ble_tracker:
  scan_parameters:
    duration: 25s
    active: false
  on_ble_advertise:
    then:
      - lambda: |-
          parseAdvertisement(x);

binary_sensor:
  - platform: ble_presence
    ibeacon_uuid: 'e24fa42a-055d-4920-9f03-c5d9855f8e74'
    name: "Andreas telefon"
    id: "andreas_telefon"
    filters:
      - delayed_off: 60s

# more ble binary sensors here

sensor:
  - platform: template
    name: "Andreas BLE Distance"
    id: phone_dist
    update_interval: 2s
    unit_of_measurement: "m"
    device_class: ""
    state_class: "measurement"
    accuracy_decimals: 1
    entity_category: "diagnostic"
    lambda: |-
      return getTracker("phone").get_dist();
      

What have I messed up?

NAN is returned when the sensor has not been seen. I suspect you are running into the same issue I worked through here. The UUID has its bytes reversed in some BLE components but not others. The UUID you pass to addTracker should be byte reversed from the UUID you use for ble_presence, for example A1B2C3-D5E6 becomes E6D5C3-B2A1. This is necessary until this issue is fixed.

That worked.
Now I just need to fine tune the constants.

Thanks!!

Is it just me or is it very hard to get even closely accurate numbers in distance?
Not that it really matters, I could just call the measurement “foobars” and it will be just an arbitrary number.
But is it even possible to get something relatively correct?

When path loss was at 1 it was fairly accurate when the phone was right next to the ESP but as I moved it 2 m away it showed about 0.9 m.
So I changed it to 1.2 and now I get 1500 m when I’m actually about 8 m away.
Perhaps it’s the phone?

The default path loss value should be fine, from what I’ve read it should be in the range 2-4.

The distance should be decently accurate, within a few meters and monotonic ish. 8m might be pushing the range depending on what output power you have set, but I would expect to never see 1500 m. That implies a received RSSI of like -150 which shouldn’t even be possible. Did you calibrate the reference power sent with the advertisements? Put your phone 1 m from the ESP32, monitor the logs and find the lowest repeated RSSI value.

RSSI measurements are extremely noisy, which is why the filtering is important.

I will give it a try tonight if I have time for it.
I know 8 m is pushing it, but I was in the other room across the apartment.
But even in the same room I had issues getting it correctly.

With the default value it was way to high values.
Where should I calibrate it? I can’t see anything about that in the GitHub page.

Are you using the home assistant app to generate the beacons? There is a setting for “measured power”. The default of -59 is just a guess, each device is somewhat different. You should turn on the beacon and put your phone 1 m from the esp32. Monitor the logs in esphome and look for the lowest repeated RSSI value. Put that into the home assistant app as measured power.

I’ve updated the repository to reverse the UUID in my code instead of relying on patching esphome or manually reversing the UUID. This doesn’t affect anyone who has it working already, but it will be easier to set up moving forward.

2 Likes

Hey, I am pretty new so I would appreciate some help!
I´ve been using ESPresense but I also need ESPhome devices in the same room for motion detection and other stuff that doesnt work that well yet on ESPresense.

I´ve just configured one of my ESP32 to detect my phone and distance reporting works but I have no idea how to configure HA now…
Could anyone explain please?

What do you need to configure? Distance reporting is all this does. You can add a template binary sensor that reports occupied if the distance is under some amount.

Yea some guidance on how to set up occupancy for multiple rooms using several ESPs would be nice.

1 Like