Introduction: IBeacon Entry System With the Raspberry Pi and Azure

In late March I went to a hackathon at Universal Studios. We created a system where guests could bypass the queue line by completing a series of tasks that would lead them around the land the ride is in where the average completion time was 66% of the current ride wait time. This system pulls people from the queue line while providing the incentive of a more rich experience, less down time, and potentially less wait time. Of course that sounds all fancy, but without actually demonstrating the technology behind such a system, it's still just an idea.

Or is it?

In the video, you can see me demonstrate the backbone of this very system. It uses iBeacons to trigger actions both on the phone and in the environment. The phone is in charge of tracking the guest's progress moving from location to location by recognizing certain iBeacons. Once the guest has completed every task, it sends a unique iBeacon signature to a Microsoft Azure SQL database, and the guest proceeds to a special entrance of the ride. Here, the guest's phone now becomes an iBeacon broadcasting the unique signiture. Once the gateway device detects an iBeacon, it checks it against the Azure database. If there is a match, the environment signals that entry is allowed, and the signature is deleted from the database. If there isn't a match, the guest is turned away. Only guests who complete the tasks are allowed to enter, and they cannot enter more than once per completion.

In this instrucable, I'll show you how to build and test the gateway device using a Raspberry Pi, iPhone, and Bluetooth LE dongle. We will:

  1. Learn how to transmit and scan for iBeacons with the Raspberry Pi and Python3
  2. Learn how to connect the Raspberry Pi to Azure with Python3
  3. Create a new Azure SQL database and Azure Mobile Service
  4. Connect all the pieces together to form our gateway

Things you will need:

  • A functioning Raspberry Pi (preferably B or B+) with Raspbian connected to the internet
  • A Bluetooth LE USB dongle
  • A Microsoft Azure account
  • An iPhone running iOS 8+ (demo code is written in Swift)
  • Optional but recommended: Apple Developer account to sideload the iOS demo app
  • Optional: a Blink(1) USB dongle or some other means of indicating program status

The code for this project can be found on my GitHub page.

Have an Android phone? Check out the last page.

Step 1: Installing and Transmitting an IBeacon

Let's start by turning the Raspberry Pi into an iBeacon. This will install the Bluetooth libraries we need and let us see that our BLE dongle is working. We'll use apt-get to install our dependencies:

sudo apt-get update;sudo apt-get install -y libbluetooth-dev bluez

For good measure, let's shutdown the Pi and restart. If the BLE dongle is not already inserted, do that now. Never connect or remove USB devices from the Pi when it's powered on. Doing so can result in power surges that cause the Pi to reboot. Once the terminal is back up, enter the following commands:

sudo hciconfig hci0 up

sudo hciconfig hci0 leadv

sudo hciconfig hci0 noscan

sudo hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61 00 00 00 00 CA 00

Just like that, the Pi should now be broadcasting an iBeacon, but how can we check? A company called Radius Networks offers a free app for iOS and Android that scans for nearby iBeacons. The app needs to be told what iBeacon packet to look for. When adding the new target, the UUID should be "E20A39F4-73F5-4BC4-A12F-17D1AD07A961", the Major "0", and the Minor "0". After saving, there should now be a found entry with the name you gave it. The app will also show you a nifty feature of iBeacons: it can approximate the distance from your phone to the iBeacon.

Once you're done, use this line to turn the iBeacon off:

sudo hciconfig hci0 noleadv<br>

If you had trouble with this step or want to learn more about what an iBeacon is, check out this Adafruit tutorial about turning the Pi into an iBeacon. Once it's working, we'll reverse this and turn the Pi into a scanner.

Note: You can use the above code as-is on an Intel Edison because bluez is already installed and the compute module has Bluetooth built in.

Step 2: Scanning for IBeacons

