Skip to content

Proximity

Did you ever want to know who is around you? I was flying back on a plane many years ago while coding on a project I was developing for a company. I was taking a quick break and for whatever reason as I looked around at people using their phones and other devices I wanted to have an easy way to know more about who was around me. So from there I decided to write a scanner app to gather information about bluetooth devices discoverable from my airplane seat. This post is what came out of that. I’ve built a quick prototype right then, during the flight, and as soon as I got it working it showed the name of people around me, people I never met, or seen before. I later  used SpriteKit to drive  a visualization I then found quite engaging.

Central and Peripheral

Here are some of the main “players” you should be aware of when dealing with CoreBluetooth. CBCentralManager and CBPeripheral. An iOS device is able to be both, concurrently as well. It can work as a peripheral, advertising services for example, or it can work as a central, discovering peripherals that advertise services for example.

CBCentralManager

From Apple’s docs: CBCentralManager objects are used to manage discovered or connected remote peripheral devices (represented by CBPeripheral objects), including scanning for, discovering, and connecting to advertising peripherals.

A central role should be adopted by devices that have more processing power capabilities, more memory etc… Examples can be phones, tablets.

CBPeripheral

From Apple’s docs: The CBPeripheral class represents remote peripheral devices that your app—by means of a central manager (an instance of CBCentralManager)—has discovered advertising or is currently connected to. Peripherals are identified by universally unique identifiers (UUIDs), represented by NSUUID objects. Peripherals may contain one or more services or provide useful information about their connected signal strength.

A peripheral role is usually adopted by smaller devices, low power and in general resource constrained type devices.

As you work with bluetooth technology you might hear the term GAP (Generic Access Profile). That is really what controls connections and advertising in bluetooth. It’s what makes your device visible to the outside world. It also defines a device role, namely central devices and or peripheral devices.

There are two ways to send advertising data over GAP. One is by using Advertising Data Payloads (mandatory), and the other is by scanning response payloads (optional).

So why is there an optional case (Scan Response payload)? That is a way to enable developers to fit more information if needed. Both options are limited to 31 bytes.

What happens once devices connect? Usually advertising stops and we get into what is known as GATT mode (Generic Attribute Profile). This mode defines the way BLE devices transfer data back and forth leveraging what is knows as Services and Characteristics.

PERIPHERAL <-> GATT Server <-> SLAVE DEVICE

CENTRAL <-> GATT Client <-> MASTER DEVICE

GAP: One to many (Advertising)

GATT: One to One (connected)

BLE Peripherals can only be connected to one Central at any given time. As soon as a peripheral will connect to a central it will stop advertising itself to other devices.

Centrals can be connected to multiple peripherals concurrently (demo shows this).

A service is identified using UUID, 16-bit or 128-bit (custom case).

Core Framework Calls [iOS]

Here I will outline the main calls I’ve leveraged to drive the quick scanner demo.

Once you have your CBCentralManager object instantiated and ready to go you can call scanForPeripherals… on it. This call will start scan for peripherals that are currently advertising any service. Apple’s docs are clear on discouraging passing nil in the UUIDs list. This is mainly to respect processing power, battery life etc… For the purpose of this demo app though we are going to pass in nil since we want to discover any advertised service. It’s important to notice that while allowed, it will not work during background mode. Background scanning only works when passing in specific UUIDs.

When the central discovers a peripheral the CBCentralManagerDelegate call:

will trigger and there we leverage the RSSI information. The RSSI stands for Received Signal Strength Indication, and it’s measure in dB. This is what we are going to use to place peripherals in our visualization. The stronger the dB from a peripheral the closer it will be placed to the central (center of screen).

RSSI determines the peripheral-central distance on screen

As a side note, relying on raw RSSI values alone to determine the distance of a peripheral is not a reliable solution. It’s error prone due to the environment noise that affect the radio wave and signal strength. If you’re interested to find out more about this topic you might enjoy reading the paper called Distance Estimation of Smart Device using Bluetooth.

Even when using the RSSI LPF data, method outlined in the paper, a reliable distance calculation is not obtained. The chart below can give a good picture of the RSSI LPF results:

Once the app finds peripherals it will try to learn more about them by looking into their advertised services and characteristics.

The Central will first try to connect to the peripheral:

Upon connection the framework will call its delegate call:

At this point we have access to the peripheral object, so we can discover its services:

We set the designated controller in our app to be the peripheral’s delegate. This allows us to then learn about the services and then characteristics in each as we adopt these calls:

To find out about the characteristics we call discoverCharacteristics on the service objects we get back in the “didDiscoverServices” call:

This below is a simple representation of the structure bluetooth leverages in regards to services and characteristics:


Visualization Demo

Lets now take a look at the visualization developed. The main idea is pretty simple: Show the central at the center of the screen, and then place peripherals around using the peripheral’s RSSI value to determine peripheral-central distance on screen.

To draw this type of visualization I resorted to SpriteKit. We have a static central node at the center of the screen and as peripherals are discovered they’ll come in from the middle of the screen and land at the appropriate distance from the central.

Here’s a quick demo:

Bluetooth peripheral scanner demo

The peripheral node will keep updating its position relative to the central node as new advertising payload are discovered with their associated RSSI information. If the peripheral has an assigned name and the node is close enough to the central node the name of the peripheral will also be visible on the node’s perimeter.

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *