All Projects → troystribling → Bluecap

troystribling / Bluecap

Licence: mit
iOS Bluetooth LE framework

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Bluecap

Swiftlyext
SwiftlyExt is a collection of useful extensions for Swift 3 standard classes and types 🚀
Stars: ✭ 31 (-95.37%)
Mutual labels:  swift-framework, cocoapods, carthage
Koyomi
Simple customizable calendar component in Swift 📆
Stars: ✭ 716 (+7.03%)
Mutual labels:  swift-framework, cocoapods, carthage
Bluetonium
Bluetooth mapping in Swift
Stars: ✭ 159 (-76.23%)
Mutual labels:  bluetooth-low-energy, cocoapods, carthage
Pulltodismiss
You can dismiss modal viewcontroller like Facebook Messenger by pulling scrollview or navigationbar in Swift.
Stars: ✭ 456 (-31.84%)
Mutual labels:  swift-framework, cocoapods, carthage
L10n Swift
Localization of the application with ability to change language "on the fly" and support for plural form in any language.
Stars: ✭ 177 (-73.54%)
Mutual labels:  swift-framework, cocoapods, carthage
Loadingshimmer
An easy way to add a shimmering effect to any view with just one line of code. It is useful as an unobtrusive loading indicator.
Stars: ✭ 1,180 (+76.38%)
Mutual labels:  swift-framework, cocoapods, carthage
Bluetoothkit
Easily communicate between iOS/OSX devices using BLE
Stars: ✭ 2,027 (+202.99%)
Mutual labels:  bluetooth-low-energy, cocoapods, carthage
Contentful.swift
A delightful Swift interface to Contentful's content delivery API.
Stars: ✭ 132 (-80.27%)
Mutual labels:  swift-framework, cocoapods, carthage
Xcglogger
A debug log framework for use in Swift projects. Allows you to log details to the console (and optionally a file), just like you would have with NSLog() or print(), but with additional information, such as the date, function name, filename and line number.
Stars: ✭ 3,710 (+454.56%)
Mutual labels:  swift-framework, cocoapods, carthage
Swiftinstagram
Instagram API client written in Swift
Stars: ✭ 570 (-14.8%)
Mutual labels:  swift-framework, cocoapods, carthage
Marshmallow
A lightweight library for converting complex objects to and from simple Python datatypes.
Stars: ✭ 5,857 (+775.49%)
Mutual labels:  serialization, deserialization
Jlroutes
URL routing library for iOS with a simple block-based API
Stars: ✭ 5,528 (+726.31%)
Mutual labels:  cocoapods, carthage
Flexiblepagecontrol
A flexible UIPageControl like Instagram.
Stars: ✭ 638 (-4.63%)
Mutual labels:  cocoapods, carthage
Haptica
Easy Haptic Feedback Generator 📳
Stars: ✭ 587 (-12.26%)
Mutual labels:  cocoapods, carthage
Flyoverkit
360° flyover on a MKMapView 🚁
Stars: ✭ 666 (-0.45%)
Mutual labels:  cocoapods, carthage
Badgehub
A way to quickly add a notification badge icon to any view. Make any view of a full-fledged animated notification center.
Stars: ✭ 592 (-11.51%)
Mutual labels:  swift-framework, cocoapods
Guitar
A Cross-Platform String and Regular Expression Library written in Swift.
Stars: ✭ 641 (-4.19%)
Mutual labels:  cocoapods, carthage
Bridge Deprecated
[DEPRECATED]: Prefer Retrofit/OkHttp by Square, or Fuel for Kotlin
Stars: ✭ 624 (-6.73%)
Mutual labels:  serialization, deserialization
Swiftoverlays
SwiftOverlays is a Swift GUI library for displaying various popups and notifications
Stars: ✭ 621 (-7.17%)
Mutual labels:  cocoapods, carthage
Sidemenu
Simple side/slide menu control for iOS, no code necessary! Lots of customization. Add it to your project in 5 minutes or less.
Stars: ✭ 5,267 (+687.29%)
Mutual labels:  cocoapods, carthage

Build Status CocoaPods Compatible Platform License Carthage Compatible

BlueCap: Swifter CoreBluetooth

Features

  • A futures interface replacing protocol implementations.
  • Timeout for Peripheral connection, Service scan, Service + Characteristic discovery and Characteristic read/write.
  • A DSL for specification of GATT profiles.
  • Characteristic profile types encapsulating serialization and deserialization.
  • Example applications implementing CentralManager and PeripheralManager.
  • A full featured extendable scanner and Peripheral simulator available in the App Store.
  • Thread safe.
  • Comprehensive test coverage.