Scanning for iBeacons is a little more complex. We're going to need to install the BlueZ Python3 module for this. I've found that the easiest way to guarantee that a module was installed for Python3 instead of Python2 is to use pip. You likely already have pip on the Pi, but we need the Python3 version, specifically pip-3.2 (because Python3.2 is the current default version). To install:

sudo apt-get install python-dev python3-dev python3-setuptools python3-pip
sudo pip-3.2 install pybluez

While you might have to change some of the files later on, if you want to follow along with Python2, install via apt-get:

sudo apt-get install pybluez

Now that the module is installed, we can use this file to scan for iBeacons (GitHub / direct download at top of page). This file was originally made by John Shovic (GitHub), and I updated it to work with Python3 and with this project. Of course the easiest way to get this and the other files onto the Pi is clone the repository. Running the file will turn the Pi into an iBeacon scanner.

git clone https://github.com/flyinactor91/RasPi-iBeacons

cd RasPi-iBeacons

sudo python3 blescan.py

Tada! It's now...oh wait nothing's happening. What's going on? There are no iBeacons in the air. Let's fix that. That iBeacon app can also broadcast/transmit. Choose any of the default options; it doesn't matter what the UUID, Major, or Minor values are. Once it's turned on, you should see the Pi start to print out gibberish, but that gibberish should match the gibberish on your phone. Then turn the app's iBeacon off, and the Pi should stop.

So far, we've enabled the Pi to scan for iBeacons and demonstrated that our phone can transmit them. Before we can do more with the Pi, we need to set-up our Azure back-end.

Step 3: Creating the Azure Mobile Service and SQL Database: Part 1

It's time to work with Azure. We will create a new Azure Mobile Service, and, in doing so, the SQL database will be made for us. Let's get started.

Note: For the sake of clarity during this tutorial, I'm going to use the actual server name, application key, user name, and password in plain text during setup. By the time you read this, the server will have been deleted, so make sure you replace the tutorial data with your own.

First go to your Azure management portal. Click "+ NEW" in the bottom left and go to Compute -> Mobile Service -> Create. This should bring up the first set-up dialogue page. We're going to set-up a new mobile service called "GatewayService" which uses a new SQL database instance. On the second page, we configure the new SQL database. For this tutorial, the database is called "rpitutorial" with the username "myrpiuser" and password "Raspbian#1".

After clinking ok, it will take a minute for the new service and server to be created. Once it is, there's a few more things we need to do.

Step 4: Creating the Azure Mobile Service and SQL Database: Part 2

Once the service is created, go to it's dashboard. Just below the image, set the language option to iOS and expand the "Connect to an existing iOS app" option. Then in step 2, set the language from Objective-C to Swift.

We need to get the server url and application key. This is found in the code line just above step 3. For this tutorial, the url is "https://gatewayservice.azure-mobile.net/" and the key "ljDJAhCqaMSUtTVcPuUxOMDPGqljsE33".

A few more things. To keep things simple, go ahead and press the green "Create Item Table" button in step 3. This will create a new table called "Item" in the new SQL database. This is where the iBeacon strings will be stored for our gateway system. Also you'll need to go to our new SQL database to find the database url at the bottom of its dashboard. In this tutorial, that's "qcezk07lpu.database.windows.net"

Next up we will connect our iOS demo app to our new mobile service.

Step 5: Connect IOS Demo to Azure

In the GitHub repository is a folder named BeaconAzureDemo. This folder contains the XCode project for our Swift iOS app. Yes you'll need access to a Mac with XCode on it. (If you don't, see the last page of this tutorial.) Open the xcodeproj file to begin.

There are two view controllers. ScannerViewController.swift is used when scanning for iBeacons. SenderViewController.swift is in charge of talking to Azure and broadcasting the phone's iBeacon. We'll be working in SenderViewController.swift here.

First off, set serverLocation to be the server url ("https://gatewayservice.azure-mobile.net/") and serverApplicationKey to be the server key ("ljDJAhCqaMSUtTVcPuUxOMDPGqljsE33"). Above this you can change the values in the iBeacon packet, but notice that Apple uses non-standard spacing for the UUID. That should be it. Make sure that your iPhone(4S or later) or iPad(3 or later) is set as the build destination and install it.

