Creating iOS application as Bluetooth Peripheral

Akshata Kulkarni
6 min readDec 2, 2019
Credit

Some days ago, I was working on BLE ( Bluetooth Low Energy) and was trying to make an iOS application which could act as the Bluetooth peripheral. To start with I did a lot of R&D on Bluetooth peripherals and started with the coding part and got stuck in between while performing BLE operations. And, to my rescue there weren’t many articles that could help in achieving it.

However, I dedicated more time into it and succeeded in completing. I don’t know, if I can call it motivation or not but it led me to write this article which could help anybody starting to work BLE Peripheral applications.

Initially, let us begin with brief introduction to BLE. Bluetooth is a communication channel between two or more devices.

The BLE devices are classified into two types: Central and Peripheral

Source: https://learn.adafruit.com/introduction-to-bluetooth-low-energy/gatt

Peripherals broadcast the data they have in the form of advertising packets.Peripherals are like server device.

On the other hand, Central is like a client device. It reads and writes to the peripheral device.

BLE GATT

GATT stands for Generic Attribute Profile.It defines data transfer back and forth from Bluetooth devices using Services and Characteristics.

Gatt transactions are based on Profiles, Services and Characteristics.

BLE Gatt Profile

Profile is a pre-defined collection of Services compiled together by either Bluetooth SIG or peripheral designers.

Services is used to break data into logic entities which again contain characteristics.

Characteristic is lowest level GATT transaction which encapsulates a single data point.

Now we are clear with basics we can move further and go on try creating sample application. If you want more information on BLE Gatt you can visit here.

Peripheral Application Sample

In this application, we will make our application act as a BLE peripheral and use LightBlue app from PunchThrough to act as server device so that our communication process is simple.

Initially, let’s start by creating simple iOS application.

I have created a basic UI to display read and write values. You can create your own custom UI as per your implementation.

To begin with, you need to import CoreBluetooth to use BLE functionalities and make View Controller subclass of CBPeripheralManagerDelegate.

import UIKit
import CoreBluetooth
class ViewController: UIViewController,CBPeripheralManagerDelegate {@IBOutlet weak var messageLabel: UILabel!
@IBOutlet weak var readValueLabel: UILabel!
@IBOutlet weak var writeValueLabel: UILabel!
}Creating iOS application as Bluetooth Peripheral

Now create the CBPeripheralManager instance and initiate it within viewDidLoad() method.

private var peripheralManager : CBPeripheralManager!override func viewDidLoad() {    super.viewDidLoad()
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
}Creating iOS application as Bluetooth Peripheral

Next step is to add PeripheralManager delegate method to get notified whenever there is change in bluetooth state.

The delegate method peripheralManagerDidUpdateState updates whether the bluetooth is On or Off or in any other state.

func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {switch peripheral.state {Creating iOS application as Bluetooth Peripheral
case .unknown:
print("Bluetooth Device is UNKNOWN")
case .unsupported:
print("Bluetooth Device is UNSUPPORTED")
case .unauthorized:
print("Bluetooth Device is UNAUTHORIZED")
case .resetting:
print("Bluetooth Device is RESETTING")
case .poweredOff:
print("Bluetooth Device is POWERED OFF")
case .poweredOn:
print("Bluetooth Device is POWERED ON")
addServices()
@unknown default:
print("Unknown State")
}
}

If the bluetooth is on, we need to add services and characteristics to the peripheral application which it exposes to the client device while advertising.

Add the below method to ViewController class.

private var service: CBUUID!
private let value = "AD34E"
func addServices() {
let valueData = value.data(using: .utf8)
Creating iOS application as Bluetooth PeripheralCreating iOS application as Bluetooth Peripheral
// 1. Create instance of CBMutableCharcateristic
let myChar1 = CBMutableCharacteristic(type: CBUUID(nsuuid: UUID()), properties: [.notify, .write, .read], value: nil, permissions: [.readable, .writeable])
let myChar2 = CBMutableCharacteristic(type: CBUUID(nsuuid: UUID()), properties: [.read], value: valueData, permissions: [.readable]) // 2. Create instance of CBMutableService
service = CBUUID(nsuuid: UUID())
let myService = CBMutableService(type: service, primary: true)
// 3. Add characteristics to the service
myService.characteristics = [myChar1, myChar2]
// 4. Add service to peripheralManager
peripheralManager.add(myService)
// 5. Start advertising
startAdvertising()
}

Now let us understand the above method.

  1. We create the characteristic by instantiating CBMutableCharacteristic. It takes type 4 parameters. Type, of type CBUUID, provides a unique identifier to the characteristic. Properties, which define whether a characteristic should be able to read, write or notify. Value, which is the characteristic value to be read by central device. And last is permission which tells either the characteristic is readable or writable or both.
  2. Create service of type CBMutable with new CBUUID specifying its type and whether it is a primary service or not.
  3. Add the previously created Characteristics to the service.
  4. Then add the service to peripheral using peripheralManager.
  5. Now call startAdvertising() like below to expose the data to other BLE devices.

The startAdvertising() method in turn calls peripheralManager’s startAdvertising method to start broadcasting the data.

func startAdvertising() {messageLabel.text = "Advertising Data"peripheralManager.startAdvertising([CBAdvertisementDataLocalNameKey : "BLEPeripheralApp", CBAdvertisementDataServiceUUIDsKey :     [service]])print("Started Advertising")}

Once it starts advertising lets use LightBlue app as client and explore how to read from and write to BLE peripheral.

Open the app and select the device name you have provided for “CBAdvertisementDataLocalNameKey” during advertising.

Select the device. The screen appears displaying the details about the peripheral device, the advertisement data, the services ,characteristics and other information like device information, battery info.

Let focus on services and characteristics.It shows the UUID of the service and the details about underlying characteristics the service consists along with its properties.

Click on any of the characteristics ,it transitions to the characteristic detail screen. It displays all the information about the characteristic.

You can write a value to or read data from peripheral using ‘Read again’ or ‘Write new value’.

PeripheralManager has delegate methods to respond to read, write and notify. Whenever a value is written to device the didReceiveWrite() method get called.

func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) {    messageLabel.text = "Writing Data"
if let value = requests.first?.value {
writeValueLabel.text = value.hexEncodedString()
//Perform here your additional operations on the data.
}
}

It receives the requests parameter which contains the write requests.

Once you get the value written through request data, you can do any operation needed.

I have added the extension of data to convert the received value of type Data to HexString type.

extension Data { struct HexEncodingOptions: OptionSet {
let rawValue: Int
static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
}
func hexEncodedString(options: HexEncodingOptions = []) -> String {
let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx"
return map { String(format: format, $0) }.joined()
}
}

It is same for reading data from peripheral. The method didReceiveRead method gets called every time a client device tries to read data from the peripheral.

You can perform any additional operation in didRecieveRead() method.

func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {    messageLabel.text = "Data getting Read"
readValueLabel.text = value
// Perform your additional operations here}

Now, the simple BLE Peripheral App is ready. You can work on to enhance and customize to your requirements. You can also get the project here.

If you feel the article was helpful, please clap, you know each can for clap 50 times😉, and encourage me futher to write more articles.

📝 Read this story later in Journal.

👩‍💻 Wake up every Sunday morning to the week’s most noteworthy stories in Tech waiting in your inbox. Read the Noteworthy in Tech newsletter.

--

--

Akshata Kulkarni

iOS Developer📱 @ Global Edge Software Limited | Tech Enthusiast | Young Explorer |