Bermuda - Bluetooth/BLE Room Presence and tracking [custom integration]

Ah, your explanation does make sense! Shelly does have scripting interface that enables the BLE Observer, maybe some adjustments to the script could force them to update regularly?

// aioshelly BLE script 2.0
const queueServeTimer = 100; // in ms, timer for events emitting
const burstSendCount =  5; // number if events, emitted on timer event
const maxQueue =  32; // if the queue exceeds the limit, all new events are ignored until it empties
const packetsInSingleEvent = 16; // max number of packets in single event

let queue = [];
let timerHandler = null;

function timerCallback() {
  for(let i = 0; i < burstSendCount; i++) {
    if (queue.length <= 0) {
      break;
    }

    Shelly.emitEvent(
      "ble.scan_result", [
        2,
        queue.slice(0, packetsInSingleEvent),
      ]
    );
    queue = queue.slice(packetsInSingleEvent);
  }

  timerHandler = null;
  if (queue.length > 0) {
    timerHandler = Timer.set(queueServeTimer, false, timerCallback);
  }
}

function bleCallback(event, res) {
  if (event !== BLE.Scanner.SCAN_RESULT) {
    return
  }

  if (queue.length > maxQueue) {
    return;
  }

  queue.push([
    res.addr,
    res.rssi,
    btoa(res.advData),
    btoa(res.scanRsp)
  ]);

  if(!timerHandler) {
    timerHandler = Timer.set(queueServeTimer, false, timerCallback);
  }
}

// Skip starting if scanner is active
if (!BLE.Scanner.isRunning()) {
  BLE.Scanner.Start({
    duration_ms: -1,
    active: true,
    interval_ms: 320,
    window_ms: 30,
  });
}

BLE.Scanner.Subscribe(bleCallback);

Above is the aioshelly BLE script v2 that gets automatically installed when BLE Active listening is enabled from native HA integration settings.

I was considering getting some M5Stack Lite ESP32 proxies, but I read various issues about the battery issues. Also running BLE proxy with battery seems not recommended. Considering cabling etc, for me Shelly Plus 1PM Mini Gen3 makes the most sense (price, versatility and installation).

Did I read correctly, you mentioned multiple proxies in same room/area could improve reliability? If so, do you have any recommendations for minimum/maximum distances between proxies?

EDIT: Found some discussion about Shelly BLE, there’s also passive script to run on the Shelly:

// aioshelly BLE script 1.0
BLE.Scanner.Subscribe(function (ev, res) {
    if (ev === BLE.Scanner.SCAN_RESULT) {
        Shelly.emitEvent("ble.scan_result", [
            1,
            res.addr,
            res.rssi,
            btoa(res.advData),
            btoa(res.scanRsp)
        ]);
    }
});
BLE.Scanner.Start({
    duration_ms: -1,
    active: false,
    interval_ms: 320,
    window_ms: 30,
});

As far as I understood, active listening sends requests to surrounding devices and asks for updates, while passive just receives broadcasted messages. Not sure if this actually matters in this use case?

Yes, I suspect the key will be in fine-tuning the script to get the best responsiveness. Hopefully some peeps in here using Shelly’s can offer some tips.