Requirements

  • iOS 12.0+
  • Xcode 11.3.1

Installation

CocoaPods

CocoaPods is an Xcode dependency manager. It is installed with the following command,

gem install cocoapods

Requires CocoaPods 1.1+

Add BluCapKit to your to your project Podfile,

platform :ios, '10.0'
use_frameworks!

target 'Your Target Name' do
  pod 'BlueCapKit', '~> 0.7'
end

To enable DBUG output add this post_install hook to your Podfile

Carthage

Carthage is a decentralized dependency manager for Xcode projects. It can be installed using Homebrew,

brew update
brew install carthage

To add BlueCapKit to your Cartfile

github "troystribling/BlueCap" ~> 0.7

To download and build BlueCapKit.framework run the command,

carthage update

then add BlueCapKit.framework to your project.

If desired use the --no-build option,

carthage update --no-build

This will only download BlueCapKit. Then follow the steps in Manual to add it to a project.

Manual

  1. Place the BlueCap somewhere in your project directory. You can either copy it or add it as a git submodule.
  2. Open the BlueCap project folder and drag BlueCapKit.xcodeproj into the project navigator of your applications Xcode project.
  3. Under your Projects Info tab set the iOS Deployment Target to 9.0 and verify that the BlueCapKit.xcodeproj iOS Deployment Target is also 9.0.
  4. Under the General tab for your project target add the top BlueCapKit.framework as an Embedded Binary.
  5. Under the Build Phases tab add BlueCapKit.framework as a Target Dependency and under Link Binary With Libraries add CoreLocation.framework and CoreBluetooth.framework.

Getting Started

With BlueCap it is possible to easily implement CentralManager and PeripheralManager applications, serialize and deserialize messages exchanged with Bluetooth devices and define reusable GATT profile definitions. The BlueCap asynchronous interface uses Following sections will describe supported use cases. Example applications are also available.

CentralManager

A simple CentralManager implementation that scans for Peripherals advertising a TiSensorTag Accelerometer Service, connects on peripheral discovery, discovers service and characteristics and subscribes to accelerometer data updates will be described.

All applications begin by calling CentralManager#whenStateChanges.

let manager = CentralManager(options: [CBCentralManagerOptionRestoreIdentifierKey : "us.gnos.BlueCap.central-manager-documentation" as NSString])

let stateChangeFuture = manager.whenStateChanges()

To start scanning for Peripherals advertising the TiSensorTag Accelerometer Service follow whenStateChanges() with CentralManager#startScanning and combine the two with the SimpleFutures FutureStream#flatMap combinator. An application error object is also defined,

public enum AppError : Error {
    case invalidState
    case resetting
    case poweredOff
    case unknown
    case unlikely
}

let serviceUUID = CBUUID(string: TISensorTag.AccelerometerService.uuid)

let scanFuture = stateChangeFuture.flatMap { [weak manager] state -> FutureStream<Peripheral> in
    guard let manager = manager else {
        throw AppError.unlikely
    }
    switch state {
    case .poweredOn:
        return manager.startScanning(forServiceUUIDs: [serviceUUID])
    case .poweredOff:
        throw AppError.poweredOff
    case .unauthorized, .unsupported:
        throw AppError.invalidState
    case .resetting:
        throw AppError.resetting
    case .unknown:
        throw AppError.unknown
    }
}

scanFuture.onFailure { [weak manager] error in
    guard let appError = error as? AppError else {
        return
    }
    switch appError {
    case .invalidState:
	break
    case .resetting:
        manager?.reset()
    case .poweredOff:
        break
    case .unknown:
        break
    }
}

Here when .poweredOn is received the scan is started. On all other state changes the appropriate error is thrown and handled in the error handler.

To connect discovered peripherals the scan is followed by Peripheral#connect and combined with FutureStream#flatMap,

var peripheral: Peripheral?

let connectionFuture = scanFuture.flatMap { [weak manager] discoveredPeripheral  -> FutureStream<Void> in
    manager?.stopScanning()
    peripheral = discoveredPeripheral
    return peripheral.connect(connectionTimeout: 10.0)
}

Here the scan is also stopped after a peripheral with the desired service UUID is discovered.

The Peripheral Services and Characteristics need to be discovered and the connection errors need to be handled. Service and Characteristic discovery are performed by 'Peripheral#discoverServices' and Service#discoverCharacteristics and more errors are added to AppError.

public enum AppError : Error {
    case dataCharactertisticNotFound
    case enabledCharactertisticNotFound
    case updateCharactertisticNotFound
    case serviceNotFound
    case invalidState
    case resetting
    case poweredOff
    case unknown
    case unlikely
}

