Summer had arrived and I ran into some true first world problems. Sitting outside with my laptop and listening to Spotify on my headphones is a pleasurable way to spend a sunny day, but I still got some things to handle here and there inside my place. And hooray for technology, I can transfer my playback from my laptop to my desktop inside and can almost seamlessly continue listening to whatever I'm listening to.
However, that involves a manual switching of my playback devices before I leave to the inside / when I come back outside, which is sometimes way too easy to forget to do that, and I always had to make a detour to do the switch-over then. I did promise first world problems, didn't I?
Having a history with Bluetooth beacons and indoor positioning using Ultra-wide band beacons, I figured this could be a valid use case for my issues. Since I'm usually carrying my phone with me anyway, I could have an app that monitors the location of some beacons, figuring out where about I am at the moment, and automatically transfer the playback between the devices via the Spotify Web API.
While Bluetooth beacons surely have their limits for real positioning, they do a well enough job for a rough approximation which of two points are closer. Plus, if your phone can do Bluetooth LE, it can detect beacons out of the box. So all I needed was some beacons, but since that's in the end just regular BLE advertising data in a specific format, you can easily set up any BLE capable device as one. In my case, it's my laptop and some random Raspberry Pi that do the job.
Setting up the beacons
I've chosen then AltBeacon protocol for the ranging, which comes with a handy shell script to set up the single fields in the advertisement data and make your BLE device advertise it using BlueZ. There's also a slightly adjusted version in the SpotifindMe git repository based on that same script.
The most important part is to set up the Beacon ID and Reference RSSI advertisement fields properly. The app is expecting two beacons with Beacon Unit ID (ID3) of 0x0001 and 0x0002. The script itself is set up with id 0x0001 already, so you only need to modify it for a second device that will act as beacon:
AD_Data_ID3="00 02" # Beacon Unit as 2-byte value
To adjust the reference RSSI value, you should measure the RSSI value of your beacon in one meter distance (there should be an app for that?), which will give you a negative value, let's say -54. The reference RSSI variable needs to set as a signed one-byte integer, so we need to give the two's complement of the measured value.
printf "%2x\n" $((-54 & 0xff)) ca
So if we have -54, we need to set 0xca in the script.
That's it, ready to go, just run the script, it will output what's going on and set up your BLE device through hciconfig and hcitool, and returns back to the terminal. The rest is done by the BLE device itself.
$ ./tools/altbeacon_transmit.sh Transmitting AltBeacon profile with the following identifiers: ID1: 53 70 6f 74 69 66 69 6e 64 4d 65 00 00 00 00 00 ID2: 00 01 ID3: 00 02 MFG RESERVED: 01 AltBeacon Advertisement: 1b ff 18 01 be ac 53 70 6f 74 69 66 69 6e 64 4d 65 00 00 00 00 00 00 01 00 02 ca 01 LE set advertise enable on hci0 returned status 12 < HCI Command: ogf 0x08, ocf 0x0008, plen 32 1F 02 01 1A 1B FF 18 01 BE AC 53 70 6F 74 69 66 69 6E 64 4D 65 00 00 00 00 00 00 01 00 02 CA 01 > HCI Event: 0x0e plen 4 01 08 20 00 $
There we go.
The SpotifindMe app was written with Android Studio, and can be simply imported there.
The app handles a couple of things:
- checks if user has a valid Spotify API auth token
- if not, do nothing until user requested one (this will either use your Spotifiy Android app...