In the video above, you can see me demonstrate the phone successfully sending the BLE string to the server.You can see there is a "Broadcast" toggle just below the button. It will turn the iPhone's iBeacon broadcast on and off. You can test this by loading blescan.py on the Pi again.

If you've gotten this far, good job. The next part is going to be the hardest in terms of configuration.

Step 6: Install and Configure Pyodbc: Part 1

Here we go. While Microsoft offers an official Azure SDK for Python, it does not give us direct access to our Azure SQL databases. Instead, we will use pyodbc to do this. The pyodbc library is a Python wrapper for two other UNIX database utilities, each of which need to be individually configured. Did you write down the database url, database name, user name, and password? You're going to need them here.

First let's install the dependencies:

sudo apt-get install unixodbc unixodbc-dev freetds-dev freetds-bin tdsodbc

Now that the dependencies are installed, they need to be configured.

First we need to configure a generic connection to our server. Use

sudo nano /etc/freetds/freetds.conf

to edit the first file. At the end of the file, add the following lines:

[rpitestsqlserver]

	host = qcezk07lpu.database.windows.net

	port = 1433

	tds version = 8.0

You can use any name you want in those brackets as long as it doesn't contain any spaces. Use ctrl+x and then y + enter to save the file.

Now we can test to make sure the config file works. We're going to use the tsql utility. It needs the name of the configuration from the previous file, the user name (and server ID), and the password.

tsql -S rpitestsqlserver -U myrpiuser@qcezk07lpu -P Raspbian#1

If the config file is correct, you should eventually see a prompt line like that in the second screenshot above. Note: Many corporate networks and some ISPs block port 1433. If you're having connection issues, this is a likely cause.

Step 7: Install and Configure Pyodbc: Part 2

Before we can move on to the next config file, we need to locate two driver files, libtdsodbc.so and libtdsS.so, whose locations differ depending on the Linux distro. The find utility is better than grep at finding file names, but it does need root permissions to access certain root directories as shown above.

sudo find / -name libtdsodbc.so

sudo find / -name libtdsS.so

The files should be located in the same directory, but it doesn't hurt to check. I found mine in "/usr/lib/arm-linux-gnueabihf/odbc/". Now we can configure the driver config file. Use nano to open the existing empty file:

sudo nano /etc/odbcinst.ini

Add the following lines as-is unless your driver and setup locations are different:

[FreeTDS]

Description = TDS driver (Sybase/MS SQL)

Driver = /usr/lib/arm-linux-gnueabihf/odbc/libtdsodbc.so

Setup = /usr/lib/arm-linux-gnueabihf/odbc/libtdsS.so

CPTimeout =

CPReuse =

FileUsage = 1

Step 8: Install and Configure Pyodbc: Part 3

Only one more config file. Again load it into nano:

sudo nano /etc/odbc.ini

This file will need the config name we used in freetds.conf and the name of our database. You should give this new config name something that identifies it as using the previous config name. Here is what it looks like for this tutorial:

[rpitestsqlserverdatasource]

Driver = FreeTDS

Description = ODBC connection via FreeTDS

Trace = No

Servername = rpitestsqlserver

Database = rpitutorial

TDS_Version = 8.0

Now that we have all of our dependencies configured, it's time for one final test, this time using isql. It looks similar to tsql with the -P parts missing. Just make sure that it uses the config settings we just made.

isql -v rpitestsqlserverdatasource myrpiuser@qcezk07lpu Raspbian#1

Once your screen looks like the screenshot, everything is successfully configured. You can make a few sql queries to verify that it's working.

Step 9: Install and Configure Pyodbc: Part 4

After all of that, it's now time to install pyodbc. As with the BlueZ module, we'll install it via pip for Python3.