let discoveryFuture = connectionFuture.flatMap { [weak peripheral] () -> Future<Void> in
    guard let peripheral = peripheral else {
        throw AppError.unlikely
    }
    return peripheral.discoverServices([serviceUUID])
}.flatMap { [weak peripheral] () -> Future<Void> in
    guard let peripheral = peripheral, let service = peripheral.services(withUUID: serviceUUID)?.first else {
        throw AppError.serviceNotFound
    }
    return service.discoverCharacteristics([dataUUID, enabledUUID, updatePeriodUUID])
}

discoveryFuture.onFailure { [weak peripheral] error in
    switch error {
    case PeripheralError.disconnected:
        peripheral?.reconnect()
    case AppError.serviceNotFound:
        break
    default:
	break
    }
}

Here a reconnect attempt is made if the Peripheral is disconnected and the AppError.serviceNotFound error is handled. Finally read and subscribe to the data Characteristic and handle the dataCharactertisticNotFound.

public enum AppError : Error {
    case dataCharactertisticNotFound
    case enabledCharactertisticNotFound
    case updateCharactertisticNotFound
    case serviceNotFound
    case invalidState
    case resetting
    case poweredOff
    case unknown
}

var accelerometerDataCharacteristic: Characteristic?

let subscriptionFuture = discoveryFuture.flatMap { [weak peripheral] () -> Future<Void> in
   guard let peripheral = peripheral, let service = peripheral.services(withUUID: serviceUUID)?.first else {
        throw AppError.serviceNotFound
    }
    guard let dataCharacteristic = service.service.characteristics(withUUID: dataUUID)?.first else {
        throw AppError.dataCharactertisticNotFound
    }
    accelerometerDataCharacteristic = dataCharacteristic
    return dataCharacteristic.read(timeout: 10.0)
}.flatMap { [weak accelerometerDataCharacteristic] () -> Future<Void> in
    guard let accelerometerDataCharacteristic = accelerometerDataCharacteristic else {
        throw AppError.dataCharactertisticNotFound
    }
    return accelerometerDataCharacteristic.startNotifying()
}.flatMap { [weak accelerometerDataCharacteristic] () -> FutureStream<Data?> in
    guard let accelerometerDataCharacteristic = accelerometerDataCharacteristic else {
        throw AppError.dataCharactertisticNotFound
    }
    return accelerometerDataCharacteristic.receiveNotificationUpdates(capacity: 10)
}

dataUpdateFuture.onFailure { [weak peripheral] error in
    switch error {
    case PeripheralError.disconnected:
        peripheral?.reconnect()
    case AppError.serviceNotFound:
        break
    case AppError.dataCharactertisticNotFound:
	break
    default:
	break
    }
}

These examples can be written as a single flatMap chain as shown in the CentralManager Example.

PeripheralManager

A simple PeripheralManager application that emulates a TiSensorTag Accelerometer Service supporting all Characteristics will be described. It will advertise the service and respond to characteristic write requests on the writable Characteristics.

First the Characteristics and Service are created and the Characteristics are then added to Service

// create accelerometer service
let accelerometerService = MutableService(uuid: TISensorTag.AccelerometerService.uuid)

// create accelerometer data characteristic
let accelerometerDataCharacteristic = MutableCharacteristic(profile: RawArrayCharacteristicProfile<TISensorTag.AccelerometerService.Data>())

// create accelerometer enabled characteristic
let accelerometerEnabledCharacteristic = MutableCharacteristic(profile: RawCharacteristicProfile<TISensorTag.AccelerometerService.Enabled>())

// create accelerometer update period characteristic
let accelerometerUpdatePeriodCharacteristic = MutableCharacteristic(profile: RawCharacteristicProfile<TISensorTag.AccelerometerService.UpdatePeriod>())

// add characteristics to service
accelerometerService.characteristics = [accelerometerDataCharacteristic, accelerometerEnabledCharacteristic, accelerometerUpdatePeriodCharacteristic]

Next create the PeripheralManager add the Service and start advertising.

enum AppError: Error {
    case invalidState
    case resetting
    case poweredOff
    case unsupported
    case unlikely
}

let manager = PeripheralManager(options: [CBPeripheralManagerOptionRestoreIdentifierKey : "us.gnos.BlueCap.peripheral-manager-documentation" as NSString])

