ESPHome component for ESPresense-like room tracking

@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

A very basic way to configure would be to compare all nodes values and the one that has the lowest distance would be considered the room you are in.

You create a template sensor called phone location and something lik;

{% if distance node 1 is lowest %}
Room1
{% elseif distance node 2 is lowest %}
Room2

And so on.
1 Like

I’m trying to use this with an iPhone running Room Assistant to provide a beacon, but I’m always getting ‘nan’ as a distance. I’m using an m5stamp, which has a risc-v processor if it makes any difference, and have tried both the arduino and esp-idf frameworks. I’m not seeing any “iBeacon data” messages from esp32_ble_tracker when I have very-verbose logging as I’ve seen others have had.

Can anybody offer advice?

Either your phone isn’t advertising or you’re using the wrong UUID. Use a BLE scanner app on another phone and see if it comes up.

I assumed the UUID I need is the Device ID in the room-assistant app on the phone. Clearly I don’t know what I’m doing, and at least one other person is having difficulty too, so at least I’m not alone. I think the problem is more with the use of room-assistant. Regardless, here’s what I’ve tried so far.

I modified ‘ble_dist.h’ to log when it finds a beacon. It’s very regularly reporting just one - it has what I understand to be an Apple manufacturer id (0x004c). If I turn off bluetooth on my phone and iPad (which both have room-assistant running) and Apple watch, and take the batteries out of my two Air Tags, it continues finding that same device, but no other (could it be an Apple TV or one of the laptops?).

If I install nRF Connect on the iPhone and iPad, they can both see each other (when bluetooth is on obv). Sometimes the name shows up as ‘room-assistant-companion’, but other times it’s the device name (eg. iPad mini). However, the app doesn’t appear to show the UUID. Even if it did, the code is not finding any other beacons. I installed Locate Beacon on both the iPad and iPhone, but if I enter the relevant Device ID, they don’t show up.

UPDATE: I decided to go back to basics and try room-assistant running on a server. It successfully sees both the iPhone and iPad companion apps. So therefore I assume the ESPHome code does not work with the beacon provided by the room-assistant companion app. It would be nice to know how nRF Connect (and hcitool etc) can get the iPhone’s name when esp32_ble_tracker cannot. If I knew how to get the device name, I could just use that for tracking.

Ok, so the room-assistant companion app works by using a particular characteristic (defined here), where it stores the Device Id. It is not the UUID of the beacon. Therefore, this code will not work with the room-assistant companion app.

The Locate Beacon app sends an iBeacon that this code can pick up, but it does not run in the background on the iPhone.