The EVVA Abrevva iOS SDK is a collection of tools to work with electronical EVVA access components. It allows for scanning and connecting via BLE.
- BLE Scanner for EVVA components
- Localize scanned EVVA components
- Disengage scanned EVVA components
- Read / Write data via BLE
Platform | Minimum Swift Version | Installation | Status |
---|---|---|---|
iOS 15.0+ | 5.7.1 / Xcode 14.1 | CocoaPods | Fully Tested |
watchOS 10.0+ | 5.7.1 / Xcode 14.1 | CocoaPods | Fully Tested |
Android | see EVVA Abrevva Android SDK |
CocoaPods is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate EVVA Abrevva iOS SDK into your Xcode project using CocoaPods, specify the pod in your Podfile
:
pod 'AbrevvaSDK'
To start off first initialize the SDK BleManager. You can pass an init callback closure for success indication.
import AbrevvaSDK
public class Example {
private var bleManager: BleManager?
private var bleDeviceMap = [String: BleDevice]()
func initialize() {
self.bleManager = BleManager { success, message in
debugPrint("BleManager initialized /w success=\(success)")
}
}
}
Use the BleManager to scan for components in range. You can pass several callback closures to react to the different events when scanning or connecting to components.
func scanForDevices() {
let timeout = 10_000
self.bleManager?.startScan(
{ device in
debugPrint("Found device /w address=\(device.address)")
self.bleDeviceMap[device.address] = device
},
{ error in
debugPrint("Scan started /w \(error ?? "success")")
},
{ error in
debugPrint("Scan stopped /w \(error ?? "success")")
},
nil, // mac filter
false, // allow duplicates
timeout
)
}
Get the EVVA advertisement data from a scanned EVVA component.
let ad = device.advertisementData
debugPrint(ad?.rssi)
debugPrint(ad?.isConnectable)
let md = ad?.manufacturerData
debugPrint(md?.batteryStatus)
debugPrint(md?.isOnline)
debugPrint(md?.officeModeEnabled)
debugPrint(md?.officeModeActive)
// ...
There are several properties that can be accessed from the advertisement.
public struct BleDeviceAdvertisementData {
public let rssi: Int
public let isConnectable: Bool?
public let manufacturerData: BleDeviceManufacturerData?
}
public struct BleDeviceManufacturerData {
public let companyIdentifier: UInt16
public let version: UInt8
public let componentType: UInt8
public let mainFirmwareVersionMajor: UInt8
public let mainFirmwareVersionMinor: UInt8
public let mainFirmwareVersionPatch: UInt16
public let componentHAL: Int
public let batteryStatus: Bool
public let mainConstructionMode: Bool
public let subConstructionMode: Bool
public let isOnline: Bool
public let officeModeEnabled: Bool
public let twoFactorRequired: Bool
public let officeModeActive: Bool
public let reservedBits: Int?
public let identifier: String
public let subFirmwareVersionMajor: UInt8?
public let subFirmwareVersionMinor: UInt8?
public let subFirmwareVersionPatch: UInt16?
public let subComponentIdentifier: String?
}
With the signalize method you can localize scanned EVVA components. On a successful signalization the component will emit a melody indicating its location.
func signalizeDevice(_ deviceId: String) async {
guard let device = self.bleDeviceMap[deviceId] else { return }
let success = await self.bleManager?.signalize(device)
debugPrint("Signalized /w success=\(success)")
}
For the component disengage you have to provide access credentials to the EVVA component. Those are generally acquired in the form of access media metadata from the Xesar software.
func disengageDevice(_ deviceId: String) async {
guard let device = self.bleDeviceMap[deviceId] else { return }
let mobileId = "" // sha256-hashed hex-encoded version of `xsMobileId` found in blob data.
let mobileDeviceKey = "" // mobileDeviceKey mobile device key string from `xsMOBDK` found in blob data.
let mobileGroupId = "" // mobileGroupId mobile group id string from `xsMOBGID` found in blob data.
let mediumAccessData = "" // mediumAccessData access data string from `mediumDataFrame` found in blob data.
let isPermanentRelease = false // office mode flag.
let timeout = 10_000
let status = await self.bleManager?.disengage(
device,
mobileId,
mobileDeviceKey,
mobileGroupId,
mediumAccessData,
isPermanentRelease,
timeout
)
debugPrint("Disengage /w status=\(status)")
}
There are several access status types upon attempting the component disengage.
public enum DisengageStatusType: String {
/// Component
case AUTHORIZED
case AUTHORIZED_PERMANENT_ENGAGE
case AUTHORIZED_PERMANENT_DISENGAGE
case AUTHORIZED_BATTERY_LOW
case AUTHORIZED_OFFLINE
case UNAUTHORIZED
case UNAUTHORIZED_OFFLINE
case SIGNAL_LOCALIZATION
case MEDIUM_DEFECT_ONLINE
case MEDIUM_BLACKLISTED
case ERROR
/// Interface
case UNKNOWN_STATUS_CODE
case UNABLE_TO_CONNECT
case TIMEOUT
case UNABLE_TO_SET_NOTIFICATIONS
case UNABLE_TO_READ_CHALLENGE
case ACCESS_CIPHER_ERROR
}