iBeacons have been around for quite some time now and are working all around you, even if you don't see them. They are pretty much the technological advancement of the QR code or standard barcode, emitting some sort of data package to any device that can pick them up via Bluetooth. So computers can pick these beacons up, any smartphone can, but what about all this new technology? Specifically, mixed and augmented reality devices like the HoloLens.
First you are going to need a couple things. Unity3D (Version 5.5.2 or later), Visual Studio 2015 or later with .NET 4, and a HoloLens with the latest firmware. An actual device is needed to test this out as the simulator doesn't pick it up. You will also need to go find and download the Windows.Devices.Bluetooth DLL from Microsoft directly. I will explain how to use it later.
Background on How This Works
So there is a process we are going to have to go through for this to work. Unity only technically supports .NET 3.5 and earlier. So we will have to create a DLL that is .NET 4.0 based to use the Windows.Devices.Bluetooth namespace along side it. We will call it the HoloBeaconScanner DLL.
- Your Unity app will call the HoloBeaconScanner DLL that I built, setup a scanner, register the beacon found event handler and start scanning.
- Once a beacon comes into range, we will grab the data bytes and format them DLL side.
- Then when we have everything formatted the way we want, we invoke an event handler that currently sends back a string that is delimited by a `*` (star character). In the future I will modify it with a dictionary or JSON package, but for now we will create a delimited string.
In the diagram below I show you how everything is talking to one another.
Custom DLL Download
You can go ahead and download the actual HoloBeaconScanner.dll file:
Setting Up Our Project
- Open up Unity and start a new project
- Make sure your build settings are targeting the Windows Store with the HoloLens properties.
- Under your Assets folder, create a new folder called ‘Plugins’
- In this Plugins folder, copy the HoloBeaconScanner.dll
- Click on the DLL in Unity to see the DLL Import Settings. You should only select WSAPlayer and change the Platform settings like this:
- Under ‘Plugins’, create a folder called ‘WSA’
- In the WSA folder, place the Windows.Devices.Bluetooth.dll file
- Click on the DLL in Unity to see the Import Settings. You should see that everything is selected, which is fine. It will look like this:
</> Dive Into Code
Now we are ready to jump into the code on the Unity side. Note that we are going to wrap anything that calls the DLL in #if !UNITY_EDITOR and this is mainly so that the Unity Engine knows we don't want to compile that bit of code while in the editor. If you don't have this, the code will not build. You can read more about Platform Dependent Compilation on Unity3D’s website.
- First let’s create a new C# script and call it “BeaconDetector”
- Next lets set the namespace
- Next lets set a global Scanner class so we can start and stop it from a public function. We will also initialize it in the Start() function.
As you can see the Scanner class has an event handler on it called ScannedBeaconEventHandler. So we want to attach to that handler with our BeaconFound method.
- Setup our public functions for the UI to attach to. We want a few buttons that can link to the start and stop methods of the beacon scanner.
- Setup our found beacon event. The DLL is going to return a delimited string every time a beacon is scanned and found. The delimited string should contain our UUID, Major, Minor, Power and the Distance Value.
- Finally, I setup a simple class called “Beacon” so we can store all the data we collect from the scanner. Here is what it looks like.
Now when you run it on a HoloLens and a beacon is in range, you will be able to see if picking up the beacon info printed in the Console.
A big side note, if you want to update the UI, you are going to have to do it from the main thread. So you would want to run UI updates in a fixed update method or pass the information to another class to update the main thread.
Personally, I added a second class that create a pool of beacons the scanner found, and then used that pool elsewhere.
Here is an example of what I did with some of the UI elements and what it looks like in a HUD like environment.