Raspberry Pi: Bluetooth Low Energy Presence Detection [Part 1]

Experimenting with home automation, I find that it would be very easy to perform certain tasks, such as turning lights on or off, if you knew exactly(ish) where a person was. I decided to buy a bluetooth low energy beacon, often marketed as an iBeacon, to try this out.

The beacon itself was very easy to set up; you just had to tap it on a hard surface and an accelerometer inside detected the sharp vibration and put it into a connectable state where it's settings could be modified. Once there, I downloaded the eBeacon iOS app, and connected it to a device named Jalaee (presumably the people who make the circuitry inside). A quick tap of 'Configure' and a set of register values were written to the tag. It was all rather easy.

I modified the values of 'Beacon Interval' and Transmit Power (Set to maximum for now), and reconfigured the device.

Now, for the client side. Luckily I had a spare Raspberry Pi lying around and a cheap CSR 4.0 bluetooth dongle which was about £1 on eBay. Although I was skeptical about whether it would actually work with linux, I soldiered on.

The first step was to install bluez. I followed the instructions on the eLinux Wiki to build and install it. http://www.elinux.org/RPi_Bluetooth_LE#BlueZ_installation

Once it was built and installed, I copied the 'btmon' utility out of the source folder.

This executable is at the path in 'bluez-5.xx/monitor/btmon'. I copied this out into another folder.

Then it was Python time! In order to get the RSSI of my bluetooth beacon without connecting to it, after a bit of research I found that I would have to run btmon and then hcitool lescan to get the data from the surrounding bluetooth environment. Essentially, btmon provides more verbose output to any bluetooth utility, but is a separate executable.

My python code to find the RSSI of the beacon was as follows:

import subprocess, time, os, sys

MAC_ADDR = "XX:XX:XX:XX:XX:XX"

thecommand = "sudo ./btmon"
thecommand2 = "sudo hcitool lescan"
last_seen = 0
last_rssi = 0
lastn = 0

cmd = thecommand.split(" ")
cmd2 = thecommand2.split(" ")

p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)

p2 = subprocess.Popen(cmd2,stdout=subprocess.PIPE,stderr=subprocess.PIPE)

n = 0
for line in iter(p.stdout.readline, b''):
    n = n + 1
    g = 0
    #print(line.rstrip())
    if(MAC_ADDR in line.rstrip()):
        last_seen = time.time()
        lastn = n
    if("RSSI:" in line.rstrip() and (n-lastn)<10):
        a =  line.rstrip()
        last_rssi = int(a.split("RSSI: ")[1].split("dBm")[0])
        g = 1

    if(g==1):
        print last_rssi

This program just prints the RSSI of the beacon when it is in range. Now, I just need to incorporate that data into something useful.

Published 2016-09-06