sudo pip-3.2 install pyodbc

To install it on Python2, use apt-get.

sudo apt-get install pyodbc

Now it is time to test our installation. Open up a python3 shell and follow along with the code below. It shows me connecting to the SQL database and reading data from the table that was created earlier.

pi@dupRasPi:~$ python3

Python 3.2.3 (default, Mar  1 2013, 11:53:50)

[GCC 4.6.3] on linux2

Type "help", "copyright" or "license" for more information.

>>> import pyodbc  #If anything went wrong during installation, it will happen here

>>> dsn = 'rpitestsqlserverdatasource'

>>> user = 'myrpiuser@qcezk07lpu'

>>> password = 'Raspbian#1'

>>> database = 'rpitutorial'

>>> 

>>> connString = 'DSN={0};UID={1};PWD={2};DATABASE={3};'.format(dsn,user,password,database)

>>> conn = pyodbc.connect(connString)  #If anything went wrong during configuration, it will happen here

>>> cursor = conn.cursor()

>>> cursor.execute('select id, uuid from [Item]')

>>> row = cursor.fetchone()

>>> if row: print(row)

...

('CDA360A6-08F2-4547-81A2-0DC9A343E8CC', 'E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 62 00 00 00 00')

conn.close()

quit()

We create the connection string, connect to the server, perform a query, read the response, and finally close the connection. With pyodbc working, we're so close to the end.

Step 10: Testing the Gateway

Now that all of the individual components are working, it's time to put everything together. If everything was set-up correctly, it should be as simple as running a file, one you've already downloaded onto the Pi if the repository was cloned. If not, the file is available at the top of the page.

Of course we need to supply the dsn, user, password, and database we used when we were testing the pyodbc install, but that should be it. Once those are added, run the file.

sudo python3 gatewayScanner.py

Now, when you toggle the demo app's broadcast to 'on', the Pi should respond by turning the Blink(1) green (or whatever else you supplied as a status indicator). If you were to leave the broadcast on, the Blink(1) will eventually turn red. This is because the Pi deleted the found iBeacon packet from the database when it turned the light green. Try sending the string to the server again. The Pi should light up green once more.

It took a lot of components, but we finally have a system that uses iBeacons to allow conditional entry with our iPhone, Raspberry Pi, and Azure. A next possible step would be to connect the Pi to a solenoid door lock so that we have a physical mechanism to prevent unauthorized entry, but that's for you guys to figure out.

I have a bonus section about hacking this with other systems if you want to read a little more.

Step 11: Bonus Hacking

OK...let's do some hacking.

What if I don't have an Apple Dev account and can't load the demo app? What if I have an Android phone? What if Microsoft finally adds iBeacon support to their Lumia phones (fingers crossed) and I want to use that instead?

Good news: we can hack this set-up.

Remember the testing app by Radius Networks from the beginning of this instructable? We can actually use that to grant us entry. Because the phone won't send the iBeacon string to the database, we'll need to do that ourselves through the database management portal. It's found on the bottom black bar when looking at the database dashboard.

First, go to "Design" (bottom left). Since we clicked the green button earlier, there should already be a table called "Item". Click "edit". Now add a new column called "uuid" and set its type to nvarchar(max). Go to the "Data" tab and add a new row. Set the id to whatever you want. The uuid should be the uuid with the major and minor in hex form. For example, if the app says the uuid is "E20A39F4-73F5-4BC4-A12F-17D1AD07A962" with a major value of "2" and a minor value of "12", the row's uuid would be "E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 62 00 02 00 0C".

The other change we'll need to make is preventing the gateway from deleting the row when it grants entry. All we need to do here is comment-out line 54 in gatewayScanner.py so that it looks like

#deleteRowWithPacket(key)

That's it. Now we can use the gateway with a store app on both iOS and Android. You can add more rows to the database to allow you and your friends access and, of course, revoke that access later on.

Have fun hacking!