I don’t have any Shelly’s yet, but taking a look at the docs it seems that

  • advertisements are ignored if they match one seen in the last 3 seconds (this is not great for our use-case, it will cause latency in detection (but not initial detection, so probably no biggie there) but also will cause bouncing between receivers if their distances are similar, since Bermuda might decide the fresher receipt is preferred due to freshness. This might also affect how eventual trilateration behaves, if it decides to discard “older” receipts - but I think I’ll probably allow older receipts for trliateration for this reason.
  • The window timings on those scripts are fairly short - it’s listening for 30ms our of 320ms (although possibly 3x30ms, not sure how they’re slicing it up between the 3 default advert channels). Their docs are pretty clear about the risks of tightening up those timings too much though, as it will depend on what else the mcu has to get done as to what will cause stability - they also mention the api possibly applying hard limits on what you configure anyway.
  • The api docs mention that if scripts take too long it will disable them, I wonder if the longer gaps in your hist_interval are due to the device rebooting or perhaps stopping/disabling/restarting the script?

Also possible is that due to the queue size and burst sizes, maybe the queue of adverts never gets fully cleared, which might result in long periods of a given beacon being at the back of a queue for a while (and never fowarded) and later at the front of the queue, etc. If the intervals of transmission and the timings of queues/windows etc line up a bit it’s easy to imagine getting a slow “wave” of adverts being caught regularly for a while then being missed for a while.

The active param of BLE.Scanner.Start seems to indicate “active scanning” (which is a term used confusingly in different ways) - in this case I think meaning that when the shelly gets a BLE advert, it then sends a scan-request packet to the device, and the device is then expected to reply with a scan-response packet, which often includes extra info like the device’s name, battery etc. This can be nice to get more names listed in the devices, but the downside is that doing this takes extra time for the shelly when it can’t be listening for new adverts or fowarding existing queued ones. I’d experiment with turning this off and seeing if it improves the hist_interval log. Bermuda uses just the passive advertising results (but an active scan will often result in it getting nicer device names on top of that).

That thread you linked has some excellent info on the Shellys, but because we can’t see the source code it’s always a bit hard to know exactly how to proceed, other than direct experimentation or asking Shelly directly. This might not be a use-case they have directly considered, though - so it might be worth asking. If I were submitting a feature request, one idea I’d put forward is that in the 3 second “caching”, if the new rssi is stronger than the previous rssi, it should override and send the new advert, since the stronger signal makes that advert “of interest” to us. If the signal is weaker or the same, that’s “less interesting”, for Bermuda’s purposes.

Bear in mind that as the number of bluetooth devices around you increases, the proxies have to spend more of their time processing and forwarding adverts. This makes fine-tuning inherently a site-specific thing, and probably means having to find a lot of your own trade-offs for getting good performance and stability from your specific environment.

On the github, @jaymunro seems to get good results with their Shelly’s, so I’ve asked them if they had to do anything in particular to get reliable adverts, fingers crossed :slight_smile:

@lazmo88 did you turn on active scanning inside HA Shelly integration?

This automatically installs a script on the Shelly to repeat Bluetooth advertisements. Without this the Shelly’s are only going to proxy their own BLU devices (and occasionally other 3rd party ones in my experience).

Passive is less noisey but will not interrogate the transmitter for further details (such as name) unless Active is selected.

1 Like

FYI, this is the script that gets automatically installed by Shelly’s HA integration. I’ve never had to touch it and have had completely reliable Bluetooth proxying.

Full script is:

// aioshelly BLE script 2.0
const queueServeTimer = 100; // in ms, timer for events emitting
const burstSendCount =  5; // number if events, emitted on timer event
const maxQueue =  32; // if the queue exceeds the limit, all new events are ignored until it empties
const packetsInSingleEvent = 16; // max number of packets in single event

let queue = [];
let timerHandler = null;

function timerCallback() {
  for(let i = 0; i < burstSendCount; i++) {
    if (queue.length <= 0) {
      break;
    }

    Shelly.emitEvent(
      "ble.scan_result", [
        2,
        queue.slice(0, packetsInSingleEvent),
      ]
    );
    queue = queue.slice(packetsInSingleEvent);
  }

  timerHandler = null;
  if (queue.length > 0) {
    timerHandler = Timer.set(queueServeTimer, false, timerCallback);
  }
}

function bleCallback(event, res) {
  if (event !== BLE.Scanner.SCAN_RESULT) {
    return
  }

  if (queue.length > maxQueue) {
    return;
  }

  queue.push([
    res.addr,
    res.rssi,
    btoa(res.advData),
    btoa(res.scanRsp)
  ]);

  if(!timerHandler) {
    timerHandler = Timer.set(queueServeTimer, false, timerCallback);
  }
}

// Skip starting if scanner is active
if (!BLE.Scanner.isRunning()) {
  BLE.Scanner.Start({
    duration_ms: -1,
    active: true,
    interval_ms: 320,
    window_ms: 30,
  });
}

BLE.Scanner.Subscribe(bleCallback);

But my suggestion is do not copy the script above, just erase the one you added and then use the HA integration to add the above. This way there’s a better chance it will be supported with future updates.

1 Like

Thanks @agittins and @HJM! I have installed the default script from HA by selecting active listening. The aioshelly BLE script 2.0 was installed, but maybe I tried fine tuning it without any clue what does what :joy:

I guess I’ll just need to take leap of faith and order more Shelly devices to see if accuracy improves with more proxies/beacons in the area/rooms. I’m anticipating outdoor/terrace/glass walls to be extremely tricky. Then again, I’m circling back to idea of embedding proxies to everyday items in the room. Perhaps using the M5Stack boards with batteries/small solar panels. Stronger signal is alway stronger signal which should help Bermuda to pick the right beacon location.

About Bermuda, can we adjust the update period somehow? Let’s say Bermuda would process updates only every 15 or 30 seconds and consider all broadcasted packages during this time frame? This should remove the “unknown” “unavailable” flickering I have seen :thinking:

This would allow Shelly/any proxy device to send multiple patches of data and then Bermuda would select the strongest signals for mapping tags to beacons.

1 Like

Great, let’s see how your detection goes with the vanilla setup (and thanks @HJM for chipping in!)

It should only go to Unknown after about 30 seconds, I think. By that point, it’s safe to say something is broken. BLE devices are deemed “unconnectable” by linux if they don’t broadcast at least every… 2.8 seconds, I think?

If it’s still flapping, take a look at the History page, and add the entities you are tracking, then narrow down the time range displayed so you can see what’s going on.

Can you also check the logbook on your shelly devices and see if perhaps their network connection might be dropping out? Do any of their sensors go “unavailable” periodically? You can add their wifi signal or other sensors to the history page so you can get a fuller picture of what’s going on, perhaps.

The problem with considering all the packets received over a 30 second block is that the data is pretty useless by then. If you walk down a hallway you could have passed through five areas in that time at a very leisurely pace - Bermuda then has to work out where you are now so recent data is critical. That said, you can always add a time element to any automations so they only trigger after a state has remained for a certain time, etc - or you could create template sensors that average out the values further. But so far your proxies have been not sending any data for over a minute at a time - so I am not sure a 30 second filter would entirely help :confused:

You might want to take a look at some of the discussion (and pretty graphs) in Discussion for further sensor filtering and algorithmic improvements · Issue #134 · agittins/bermuda · GitHub and the previous discussion at Add per-proxy distance sensors for configured beacons · Issue #99 · agittins/bermuda · GitHub for some ideas on how the work has gone in getting the area and distance detection into it’s current state.

You might notice there that there are a lot more sensors you can enable if you want to do some deeper testing - you can enable sensors for raw and filtered distances between every combination of device and proxy - bear in mind doing so will cause your database to grow more quickly, and your UI might get a little more sluggish on phones/tablets, but a handful of sensors on a few chosen devices should be no problem, and it makes the graphs a lot more exciting :smile:

If you have just the two proxies so far, then yes I’d definitely suggest that adding a few more should help. Also, right now you seem to have the two proxies fairly equidistant from where you were last trying to get a fix (when you did the dump_devices export). Bermuda does a fair bit of smoothing and averaging to try and reduce the flapping, but it’s just an unfortunate reality that if you are equally close to both proxies, it’s going to either oscillate between them, or take too long to change when you move toward one. The rssi signal is noisy, and there’s a real tradeoff between latency and volatility. I think the units you have are DIN-rail mounted, so you are probably pretty limited in where you can put them for now!

I use clones of the Wemos D1mini32 - they cost me about AU$6ea and are easy to pop into anything with a spare USB port around the house (although I also use a number of wall-warts I’ve scavenged over the years). I wouldn’t expect battery-power to be much fun, since the wifi part will use a lot of juice. But any way you can add more devices (or have them more centrally located in an “area” will help.

Once we have full trilateration I expect that having proxies actually in an area might not be necessary at all, but having a generous amount of them spaced around the house will always be key to getting good results - but 4 should be fairly solid for starters, providing they are reliably forwarding packets - which is the core of the issue you’ve been facing so far.

Once you’ve had a chance to see how the last changes go, could you send through some fresh data from the dump_devices service call? In particular I’m interested in the hist_interval stats. Fingers crossed! :slight_smile:

Oh, something else just popped into my head… You could enable the “distance to …” sensors for a device, and with your automaton you could check the distances - you could treat it as “being within 8 metres of living room is living room, regardless if that means 5m away from kitchen”. It won’t solve the dropout issue you were having but it might solve the flipping between areas problem, at a pinch.

I’ll give it a shot! Does Bermuda also consider distance value in the calculations? Another thought popped in my mind, would it be possible to keep area unchanged until there’s enough confirmations for the area determination? Ie. Wait for 5 confirmations/data points before changing device area? Or would it be possible to publish new locations to MQTT directly from Bermuda?

Second thought I had was adjusting tx power of the tag itself. Unfortunately RuuviTags I have requires manually compiled firmware, as there’s no software adjustments as there is on BlueUp tags. I would assume lowering the TX power and adding more proxies/anchors should make tracking much more accurate :thinking:

I’ll call BlueUp tomorrow and see if their tags are easily available for testing :sweat_smile: For proxies I’ll stick with the Shelly plan, but may play around with battery powered proxies as well.

There’s also mesh protocol called Wirepas, which works on bluetooth, also the proxies/anchors.

EDIT: BlueUp not easily available, but the tags seems very versatile and easy to config. Wirepas is commercial bluetooth mesh, which operates purely on battery devices (pretty flexible), but isn’t very fast with updates. Gone through a rabbit hole of different locating technologies and all of them have their pros/cons and in the end it boils down to the planned use case. There’s not a lot of open source or community development around this topic, most of indoor location systems are commercial services aimed for niche market, none of them is consumer friendly.

@agittins hats off for embarking on this path of a pioneer! It is truly remarkable work :ok_hand: It seems like AoA/AoD, Mesh tech stack is been kept as hostage by few software development companies, even if the hardware is quite freely available for consumers. I know we are not going there (yet), but I’m sure this project will inspire others to push the boundaries :wink:

1 Like

I have been watching the RuuviTags now, and maybe it is RuuviTag issue… They seem to send updates only when one of the sensors change (temperature, humidity, pressure, battery voltage, movement detected). Maybe I have been looking this issue wrong all the time and root cause is the tags. If so, it does make sense from battery management perspective. Which actually made me thing about the MQTT idea, solution for this could be automation that triggers on Bermuda area change, ignores unavailable status and posts all other updates to MQTT topic, which I could turn into more stable sensors for HA dashboard? :thinking:

EDIT: Contacted RuuviTag team, above assumption was not completely correct. RuuviTags doed broadcast MAC with 1285 ms interval, which is much higher than iBeacon normally do, but still less than 10000 ms that is said to be the upperbound for iBeacons. It is still lower than 2.8s threshold.

Shelly logs didn’t show continuous or repeating connection issues (3 disconnect events in past 24h which IMHO is fine for WiFi). Neither did Shellys on device logs show anything weird.

I looked into Bermuda addon debug logs and used the service dump, but I can’t see any error errors, but I see some duplicate creation messages and beacon type “not a beacon” parameters in the dump.

Strange this is, this exactly same behaviour is also happening with HA Android Companion App tracker (my mobile). That would point again that RuuviTag may not be the culprit after all, then again Shelly logs (device or integration) doesn’t show any errors. Native Shelly integration works through RPC as it seems, not sure if other protocol could be more stable.

TLDR; Something seems to be off with the Shelly as a proxy or bluetooth_le_tracker config that causes devices to go “Unavailable” all the time.

Logs: Bermuda Add-On Debug Log2024-04-23 14:28:49.045 WARNING (SyncWorker_0) [home - Pastebin.com

Bluetooth from configuration.yaml:

bluetooth:
device_tracker:
platform: bluetooth_le_tracker
track_new_devices:true
track_battery: true
track_battery_interval: 3600



1 Like

I use the addon to track who is at home with my G Tag key fob. This works very well with Shelly and bluetooth proxy. When I restart Home assistant and I am not at home, the message not aviable always appears. Can’t I save the Mac address somewhere so that this doesn’t happen when I restart?

Hmm. Good question. HA’s thinking on this generally is that if we don’t “know” something, we set it to unknown or unavailable. But in our case, our only way of knowing something is “away” is simply not hearing from it, which logically is no different to “not heard from yet”.

I could change the logic so that “configured” devices default to being “away” at startup.

The downside to this is that automations based on away status would trigger at startup, as would automations set to trigger on transition from away to home, once a packet is detected.

Do devices stay stuck at “unknown” until you return home, or do they change to “away” after the configured away timeout? The latter is what it probably should do.

That makes sense. It would be good if he could remember the last status? The status remains unknown until I return home.

It would be best if I could enter the Mac address somewhere in the config so that the system would still recognize it when I restart and then set it to present if it is reachable or to absent if it is not reachable.

The problem now is that it no longer recognizes the Mac address after a restart. Or can I save it somewhere now? I may not have seen that.

Hmmm… that doesn’t sound right. Can you post some screenshots of what you are seeing and how it’s configured?

If you are getting actual Bermuda sensors for something, then it implies that it must either be set up in the configuration under Settings, Devices&Services, Bermuda, Configure, “Configured Devices” - or it must be a Private BLE Device in which case it will be saved in the config of that integration.

If it’s a random MAC address then it’s either sending iBeacon adverts (in which case it will be added via “Configured Devices” using the iBeacon UUID/Minor/Major, and/or via the Private BLE integration. Neither should require you to keep track of the MAC address, because it should just update the configured sensor whenever it knows something.

Unless of course you’re actually looking at a sensor provided by the iBeacon integration, in which case all of the above three posts can be ignored, and you need to add your thing via Bermuda, Configure, Configured Devices.

Some screenshots of what you’re seeing, and of your Bermuda configuration might be helpful if there’s any confusion

So bluetooth_le_tracker is completely separate from Bermuda, and you don’t need any of those entries in configuration.yaml for Bermuda to work (in fact, the poor state of bluetooth_le_tracker is one of the reasons Bermuda exists, that plus I knew it wouldn’t be a good fit for core for at least a while).

I can see you have the Devtracker Timeout in seconds to consider a device as "Not Home" set to (the default of?) 30 seconds. This is fairly short, and while I find that 180 seconds is pretty good, you could bump yours up as much as you need to (perhaps 4 minutes (240s) or more) to stop Bermuda from setting them as away as eagerly. Arrivals should still be instant, it’s only the “departure” that gets delayed.

In your dump_devices service output, you can see this block that shows the number of seconds between each received packet for that device (updated only every update_interval, so usually won’t show less than 1s):

     hist_interval:
        - 2.5520358320209198
        - 77.1560656990041
        - 2.591035165998619
        - 2.5540346179623157
        - 77.11702469200827
        - 2.5480331380385906
        - 2.5510331269470043
        - 3.8650500990333967
        - 73.26307638001163
        - 3.7490643459605053

The newest entry is at the top. So our last packet arrived 2.5 seconds after the previous one we saw, but before that it was over a minute (77 seconds) since we heard from that device. Then 2.5 seconds twice more, and 77 seconds again, and so on.

Bermuda gets this info by looking in Home Assistant’s internal cache of bluetooth packets, which (except for ones from usb bluetooth adaptors) will have timestamps on them supplied by either esphome or HA (not sure which part applies the stamps).

Given you are regularly getting 77 second gaps between packets, and you have the devtracker timeout in Bermuda set to the default 30 seconds, I think you’d probably find a big improvement by setting the timeout to at least 180, since “away” tends to not need to be as time-sensitive a status as “home”.

Is that likely to improve the situation for you?

Sorry for the delay in my response, combinations of real life and adhd mean I sometimes think I’ve already replied, or it slips my mind etc!

I plan for Bermuda to be an HA-native integration, so I don’t plan on doing any mqtt-specific things, but since they are just sensors on HA I expect they should all be available via the mqtt integration, if I understand correctly.

Re ideas for algorithmic improvements, there’s a few threads that are pretty much mandatory reading at this stage :slight_smile: I’ve tried to spell out the reasoning behind how I’ve set it up, so that people can evaluate that and provide ideas with the background knowledge on why it is currently how it is. I think most of the points you raise are well-covered in those, but let me know what you think after taking a read through:

Generally speaking, for Bermuda’s purposes, the maximum TX power is best, as it allows Bermuda to “hear” your devices from further away, maximising the opportunity to use multiple receivers (proxies) to make decisions about your device’s location.

If you have a fairly simple setup and just want to reduce the radius in which bermuda will detect the device, you can try lowering the power, but this is only a reasonable strategy when you have very few proxies. If you have more proxies the device should be “moved” to a closer area instead - but given the gaps in reception you are seeing it might be a reasonable option for you, at least until we have trilateration implemented.

v0.6.4 Released!

Very much a maintenance release, but with a few important bug fixes.

Thanks to @skrashevich and @itsteddyyo for their much-appreciated contributions via PRs merged into this release, and to those who have generously offered financial support to keep Bermuda improving. As well as the amazing community support these things make it that much more enjoyable to further this thing that I made to scratch my own itches :slight_smile:

Most of these changes have been sitting in the main branch of the repo for about two weeks, so you may already have these changes if you’re tracking that branch rather than official releases.

This release sees:

  • fixes to the dump_devices service call
  • making sure that changing the Area on a scanner applies properly
  • an important fix for devices that are both Private_ble and iBeacon (ie, all Android HA Companion app beacons) that would stop updating after a time ( @ingranu it might be worth checking if this was affecting your system)
  • some tidying / hardening of calculations
  • a process that “prunes” stale mac addresses from the in-memory cache to keep only the last 1000 un-tracked devices over the past 3 days. This may offer some CPU usage improvements, after 6 days my server went from 0.004 seconds per update cycle to 0.100s per cycle. Now it remains pretty stable around 0.005. It may improve memory usage but I didn’t see much difference there on my machine.
  • :rotating_light: Device names are now filtered for whitespace and binary cruft before and after the name. I have a device that calls itself ‘UC96BLE\0\0\0\0’ which makes it very unpopular with my long-term stats database :slight_smile: Note that you might find some device names may change if they had whitespace or non-alphanum chars in their names previously.

Changes

Full release notes at Github, update available via HACS.

2 Likes

I really love this integration. I’m having great success with shelly minis as bluetooth proxies. They’re cheap and can install behind an existing switch or outlet. The shelly integration is local and really nice. Set them up and turn on bluetooth and bermuda picks them up right away. I have 2 dogs that not everyone loves, so my main purpose for Bermuda is tracking them to know if they’re inside or outside the house. They have Blue Charm Beacons on their collars. I have a wifi pet door from High Tech pets integrated with HA and some cameras outside. Couple all of that with Bermuda, and I can know where they are at all times, with no battery life issues or expensive gps subscriptions. If guests are coming and I’m not home, I can keep them outside if they’re already there, or I can send them outside if they’re inside and close the door behind them. The dogs even have their own person card now! I really enjoy that on my mobile dashboard. It is useful, and just fun. Thanks @agittins!
image

4 Likes

Heads-up - reconfiguring in v0.6.4 causes HA lockup!

@sdholden28 discovered a bug in the new version v0.6.4 that causes the HA user interface to lock up if you change any of Bermuda’s config settings and click “Submit”.

I’ve been able to replicate the issue on my system, so should hopefully have a fix sorted out “tomorrow” - my brain is fried and overdue for sleep right now :slight_smile:

If you encounter this issue I’d suggest rolling back to v 0.6.3 until a fix is provided.
More info at After installing v0.6.4, changes to configuration page causes HA lockup · Issue #185 · agittins/bermuda · GitHub - and other observations welcome.

If you get the UI lock-up, you will probably need to restart HA - either by SSH’ing into your server, or if using a supervised install it looks like it will restart it automatically after perhaps 10 minutes.

Apologies for the inconvenience!

2 Likes

Cool system! Love the dog cards with pictures!

How do you “send them outside” if you are not home? Do you have some cool way to remotely deliver them treats outside with a sound alert so they run outside to get the treats?

They are both well trained and well behaved. They understand the “outside” command and go through the dog door whenever it is issued. A couple of the cameras are two-way audio so I can just tell them to go outside if I know where they are in the house. Now that I think of it, I really should just record the command and set up a button on the mobile dashboard to broadcast it. That would be easier.

Honestly, given the hours and money spent on training long ago, “the cool way to remotely deliver treats” would have been probably been cheaper and easier. :rofl:

3 Likes