let startAdvertiseFuture = manager.whenStateChanges().flatMap { [weak manager] state -> Future<Void> in
    guard let manager = manager else {
        throw AppError.unlikely
    }
    switch state {
    case .poweredOn:
        manager.removeAllServices()
        return manager.add(self.accelerometerService)
    case .poweredOff:
        throw AppError.poweredOff
    case .unauthorized, .unknown:
        throw AppError.invalidState
    case .unsupported:
        throw AppError.unsupported
    case .resetting:
        throw AppError.resetting
    }
}.flatMap { [weak manager] _ -> Future<Void> in
    guard let manager = manager else {
        throw AppError.unlikely
    }
    manager.startAdvertising(TISensorTag.AccelerometerService.name, uuids:[CBUUID(string: TISensorTag.AccelerometerService.uuid)])
}

startAdvertiseFuture.onFailure { [weak manager] error in
    switch error {
    case AppError.poweredOff:
        manager?.reset()            
    case AppError.resetting:
        manager?.reset()
    default:
	break
    }
    manager?.stopAdvertising()
}

Now respond to write events on accelerometerEnabledFuture and accelerometerUpdatePeriodFuture.

// respond to Update Period write requests
let accelerometerUpdatePeriodFuture = startAdvertiseFuture.flatMap {
    accelerometerUpdatePeriodCharacteristic.startRespondingToWriteRequests()
}

accelerometerUpdatePeriodFuture.onSuccess {  [weak accelerometerUpdatePeriodCharacteristic] (request, _) in
    guard let accelerometerUpdatePeriodCharacteristic = accelerometerUpdatePeriodCharacteristic else {
        throw AppError.unlikely
    }
    guard let value = request.value, value.count > 0 && value.count <= 8 else {
        return
    }
    accelerometerUpdatePeriodCharacteristic.value = value
    accelerometerUpdatePeriodCharacteristic.respondToRequest(request, withResult:CBATTError.success)
}

// respond to Enabled write requests
let accelerometerEnabledFuture = startAdvertiseFuture.flatMap {
    accelerometerEnabledCharacteristic.startRespondingToWriteRequests(capacity: 2)
}

accelerometerEnabledFuture.onSuccess { [weak accelerometerUpdatePeriodCharacteristic] (request, _) in
    guard let accelerometerEnabledCharacteristic = accelerometerEnabledCharacteristic else {
        throw AppError.unlikely
    }
    guard let value = request.value, value.count == 1 else {
        return
    }
    accelerometerEnabledCharacteristic.value = request.value
    accelerometerEnabledCharacteristic.respondToRequest(request, withResult:CBATTError.success)
}

See PeripheralManager Example for details.

Test Cases

Test Cases are available. To run type,

pod install

and run from test tab in generated workspace.

Examples

Examples are available that implement both CentralManager and PeripheralManager. The BluCap app is also available. The example projects are constructed using either CocoaPods or Carthage. The CocaPods projects require installing the Pod before building,

pod install

and Carthage projects require,

carthage update
BlueCap BlueCap provides CentralManager, PeripheralManager and iBeacon Ranging with implementations of GATT profiles. In CentralManager mode a scanner for Bluetooth LE peripherals is provided. In PeripheralManager mode an emulation of any of the included GATT profiles or an iBeacon is supported. In iBeacon Ranging mode beacon regions can be configured and monitored.
CentralManager CentralManager implements a BLE CentralManager scanning for services advertising the TiSensorTag Accelerometer Service. When a Peripheral is discovered a connection is established, services are discovered, the accelerometer is enabled and the application subscribes to accelerometer data updates. It is also possible to change the data update period.
CentralManagerWithProfile A version of CentralManager that uses GATT Profile Definitions to create services.
PeripheralManager PeripheralManager implements a BLE PeripheralManager advertising a TiSensorTag Accelerometer Service. PeripheralManager uses the onboard accelerometer to provide data updates.
PeripheralManagerWithProfile A version of Peripheral that uses GATT Profile Definitions to create services.
Beacon Peripheral emulating an iBeacon.
Beacons iBeacon ranging.

Documentation

BlueCap supports many features that simplify writing Bluetooth LE applications. Use cases with example implementations are described in each of the following sections.

  1. CentralManager: The BlueCap CentralManager implementation replaces CBCentralManagerDelegate and CBPeripheralDelegate protocol implementations with a Scala Futures interface using SimpleFutures.

  2. PeripheralManager: The BlueCap PeripheralManager implementation replaces CBPeripheralManagerDelegate protocol implementations with a Scala Futures interface using SimpleFutures.

  3. Serialization/Deserialization: Serialization and deserialization of device messages.

  4. GATT Profile Definition: Define reusable GATT profiles and add profiles to the BlueCap app.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].