I’m currently using Hass.io in a VM and love it. One thing I’d like to do is presence detection with Bluetooth. I know I can’t pass through a BT dongle as Hass.io won’t support it, but is it possible to use some other BT device/receiver or a standalone Raspberry Pi 3 that can send updates to my Hass.io server? Figured I’d see if there were any unique solutions to this problem that I didn’t think of.
I think you could do it on a stand alone PI using room assistant and FIND as both use MQTT also zanzito integrates with FIND
See here …
Certainly food for thought
This is just the rabbit hole I was looking for. Thank you!
I use a Pi Zero (running Hassbian, can be raspbian) to do the job, it has built-in Bluetooth.
I run a little python rest api script to listen out for any BluetoothLE devices, in my case Tile keyrings.
It’s basic - just checks if the device is detectable or not. Might be of use:
Some things you might need to install
sudo apt-get install python3-pip libglib2.0-dev python-flask
sudo pip3 install bluepy
And the python script:
from flask import Flask
from bluepy.btle import Scanner, DefaultDelegate
class ScanDelegate(DefaultDelegate):
def __init__(self):
DefaultDelegate.__init__(self)
def handleDiscovery(self, dev, isNewDev, isNewData):
return()
scanner = Scanner().withDelegate(ScanDelegate())
app = Flask(__name__)
@app.route('/api/search/<string:mac_addr>', methods=['GET'])
def device_scan(mac_addr):
scanner = Scanner().withDelegate(ScanDelegate())
devices = scanner.scan(3.0)
for dev in devices:
if dev.addr == mac_addr:
return("true")
return("false")
@app.errorhandler(404)
def not_found(error):
return("Not Found ", error)
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=False)
For the sensors.yaml
## Presense / Tiles Sensor via Pi Zero Hassbian
- platform: rest
name: Car Keys
resource: http://192.168.18.143:5000/api/search/a4:e8:27:f4:3e:2a
Where ‘a4:e8:27:f4:3e:2a’ is the MAC address of the BluetoothLE device you’re looking for:
sudo hcitool lescan
if you need to find it out.
The MAC address must be in Lower Case.
and 'http://192.168.18.143:5000 ’ the IP of your Pi Zero.
And a binary_sensor.yaml entry to make things easier:
- platform: template
sensors:
car_keys_boolean:
friendly_name: "Car Keys"
value_template: "{{ states.sensor.car_keys.state == 'true' }}"
Some might want to increase the scan time in the script, so 5 secs would look like this:
devices = scanner.scan(5.0)
The binary rest sensor option might look like a better fit here, but it will view the device as unavailable between boots if not seen at boot-time, hence the sensor to binary_sensor step.
How did you manage to get the Tile MAC address using the scan function? I set it up with my phone and then went to scan and I get a ton of devices that pop up with the tag of (unknown) because I live in a pretty densely populated area. Is there anyway to get some sort of descriptive text?
Edit: It appears that being paired with a phone stops the Tile from broadcasting it’s MAC address. Deleted the Tile app from my phone and I was able to get it.
Awesome thank you for the script, I have a couple of Pi Zero W’s laying around and have been thinking about doing this exact thing
Oh, yeap they’re particular that way.
I only ever activate the app if I need to find them, and thankfully that’s been a while.
Cheers, I’m very happy with it.
It saves having my main Hass.io do the checking, and it’s a handy way of extending BLe detection out to the range of my wifi.
Do you ever get random disconnects causing false ‘False’ returns? I get quite a number each day (20+ if I had to guess) for <1 minute usually. I increased the scan time to 5 seconds, then ultimately to 8 but it’s not made a dent. I did put a two-minute timer on the relevant automations and that’s fixed it for the most part, though I had one today last longer than 2 minutes and it triggered my automations. I’d like to solve this without going to a longer automation timer as I ultimately plan on using this for home security arming.
I have ~40 seconds gaps about 4 times a day, typically coinciding with heavier foot / device traffic.
I know the type of gaps you mean though, I had them more often when the sensor was roughly head height or below.
My current pi zero is at the top of a tall cabinet, and that’s fixed it for me.
hey @Bit-River trying to use your script to find my fitbit or even my cell phone but I keep getting this error
pi@raspberrypi:~ $ sudo python3 bt.py
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
192.168.1.11 - - [21/Dec/2017 21:10:42] "GET /api/search/C6:17:76:1B:30:C2 HTTP/1.1" 200 -
[2017-12-21 21:10:43,275] ERROR in app: Exception on /favicon.ico [GET]
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/werkzeug/wrappers.py", line 949, in _set_status
self._status = to_native(value)
File "/usr/local/lib/python3.6/site-packages/werkzeug/_compat.py", line 195, in to_native
return x.decode(charset, errors)
AttributeError: 'NotFound' object has no attribute 'decode'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1615, in full_dispatch_request
return self.finalize_request(rv)
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1630, in finalize_request
response = self.make_response(rv)
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1737, in make_response
status=status_or_headers)
File "/usr/local/lib/python3.6/site-packages/werkzeug/wrappers.py", line 842, in __init__
self.status = status
File "/usr/local/lib/python3.6/site-packages/werkzeug/wrappers.py", line 951, in _set_status
raise TypeError('Invalid status argument')
TypeError: Invalid status argument
192.168.1.11 - - [21/Dec/2017 21:10:43] "GET /favicon.ico HTTP/1.1" 500 -
Not sure if I missed a step or something but I always get “false” for every device
Oh, I haven’t seen that error before. it’s looks like the flask sub-program doesn’t like the following section of my script:
@app.errorhandler(404)
def not_found(error):
return("Not Found ", error)
Though it’s working fine for me right now with no errors, could you check to see if there’s a copy & paste error with that piece of code?
Also, it doesn’t need to be there - it’s handy for logs, error checking but otherwise serves no purpose.
So I would try the script without that section, leaving the rest as is. A simple comment-out will do.
#@app.errorhandler(404)
#def not_found(error):
#return("Not Found ", error)
Other than that the only thing that looks different is using all Caps in the MAC address, where I usually have it in lower case. I’d be surprised if that was the cause, but worth a try.
Thank you! Commenting out those lines of code and using lowercase worked
DUDE - massive kudos!
just set this up on a pi zero at works like a charm! Thank you for sharing
Got a couple of mains 110V to 3.3V step down converters to see if i can 3D print a case with a plug connected so it can stay on in the middle of the house
Thrilled it’s useful for ya
Another option is to use the cheaper esp8266 with a Bluetooth module:
Devs are currently working to get it running on a esp32 (wifi+bluetooth built in for ~$8/unit). I have one up but it’s not terribly stable yet on the esp32 - it will run for a day or two then crash. Been watching the github because esp32 support would make deploying a bunch of these real easy. They also read MiFlora data if you have those devices.
I built an ESP32 presence detector and although it works great for a few days, it eventually stops working until powered off/on. I think the ESP32’s are quite fussy about power supply stability so I’m going to try going down the Pi zero W route.
Hi, where do you save the python script on the Pi?
I tried using the standard bluetooth_tracker and bluetooth_le_tracker. Slowed down my raspi quite a bit. Way too laggy for my taste.
Just used this script with these BLe devices:
https://www.amazon.com/gp/product/B07F39J8HL/ref=oh_aui_detailpage_o02_s00?ie=UTF8&psc=1
Works great! I also get cutouts here and there but I’m going to filter them out with some automation scripting.
I have never coded in python but this gives me the opportunity to learn and maybe do some interesting things with it.
Thank you, Bit-River!
-Rey
Hey - Thank you so much for this writeup! I think this MIGHT be what I’m looking to use my Tile Trackers for and hope you can help me out with some guidance…
I’m essentially looking to use Tile Bluetooth Trackers to identify if anyone is home
or not home
without running the Tile app on our phones with Bluetooth running 24/7. I tried to accomplish this using a Kindle Fire tablet which I installed the Play Store/Google Play Services/etc on and installed the Tile app. Upon logging in on the Kindle Fire and granting access to Bluetooth and location services the Tile app continually told me it wasn’t able to receive location access no matter what I did.
Before I order a new Pi 3 Model B+
or maybe a Pi Zero W
I wanted to check with you to ensure I’m understanding this properly… Unfortunately, I have a spare Pi 2 Model B and a Pi Zero here, but no bluetooth dongles available right now.
-
I currently have a
Raspberry Pi 3 Model B
running Home Assistant using the Hassbian installation method. You can find my full configuration repo here. -
Using your Python script I should be able to keep Bluetooth turned OFF on my phone and use the
binary_sensor
to determine if a Tile ishome
ornot home
, is this correct? -
Can I install this on my existing Pi 3 Model B which is running Hassbian already?
If I can install this I believe I need to run sudo apt-get install libglib2.0-dev python-flask
and then activate my venv
by running source /srv/homeassistant/bin/activate
.
Once my venv
is activated I can run pip install bluepy
, correct?
Where would I actually place the Python
script? Would this go inside of /home/homeassistant/.homeassistant
?
Thank you so much! I really appreciate any guidance you can provide. You can also reach me on Discord at bk#5430
if that’s easier for you.
Thank you! Cheers…