PiBeacon - Making an iBeacon from a Raspberry Pi

When I first heard about iBeacons, I thought it would be a great idea to build one. It seemed doable for an ex-developer-would-like-to-code-again-but-doesn-t-have-a-lot-of-spare-time like me.

So I grabbed my Rapsberry Pi, and found a couple of articles describing how to make an iBeacon out of it. Unfortunately, none would tell exactly what I wanted: a simple service launched at boot, easy enough to configure, with no complicated C code.

The first article I read is from Radius Networks. They seem to have developped a comprehensive platform enabling marketers to do a lot of location-based things in their apps. The post is almost exactly what I was looking for, except that for some reason their Bluetooth commands didn't work with my adapter.

In the second article from Carson McDonald, the iBeacon part is a C program. It worked instantly with my adapter, but I didn't want to dive into C code to maintain it, should I need/want to. So I kind of reverse-engineered the C program with a bluetooth debugger, to see exactly what commands were transmitted to the adapter.

Combining thes two articles, I was able to determine the commands compatible with my adapter and put together a fully autonomous PiBeacon.

This is what worked for me. Everything is on my github repo.

Shopping list

  • a Raspberry Pi. I had the B model in hand, but the A model should work just the same.
  • an SD Card for the system. Any will do as long as it's at least 4GB.
  • a Bluetooth 4.0 dongle. I chose the Inatek BTA-CSR4B5 because it's tiny, affordable and its chipset (CSR8510) is known to work well with Linux. You can find a list of tested Bluetooth adapters at eLinux.org.

Installation

Raspbian

Nothing fancy here, download the official Wheezy Raspbian, and write it on the SD Card.

Plug the Bluetooth dongle, boot the raspi and log in.

Because you don't want outdated software on your system, upgrade everything that needs to:

sudo apt-get update && sudo apt-get upgrade -y

(Also want a fresh firmware/kernel ? See rpi-update)

The BlueZ stack

Go to the BlueZ site to know what the latest version is and replace it in the following commands on your raspi:

wget https://www.kernel.org/pub/linux/bluetooth/bluez-5.14.tar.xz
tar xvJf bluez-5.14.tar.xz
cd bluez-5.14
./configure --disable-systemd --enable-library
make
make install

Verify that your Bluetooth dongle is recognized: type hciconfig to see if your device is listed. It will most probably be named hci0. If you don't see "UP RUNNING", type sudo hciconfig hci0 up.

Scripts

Now that the Raspi is fully installed, we can transform it into an iBeacon.

We only use programs that are part of the BlueZ stack: hciconfig and hcitool.

There are three parts:

  • a start script, to start the iBeacon advertising
  • a stop script, to stop advertising
  • a config file, used by both scripts

For convenience, create a directory named iBeacon in /home/pi, and put these three files there.

The config file

Since you could have several iBeacons in the same place, this file contains the values enabling us to identify an iBeacon.

Name it ibeacon.conf

#all values must be in hex form separated by spaces between every two hex digits
export BLUETOOTH_DEVICE=hci0
export UUID="e2 c5 6d b5 df fb 48 d2 b0 60 d0 f5 a7 10 96 e0"
export MAJOR="00 16"
export MINOR="00 08"
export POWER="c5"

You can change major/minor values at your linking.

The start script

Name it ibeacon_start

#!/bin/sh
. ./ibeacon.conf
echo "Launching virtual iBeacon..."
sudo hciconfig $BLUETOOTH_DEVICE up
sudo hciconfig $BLUETOOTH_DEVICE noleadv
sudo hciconfig $BLUETOOTH_DEVICE leadv 0
sudo hcitool -i hci0 cmd 0x08 0x0008 1e 02 01 1a 1a ff 4c 00 02 15 $UUID $MAJOR $MINOR $POWER 00
echo "Complete"

The stop script

Name it ibeacon_stop

#!/bin/sh
. ./ibeacon.conf
echo "Disabling virtual iBeacon..."
sudo hciconfig $BLUETOOTH_DEVICE noleadv
echo "Complete"

Test

Type ./ibeacon_start

The iBeacon should start advertising (broadcasting) its identifiers.

You can verify that the iBeacon is running by using an app on your Android or iOS device:

Of course, your device has to be Bluetooth 4.0 capable.

You can stop your iBeacon with the following command: ./ibeacon_stop

Making it a service

Put this script in a file named ibeacon_install_service.sh:

#! /bin/bash
# check root permissions
if [[ $UID != 0 ]]; then
  echo "Please start the script as root or sudo!"
  exit 1
fi

apt-get install bluez -y

sed "s:/home/pi/iBeacon:$(dirname $(readlink -f $0)):" > /etc/init.d/ibeacon << "EOF"
#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:$PATH

DESC="iBeacon Application Software"
PIDFILE=/var/run/ibeacon.pid
SCRIPTNAME=/etc/init.d/ibeacon

case "$1" in
  start)
    printf "%-50s" "Starting ibeacon..."
    cd /home/pi/iBeacon
    ./ibeacon_start
    ;;
  stop)
    printf "%-50s" "Stopping ibeacon..."
    cd /home/pi/iBeacon
    ./ibeacon_stop
    ;;
  restart)
    $0 stop
    $0 start
    ;;
  *)
    echo "Usage: $0 {start|stop|restart}"
    exit 1
esac
EOF

chmod +x /etc/init.d/ibeacon

update-rc.d -f ibeacon start 80 2 3 4 5 . stop 30 0 1 6 .

Now sudo ibeacon_install_service.sh to install the ibeacon service.

The ibeacon service starts automatically when the raspi boots. You can also start/stop it manually by typing sudo /etc/init.d/ibeacon start and sudo /etc/init.d/ibeacon stop.

PiBeacon - done

Congratulations, you now have a fully autonomous PiBeacon!

If you want to know a little more about iBeacons and what you can do with it, you can read this post by Dave Addey.