Make an app that can scan and discover other BT peripherals and display them on a UITableView. To achieve this, we need a timer to schedule the scan for the surrounding devices. The timer fire every 3 seconds, but you can tweak it, based on what you need. Keep in mind that shorter timer could drain your battery.
To achieve our goal first of all we need to import 2 libraries (besides UIKit):
We’ll use AudioToolbox to notify the user when a device is discovered (by vibration) and the Core Bluetooth framework provides the classes needed for your apps to communicate with Bluetooth-equipped low energy (BLE) and Basic Rate wireless technology.
To manage discovered or connected remote peripheral devices including scanning for discovering and connecting to advertising peripherals, we need a CBCentralManager object. Then we set the outlet for the table view and the Timer property:
When a BLE device is detected after a scan, with the various informations, there is also RSSI, this value is the average signal strength of the samples received, since Core Location last reported the range of the device to your app.
Using RSSI it is really difficult to estimate accurate distance. If you are using many devices (every 1 m) you can estimate it but if the distance between pheripherals are large, it is difficult because of reflection and absorption of signal. You can try using fingerprinting for better accuracy and it’s a good topic for my next article (😜).
To stabilize the RSSI of each device founded we can use the “KalmanFilter”
Kalman filter is a widely applied algorithm to get a more accurate guess in noisy environment. It has a lot of applications in real life such as guidance, navigation control for vehicles, etc. Although it is mostly used to filter GPS data, this framework doesn’t have a ready-to-use solutions that work with GPS and is more general implementation of algorithm.
Kalman Filter uses a statistical predictive model to try to discern the difference between noise and signal, and filter out the noise. There are many variants of Kalman Filters, and different variants may be better or worse at reducing noise in specific conditions.
Now I declare the item dictionary in order to keep reference for every single Kalman Filter associated to each device:
In your viewDidLoad initialise your CentralManager with a specified delegate and dispatch queue (in this case we set it as nil). Don’t forget to set your ViewController as tableView.dataSource:
As said before we want the scan to be done every three seconds so let’s create a private method that programs the timer and starts the scan:
In this way the scanForPeripherals() method will be triggered every three seconds, let’s define it:
So the delegate that receives central events is our ViewController. The only required method is centralManagerDidUpdateState(_:) the central manager invoke it when its state updates, thereby indicating the availability of the central manager and we’ll use it to to manage bluetooth based on its status. We have different states, but the only two we need to consider are .poweredOff and .poweredOn; In fact we want to stop scanning peripherals when BT is turned off and instead we want to start it when is turned on:
Now, how do we know if we found a device? The method centralManager(_:didDiscover:advertisementData:rssi:) tells the delegate the central manager discovered a peripheral while scanning for devices:
Now we only need to setup our tableView:
For the full project, you can find it on my GitHub → there ❇️