From 50ac08106d4b9867a4f60778f945eac0f0123230 Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Thu, 5 Dec 2024 14:22:38 +0100
Subject: [PATCH 01/16] refactor: add interfaces changes and android
refactoring
---
.editorconfig | 2 +-
README.md | 134 +++----
android/build.gradle | 2 +-
.../plugins/capacitor/AbrevvaPluginBLE.kt | 359 ++++++++++--------
.../plugins/capacitor/AbrevvaPluginCrypto.kt | 1 -
src/plugins/ble/client.ts | 52 +--
src/plugins/ble/definitions.ts | 79 ++--
7 files changed, 308 insertions(+), 321 deletions(-)
diff --git a/.editorconfig b/.editorconfig
index b6355c4..21d392b 100755
--- a/.editorconfig
+++ b/.editorconfig
@@ -11,7 +11,7 @@ trim_trailing_whitespace = true
[*.java]
ij_java_imports_layout = $*, |, javax.**, java.**, |, *
-[*.gradle]
+[{*.gradle,*.kt}]
indent_size = 4
[*.md]
diff --git a/README.md b/README.md
index 032ac99..39445b8 100644
--- a/README.md
+++ b/README.md
@@ -93,7 +93,6 @@ const status = await AbrevvaBLEClient.disengage(
* [Interfaces](#interfaces)
-* [Enums](#enums)
@@ -105,29 +104,29 @@ const status = await AbrevvaBLEClient.disengage(
#### AbrevvaBLEInterface
-| Method | Signature |
-| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| **initialize** | (options?: InitializeOptions \| undefined) => Promise<void> |
-| **isEnabled** | () => Promise<BooleanResult> |
-| **isLocationEnabled** | () => Promise<BooleanResult> |
-| **startEnabledNotifications** | () => Promise<void> |
-| **stopEnabledNotifications** | () => Promise<void> |
-| **openLocationSettings** | () => Promise<void> |
-| **openBluetoothSettings** | () => Promise<void> |
-| **openAppSettings** | () => Promise<void> |
-| **requestLEScan** | (options?: RequestBleDeviceOptions \| undefined) => Promise<void> |
-| **stopLEScan** | () => Promise<void> |
-| **addListener** | (eventName: "onEnabledChanged", listenerFunc: (result: BooleanResult) => void) => PluginListenerHandle |
-| **addListener** | (eventName: string, listenerFunc: (event: ReadResult) => void) => PluginListenerHandle |
-| **addListener** | (eventName: "onScanResult", listenerFunc: (result: ScanResultInternal) => void) => PluginListenerHandle |
-| **connect** | (options: DeviceIdOptions & TimeoutOptions) => Promise<void> |
-| **disconnect** | (options: DeviceIdOptions) => Promise<void> |
-| **read** | (options: ReadOptions & TimeoutOptions) => Promise<ReadResult> |
-| **write** | (options: WriteOptions & TimeoutOptions) => Promise<void> |
-| **signalize** | (options: SignalizeOptions) => Promise<void> |
-| **disengage** | (options: DisengageOptions) => Promise<StringResult> |
-| **startNotifications** | (options: ReadOptions) => Promise<void> |
-| **stopNotifications** | (options: ReadOptions) => Promise<void> |
+| Method | Signature |
+| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **initialize** | (options?: InitializeOptions \| undefined) => Promise<void> |
+| **isEnabled** | () => Promise<BooleanResult> |
+| **isLocationEnabled** | () => Promise<BooleanResult> |
+| **startEnabledNotifications** | () => Promise<void> |
+| **stopEnabledNotifications** | () => Promise<void> |
+| **openLocationSettings** | () => Promise<void> |
+| **openBluetoothSettings** | () => Promise<void> |
+| **openAppSettings** | () => Promise<void> |
+| **requestLEScan** | (options?: BleScannerOptions \| undefined) => Promise<void> |
+| **stopLEScan** | () => Promise<void> |
+| **addListener** | (eventName: "onEnabledChanged", listenerFunc: (result: BooleanResult) => void) => PluginListenerHandle |
+| **addListener** | (eventName: string, listenerFunc: (event: ReadResult) => void) => PluginListenerHandle |
+| **addListener** | (eventName: "onScanResult", listenerFunc: (result: BleDevice) => void) => PluginListenerHandle |
+| **connect** | (options: DeviceIdOptions & TimeoutOptions) => Promise<void> |
+| **disconnect** | (options: DeviceIdOptions) => Promise<void> |
+| **read** | (options: ReadOptions & TimeoutOptions) => Promise<ReadResult> |
+| **write** | (options: WriteOptions & TimeoutOptions) => Promise<void> |
+| **signalize** | (options: SignalizeOptions) => Promise<void> |
+| **disengage** | (options: DisengageOptions) => Promise<StringResult> |
+| **startNotifications** | (options: ReadOptions) => Promise<void> |
+| **stopNotifications** | (options: ReadOptions) => Promise<void> |
#### InitializeOptions
@@ -144,17 +143,12 @@ const status = await AbrevvaBLEClient.disengage(
| **`value`** | boolean
|
-#### RequestBleDeviceOptions
+#### BleScannerOptions
-| Prop | Type |
-| ---------------------- | --------------------------------------------- |
-| **`services`** | string[]
|
-| **`name`** | string
|
-| **`namePrefix`** | string
|
-| **`optionalServices`** | string[]
|
-| **`allowDuplicates`** | boolean
|
-| **`scanMode`** | ScanMode
|
-| **`timeout`** | number
|
+| Prop | Type |
+| --------------- | ------------------- |
+| **`macFilter`** | string
|
+| **`timeout`** | number
|
#### PluginListenerHandle
@@ -171,27 +165,47 @@ const status = await AbrevvaBLEClient.disengage(
| **`value`** | string
|
-#### ScanResultInternal
-
-| Prop | Type |
-| ---------------------- | ----------------------------------------------- |
-| **`device`** | BleDevice
|
-| **`localName`** | string
|
-| **`rssi`** | number
|
-| **`txPower`** | number
|
-| **`manufacturerData`** | { [key: string]: T; }
|
-| **`serviceData`** | { [key: string]: T; }
|
-| **`uuids`** | string[]
|
-| **`rawAdvertisement`** | T
|
-
-
#### BleDevice
-| Prop | Type |
-| -------------- | --------------------- |
-| **`deviceId`** | string
|
-| **`name`** | string
|
-| **`uuids`** | string[]
|
+| Prop | Type |
+| ----------------------- | --------------------------------------------------------------------------------- |
+| **`deviceId`** | string
|
+| **`name`** | string
|
+| **`advertisementData`** | BleDeviceAdvertisementData
|
+
+
+#### BleDeviceAdvertisementData
+
+| Prop | Type |
+| ---------------------- | ------------------------------------------------------------------------------- |
+| **`rssi`** | number
|
+| **`isConnectable`** | boolean
|
+| **`manufacturerData`** | BleDeviceManufacturerData
|
+
+
+#### BleDeviceManufacturerData
+
+| Prop | Type |
+| ------------------------------ | ----------------------------------------------------------------------------------------------------- |
+| **`companyIdentifier`** | string
|
+| **`version`** | number
|
+| **`componentType`** | 'handle' \| 'escutcheon' \| 'cylinder' \| 'wallreader' \| 'emzy' \| 'iobox' \| 'unknown'
|
+| **`mainFirmwareVersionMajor`** | number
|
+| **`mainFirmwareVersionMinor`** | number
|
+| **`mainFirmwareVersionPatch`** | number
|
+| **`componentHAL`** | string
|
+| **`batteryStatus`** | 'battery-full' \| 'battery-empty'
|
+| **`mainConstructionMode`** | boolean
|
+| **`subConstructionMode`** | boolean
|
+| **`isOnline`** | boolean
|
+| **`officeModeEnabled`** | boolean
|
+| **`twoFactorRequired`** | boolean
|
+| **`officeModeActive`** | boolean
|
+| **`identifier`** | string
|
+| **`subFirmwareVersionMajor`** | number
|
+| **`subFirmwareVersionMinor`** | number
|
+| **`subFirmwareVersionPatch`** | number
|
+| **`subComponentIdentifier`** | string
|
#### DeviceIdOptions
@@ -249,7 +263,7 @@ const status = await AbrevvaBLEClient.disengage(
| **`mobileId`** | string
|
| **`mobileDeviceKey`** | string
|
| **`mobileGroupId`** | string
|
-| **`mobileAccessData`** | string
|
+| **`mediumAccessData`** | string
|
| **`isPermanentRelease`** | boolean
|
@@ -270,16 +284,4 @@ const status = await AbrevvaBLEClient.disengage(
| **random** | (options: { numBytes: number; }) => Promise<{ value: string; }> |
| **derive** | (options: { key: string; salt: string; info: string; length: number; }) => Promise<{ value: string; }> |
-
-### Enums
-
-
-#### ScanMode
-
-| Members | Value |
-| --------------------------- | -------------- |
-| **`SCAN_MODE_LOW_POWER`** | 0
|
-| **`SCAN_MODE_BALANCED`** | 1
|
-| **`SCAN_MODE_LOW_LATENCY`** | 2
|
-
diff --git a/android/build.gradle b/android/build.gradle
index 46c5a8a..4749ff4 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -70,7 +70,7 @@ dependencies {
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation "androidx.core:core-ktx:$coreKtx"
- implementation group: "com.evva.xesar", name: "abrevva-sdk-android", version: "1.0.21"
+ implementation group: "com.evva.xesar", name: "abrevva-sdk-android", version: "3.0.0"
testImplementation "junit:junit:$junitVersion"
diff --git a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
index ec38dab..0165cbd 100644
--- a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
+++ b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
@@ -6,10 +6,11 @@ import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.annotation.RequiresPermission
+import com.evva.xesar.abrevva.ble.BleDevice
import com.evva.xesar.abrevva.ble.BleManager
+import com.evva.xesar.abrevva.ble.BleWriteType
import com.evva.xesar.abrevva.util.bytesToString
import com.evva.xesar.abrevva.util.stringToBytes
-import com.getcapacitor.JSArray
import com.getcapacitor.JSObject
import com.getcapacitor.Logger
import com.getcapacitor.PermissionState
@@ -18,7 +19,9 @@ import com.getcapacitor.PluginCall
import com.getcapacitor.PluginMethod
import com.getcapacitor.annotation.CapacitorPlugin
import com.getcapacitor.annotation.PermissionCallback
-import no.nordicsemi.android.kotlin.ble.core.scanner.BleScanResult
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
import java.util.UUID
@CapacitorPlugin(
@@ -195,38 +198,25 @@ class AbrevvaPluginBLE : Plugin() {
@PluginMethod
fun requestLEScan(call: PluginCall) {
+ val macFilter = call.getString("macFilter", null)
val timeout = call.getFloat("timeout", 15000.0F)!!.toLong()
- this.manager.startScan({ success ->
- if (success) {
- call.resolve()
- } else {
- call.reject("requestLEScan(): failed to start")
- }
- }, { result ->
- Logger.debug(tag, "Found device: ${result.device.address}")
+ this.manager.startScan({ device ->
+ Logger.debug(tag, "Found device: ${device.address}")
- val scanResult = getScanResultFromNordic(result)
+ val bleDevice = getBleDeviceData(device)
try {
- notifyListeners("onScanResult", scanResult)
- } catch (e: java.util.ConcurrentModificationException) {
+ notifyListeners("onScanResult", bleDevice)
+ } catch (e: Exception) {
Logger.error(tag, "requestLEScan()", e)
}
- }, { address ->
- try {
- notifyListeners("connected|${address}", null)
- } catch (e: java.util.ConcurrentModificationException) {
- Logger.error(tag, "onConnect()", e)
- }
- }, { address ->
- try {
- notifyListeners("disconnected|${address}", null)
- } catch (e: java.util.ConcurrentModificationException) {
- Logger.error(tag, "onDisconnect()", e)
+ }, { success ->
+ if (success) {
+ call.resolve()
+ } else {
+ call.reject("requestLEScan(): failed to start")
}
- },
- timeout
- )
+ }, {}, macFilter, timeout)
}
@PluginMethod
@@ -240,13 +230,27 @@ class AbrevvaPluginBLE : Plugin() {
fun connect(call: PluginCall) {
val deviceId = call.getString("deviceId", "")!!
val timeout = call.getFloat("timeout", 16000.0F)!!.toLong()
+ val device = manager.getBleDevice(deviceId) ?: run {
+ return call.reject("connect(): device not found")
+ }
- manager.connect(deviceId, { success ->
+ manager.connect(device, { success ->
if (success) {
+ try {
+ notifyListeners("connected|${deviceId}", null)
+ } catch (e: java.util.ConcurrentModificationException) {
+ Logger.error(tag, "onConnect()", e)
+ }
call.resolve()
} else {
call.reject("connect(): failed to connect after $timeout ms")
}
+ }, {
+ try {
+ notifyListeners("disconnected|${deviceId}", null)
+ } catch (e: java.util.ConcurrentModificationException) {
+ Logger.error(tag, "onConnect()", e)
+ }
}, timeout)
}
@@ -254,9 +258,17 @@ class AbrevvaPluginBLE : Plugin() {
@RequiresPermission(value = "android.permission.BLUETOOTH_CONNECT")
fun disconnect(call: PluginCall) {
val deviceId = call.getString("deviceId", "")!!
+ val device = manager.getBleDevice(deviceId) ?: run {
+ return call.reject("disconnect(): device not found")
+ }
- manager.disconnect(deviceId) { success ->
+ manager.disconnect(device) { success ->
if (success) {
+ try {
+ notifyListeners("disconnected|${deviceId}", null)
+ } catch (e: java.util.ConcurrentModificationException) {
+ Logger.error(tag, "onDisconnect()", e)
+ }
call.resolve()
} else {
call.reject("disconnect(): failed to disconnect")
@@ -266,55 +278,70 @@ class AbrevvaPluginBLE : Plugin() {
@PluginMethod
@RequiresPermission(value = "android.permission.BLUETOOTH_CONNECT")
+ @OptIn(DelicateCoroutinesApi::class)
fun read(call: PluginCall) {
val deviceId = call.getString("deviceId", "")!!
val timeout = call.getFloat("timeout", 10000.0F)!!.toLong()
- val characteristic = getCharacteristic(call)
- ?: return call.reject("read(): bad characteristic")
+ val characteristic = getCharacteristic(call) ?: run {
+ return call.reject("read(): bad characteristic")
+ }
+ val device = manager.getBleDevice(deviceId) ?: run {
+ return call.reject("read(): device not found")
+ }
- manager.read(deviceId, characteristic.first, characteristic.second, { success, data ->
- if (success) {
+ GlobalScope.launch {
+ val data = device.read(characteristic.first, characteristic.second, timeout)
+ if (data != null) {
val ret = JSObject()
- ret.put("value", bytesToString(data!!))
+ ret.put("value", bytesToString(data))
call.resolve(ret)
} else {
call.reject("read(): failed to read from device")
}
- }, timeout)
+ }
}
@PluginMethod
@RequiresPermission(value = "android.permission.BLUETOOTH_CONNECT")
+ @OptIn(DelicateCoroutinesApi::class)
fun write(call: PluginCall) {
val deviceId = call.getString("deviceId", "")!!
val timeout = call.getFloat("timeout", 10000.0F)!!.toLong()
- val characteristic =
- getCharacteristic(call) ?: return call.reject("read(): bad characteristic")
- val value =
- call.getString("value", null) ?: return call.reject("write(): missing value for write")
-
- manager.write(
- deviceId,
- characteristic.first,
- characteristic.second,
- stringToBytes(value),
- { success ->
- if (success) {
- call.resolve()
- } else {
- call.reject("write(): failed to write to device")
- }
- },
- timeout
- )
+ val characteristic = getCharacteristic(call) ?: run {
+ return call.reject("write(): bad characteristic")
+ }
+ val value = call.getString("value", null) ?: run {
+ return call.reject("write(): missing value for write")
+ }
+ val device = manager.getBleDevice(deviceId) ?: run {
+ return call.reject("write(): device not found")
+ }
+
+ GlobalScope.launch {
+ val success = device.write(
+ characteristic.first,
+ characteristic.second,
+ stringToBytes(value),
+ BleWriteType.NO_RESPONSE,
+ timeout
+ )
+ if (success) {
+ call.resolve()
+ } else {
+ call.reject("write(): failed to write to device")
+ }
+ }
}
@PluginMethod
@RequiresPermission(value = "android.permission.BLUETOOTH_CONNECT")
fun signalize(call: PluginCall) {
val deviceId = call.getString("deviceId", "")!!
+ val device = manager.getBleDevice(deviceId) ?: run {
+ return call.reject("signalize(): device not found")
+ }
- manager.signalize(deviceId) { success ->
+ manager.signalize(device) { success ->
if (success) {
call.resolve()
} else {
@@ -330,15 +357,18 @@ class AbrevvaPluginBLE : Plugin() {
val mobileId = call.getString("mobileId", "")!!
val mobileDeviceKey = call.getString("mobileDeviceKey", "")!!
val mobileGroupId = call.getString("mobileGroupId", "")!!
- val mobileAccessData = call.getString("mobileAccessData", "")!!
+ val mediumAccessData = call.getString("mediumAccessData", "")!!
val isPermanentRelease = call.getBoolean("isPermanentRelease", false)!!
+ val device = manager.getBleDevice(deviceId) ?: run {
+ return call.reject("disengage(): device not found")
+ }
manager.disengage(
- deviceId,
+ device,
mobileId,
mobileDeviceKey,
mobileGroupId,
- mobileAccessData,
+ mediumAccessData,
isPermanentRelease
) { status ->
val result = JSObject()
@@ -350,50 +380,53 @@ class AbrevvaPluginBLE : Plugin() {
@PluginMethod
@RequiresPermission(value = "android.permission.BLUETOOTH_CONNECT")
+ @OptIn(DelicateCoroutinesApi::class)
fun startNotifications(call: PluginCall) {
val deviceId = call.getString("deviceId", "")!!
- val characteristic =
- getCharacteristic(call)
- ?: return call.reject("startNotifications(): bad characteristic")
-
- manager.startNotifications(
- deviceId,
- characteristic.first,
- characteristic.second,
- { success ->
- if (success) {
- call.resolve()
- } else {
- call.reject("startNotifications(): failed to set notifications")
- }
- }, { data ->
- val key =
- "notification|${deviceId}|${(characteristic.first)}|${(characteristic.second)}"
-
- val ret = JSObject()
- ret.put("value", bytesToString(data))
+ val characteristic = getCharacteristic(call) ?: run {
+ return call.reject("startNotifications(): bad characteristic")
+ }
+ val device = manager.getBleDevice(deviceId) ?: run {
+ return call.reject("startNotifications(): device not found")
+ }
- try {
- notifyListeners(key, ret)
- } catch (e: java.util.ConcurrentModificationException) {
- Logger.error(tag, "startNotifications()", e)
- }
- })
+ GlobalScope.launch {
+ val success = device.setNotifications(characteristic.first,
+ characteristic.second, { data ->
+ val key =
+ "notification|${deviceId}|${(characteristic.first)}|${(characteristic.second)}"
+
+ val ret = JSObject()
+ ret.put("value", bytesToString(data))
+
+ try {
+ notifyListeners(key, ret)
+ } catch (e: java.util.ConcurrentModificationException) {
+ Logger.error(tag, "startNotifications()", e)
+ }
+ })
+ if (success) {
+ call.resolve()
+ } else {
+ call.reject("startNotifications(): failed to set notifications")
+ }
+ }
}
@PluginMethod
@RequiresPermission(value = "android.permission.BLUETOOTH_CONNECT")
+ @OptIn(DelicateCoroutinesApi::class)
fun stopNotifications(call: PluginCall) {
val deviceId = call.getString("deviceId", "")!!
- val characteristic =
- getCharacteristic(call)
- ?: return call.reject("stopNotifications(): bad characteristic")
-
- manager.stopNotifications(
- deviceId,
- characteristic.first,
- characteristic.second
- ) { success ->
+ val characteristic = getCharacteristic(call) ?: run {
+ return call.reject("stopNotifications(): bad characteristic")
+ }
+ val device = manager.getBleDevice(deviceId) ?: run {
+ return call.reject("stopNotifications(): device not found")
+ }
+
+ GlobalScope.launch {
+ val success = device.stopNotifications(characteristic.first, characteristic.second)
if (success) {
call.resolve()
} else {
@@ -436,80 +469,76 @@ class AbrevvaPluginBLE : Plugin() {
return Pair(serviceUUID, characteristicUUID)
}
- private fun getBleDeviceFromNordic(result: BleScanResult): JSObject {
- val bleDevice = JSObject()
-
- bleDevice.put("deviceId", result.device.address)
-
- if (result.device.hasName) {
- bleDevice.put("name", result.device.name)
- }
-
- val uuids = JSArray()
- result.data?.scanRecord?.serviceUuids?.forEach { uuid -> uuids.put(uuid.toString()) }
-
- if (uuids.length() > 0) {
- bleDevice.put("uuids", uuids)
- }
-
- return bleDevice
- }
-
- @OptIn(ExperimentalStdlibApi::class)
- private fun getScanResultFromNordic(result: BleScanResult): JSObject {
- val scanResult = JSObject()
- val bleDevice = getBleDeviceFromNordic(result)
-
- scanResult.put("device", bleDevice)
-
- if (result.device.hasName) {
- scanResult.put("localName", result.device.name)
- }
- if (result.data?.rssi != null) {
- scanResult.put("rssi", result.data!!.rssi)
- }
- if (result.data?.txPower != null) {
- scanResult.put("txPower", result.data!!.txPower)
- } else {
- scanResult.put("txPower", 127)
- }
-
- val manufacturerData = JSObject()
-
- val scanRecordBytes = result.data?.scanRecord?.bytes
- if (scanRecordBytes != null) {
- try {
- // Extract EVVA manufacturer-id
- val keyHex = scanRecordBytes.getByte(6)?.toHexString() + scanRecordBytes.getByte(5)
- ?.toHexString()
- val keyDec = keyHex.toInt(16)
-
- // Slice out manufacturer data
- val bytes = scanRecordBytes.copyOfRange(7, scanRecordBytes.size)
-
- manufacturerData.put(keyDec.toString(), bytesToString(bytes.value))
- } catch (e: Exception) {
- Logger.warn("getScanResultFromNordic(): invalid manufacturer data")
+ private fun getBleDeviceData(device: BleDevice): JSObject {
+ val bleDeviceData = JSObject()
+
+ bleDeviceData.put("deviceId", device.address)
+ bleDeviceData.put("name", device.localName)
+
+ val advertisementData = JSObject()
+ device.advertisementData?.let {
+ advertisementData.put("rssi", it.rssi)
+ advertisementData.put("isConnectable", it.isConnectable)
+
+ val manufacturerData = JSObject()
+ it.manufacturerData?.let { data ->
+ manufacturerData.put("companyIdentifier", data.companyIdentifier.toInt())
+ manufacturerData.put("version", data.version.toInt())
+ manufacturerData.put(
+ "componentType",
+ when (data.componentType.toInt()) {
+ 98 -> "escutcheon"
+ 100 -> "handle"
+ 105 -> "iobox"
+ 109 -> "emzy"
+ 119 -> "wallreader"
+ 122 -> "cylinder"
+ else -> "unknown"
+ }
+ )
+ manufacturerData.put(
+ "mainFirmwareVersionMajor",
+ data.mainFirmwareVersionMajor.toInt()
+ )
+ manufacturerData.put(
+ "mainFirmwareVersionMinor",
+ data.mainFirmwareVersionMinor.toInt()
+ )
+ manufacturerData.put(
+ "mainFirmwareVersionPatch",
+ data.mainFirmwareVersionPatch.toInt()
+ )
+ manufacturerData.put("componentHAL", data.componentHAL)
+ manufacturerData.put(
+ "batteryStatus",
+ if (data.batteryStatus) "battery-full" else "battery-empty"
+ )
+ manufacturerData.put("mainConstructionMode", data.mainConstructionMode)
+ manufacturerData.put("subConstructionMode", data.subConstructionMode)
+ manufacturerData.put("isOnline", data.isOnline)
+ manufacturerData.put("officeModeEnabled", data.officeModeEnabled)
+ manufacturerData.put("twoFactorRequired", data.twoFactorRequired)
+ manufacturerData.put("officeModeActive", data.officeModeActive)
+ manufacturerData.put("reservedBits", data.reservedBits)
+ manufacturerData.put("identifier", data.identifier)
+ manufacturerData.put(
+ "subFirmwareVersionMajor",
+ data.subFirmwareVersionMajor?.toInt()
+ )
+ manufacturerData.put(
+ "subFirmwareVersionMinor",
+ data.subFirmwareVersionMinor?.toInt()
+ )
+ manufacturerData.put(
+ "subFirmwareVersionPatch",
+ data.subFirmwareVersionPatch?.toInt()
+ )
+ manufacturerData.put("subComponentIdentifier", data.subComponentIdentifier)
}
+ bleDeviceData.put("manufacturerData", manufacturerData)
}
+ bleDeviceData.put("advertisementData", advertisementData)
- scanResult.put("manufacturerData", manufacturerData)
-
- val serviceDataObject = JSObject()
- val serviceData = result.data?.scanRecord?.serviceData
- serviceData?.forEach {
- serviceDataObject.put(it.key.toString(), bytesToString(it.value.value))
- }
- scanResult.put("serviceData", serviceDataObject)
-
- val uuids = JSArray()
- result.data?.scanRecord?.serviceUuids?.forEach { uuid -> uuids.put(uuid.toString()) }
- scanResult.put("uuids", uuids)
- scanResult.put(
- "rawAdvertisement",
- result.data?.scanRecord?.bytes?.toString()
- )
-
- return scanResult
+ return bleDeviceData
}
}
diff --git a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginCrypto.kt b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginCrypto.kt
index 33fd88b..59ee5fb 100644
--- a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginCrypto.kt
+++ b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginCrypto.kt
@@ -29,7 +29,6 @@ private enum class CryptoError {
DecryptInvalidArgumentError,
DecryptEmptyResultError,
DecryptCryptoError,
- DecryptFileReadError,
DecryptFileCryptoError,
DecryptFileInvalidArgumentError,
DecryptFileFromURLNetworkError,
diff --git a/src/plugins/ble/client.ts b/src/plugins/ble/client.ts
index 157f038..2425be6 100644
--- a/src/plugins/ble/client.ts
+++ b/src/plugins/ble/client.ts
@@ -1,15 +1,7 @@
import type { PluginListenerHandle } from "@capacitor/core";
import { dataViewToHexString, hexStringToDataView } from "./conversion";
-import type {
- Data,
- InitializeOptions,
- RequestBleDeviceOptions,
- TimeoutOptions,
- ReadResult,
- ScanResult,
- ScanResultInternal,
-} from "./definitions";
+import type { InitializeOptions, TimeoutOptions, ReadResult, BleScannerOptions, BleDevice, Data } from "./definitions";
import { AbrevvaBLE } from "./plugin";
import { getQueue } from "./queue";
import { validateUUID } from "./validators";
@@ -23,7 +15,7 @@ export interface AbrevvaBLEClientInterface {
openLocationSettings(): Promise;
openBluetoothSettings(): Promise;
openAppSettings(): Promise;
- requestLEScan(options: RequestBleDeviceOptions, callback: (result: ScanResult) => void): Promise;
+ requestLEScan(options: BleScannerOptions, callback: (result: BleDevice) => void): Promise;
stopLEScan(): Promise;
connect(deviceId: string, onDisconnect?: (deviceId: string) => void, options?: TimeoutOptions): Promise;
disconnect(deviceId: string): Promise;
@@ -117,20 +109,11 @@ class AbrevvaBLEClientClass implements AbrevvaBLEClientInterface {
});
}
- async requestLEScan(options: RequestBleDeviceOptions, callback: (result: ScanResult) => void): Promise {
- options = this.validateRequestBleDeviceOptions(options);
+ async requestLEScan(options: BleScannerOptions, callback: (result: BleDevice) => void): Promise {
await this.queue(async () => {
await this.scanListener?.remove();
- this.scanListener = AbrevvaBLE.addListener("onScanResult", (resultInternal: ScanResultInternal) => {
- const result: ScanResult = {
- ...resultInternal,
- manufacturerData: this.convertObject(resultInternal.manufacturerData),
- serviceData: this.convertObject(resultInternal.serviceData),
- rawAdvertisement: resultInternal.rawAdvertisement
- ? this.convertValue(resultInternal.rawAdvertisement)
- : undefined,
- };
- callback(result);
+ this.scanListener = AbrevvaBLE.addListener("onScanResult", (device: BleDevice) => {
+ callback(device);
});
await AbrevvaBLE.requestLEScan(options);
});
@@ -213,7 +196,7 @@ class AbrevvaBLEClientClass implements AbrevvaBLEClientInterface {
mobileId: string,
mobileDeviceKey: string,
mobileGroupId: string,
- mobileAccessData: string,
+ mediumAccessData: string,
isPermanentRelease: boolean,
onConnect?: (address: string) => void,
onDisconnect?: (address: string) => void,
@@ -243,7 +226,7 @@ class AbrevvaBLEClientClass implements AbrevvaBLEClientInterface {
mobileId,
mobileDeviceKey,
mobileGroupId,
- mobileAccessData,
+ mediumAccessData,
isPermanentRelease,
});
@@ -289,16 +272,6 @@ class AbrevvaBLEClientClass implements AbrevvaBLEClientInterface {
});
}
- private validateRequestBleDeviceOptions(options: RequestBleDeviceOptions): RequestBleDeviceOptions {
- if (options.services) {
- options.services = options.services.map(validateUUID);
- }
- if (options.optionalServices) {
- options.optionalServices = options.optionalServices.map(validateUUID);
- }
- return options;
- }
-
private convertValue(value?: Data): DataView {
if (typeof value === "string") {
return hexStringToDataView(value);
@@ -307,17 +280,6 @@ class AbrevvaBLEClientClass implements AbrevvaBLEClientInterface {
}
return value;
}
-
- private convertObject(obj?: { [key: string]: Data }): { [key: string]: DataView } | undefined {
- if (obj === undefined) {
- return undefined;
- }
- const result: { [key: string]: DataView } = {};
- for (const key of Object.keys(obj)) {
- result[key] = this.convertValue(obj[key]);
- }
- return result;
- }
}
export const AbrevvaBLEClient = new AbrevvaBLEClientClass();
diff --git a/src/plugins/ble/definitions.ts b/src/plugins/ble/definitions.ts
index 307415a..3f6cb00 100644
--- a/src/plugins/ble/definitions.ts
+++ b/src/plugins/ble/definitions.ts
@@ -1,27 +1,11 @@
import type { PluginListenerHandle } from "@capacitor/core";
+export type Data = DataView | string;
+
export interface InitializeOptions {
androidNeverForLocation?: boolean;
}
-export enum ScanMode {
- SCAN_MODE_LOW_POWER = 0,
- SCAN_MODE_BALANCED = 1,
- SCAN_MODE_LOW_LATENCY = 2,
-}
-
-export interface RequestBleDeviceOptions {
- services?: string[];
- name?: string;
- namePrefix?: string;
- optionalServices?: string[];
- allowDuplicates?: boolean;
- scanMode?: ScanMode;
- timeout?: number;
-}
-
-export type Data = DataView | string;
-
export interface BooleanResult {
value: boolean;
}
@@ -38,32 +22,43 @@ export interface TimeoutOptions {
timeout?: number;
}
-export interface BleDevice {
- deviceId: string;
- name?: string;
- uuids?: string[];
+export interface BleScannerOptions {
+ macFilter?: string;
+ timeout?: number;
}
-export interface ScanResult {
- device: BleDevice;
- localName?: string;
+export interface BleDeviceAdvertisementData {
rssi?: number;
- txPower?: number;
- manufacturerData?: { [key: string]: DataView };
- serviceData?: { [key: string]: DataView };
- uuids?: string[];
- rawAdvertisement?: DataView;
+ isConnectable?: boolean;
+ manufacturerData?: BleDeviceManufacturerData;
+}
+
+export interface BleDeviceManufacturerData {
+ companyIdentifier?: string;
+ version?: number;
+ componentType?: "handle" | "escutcheon" | "cylinder" | "wallreader" | "emzy" | "iobox" | "unknown";
+ mainFirmwareVersionMajor?: number;
+ mainFirmwareVersionMinor?: number;
+ mainFirmwareVersionPatch?: number;
+ componentHAL?: string;
+ batteryStatus?: "battery-full" | "battery-empty";
+ mainConstructionMode?: boolean;
+ subConstructionMode?: boolean;
+ isOnline?: boolean;
+ officeModeEnabled?: boolean;
+ twoFactorRequired?: boolean;
+ officeModeActive?: boolean;
+ identifier?: string;
+ subFirmwareVersionMajor?: number;
+ subFirmwareVersionMinor?: number;
+ subFirmwareVersionPatch?: number;
+ subComponentIdentifier?: string;
}
-export interface ScanResultInternal {
- device: BleDevice;
- localName?: string;
- rssi?: number;
- txPower?: number;
- manufacturerData?: { [key: string]: T };
- serviceData?: { [key: string]: T };
- uuids?: string[];
- rawAdvertisement?: T;
+export interface BleDevice {
+ deviceId: string;
+ name?: string;
+ advertisementData?: BleDeviceAdvertisementData;
}
export interface ReadOptions {
@@ -92,7 +87,7 @@ export interface DisengageOptions {
mobileId: string;
mobileDeviceKey: string;
mobileGroupId: string;
- mobileAccessData: string;
+ mediumAccessData: string;
isPermanentRelease: boolean;
}
@@ -105,11 +100,11 @@ export interface AbrevvaBLEInterface {
openLocationSettings(): Promise;
openBluetoothSettings(): Promise;
openAppSettings(): Promise;
- requestLEScan(options?: RequestBleDeviceOptions): Promise;
+ requestLEScan(options?: BleScannerOptions): Promise;
stopLEScan(): Promise;
addListener(eventName: "onEnabledChanged", listenerFunc: (result: BooleanResult) => void): PluginListenerHandle;
addListener(eventName: string, listenerFunc: (event: ReadResult) => void): PluginListenerHandle;
- addListener(eventName: "onScanResult", listenerFunc: (result: ScanResultInternal) => void): PluginListenerHandle;
+ addListener(eventName: "onScanResult", listenerFunc: (result: BleDevice) => void): PluginListenerHandle;
connect(options: DeviceIdOptions & TimeoutOptions): Promise;
disconnect(options: DeviceIdOptions): Promise;
read(options: ReadOptions & TimeoutOptions): Promise;
From 530e37572040e781d5e13012614dcc666115858d Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Thu, 5 Dec 2024 14:25:16 +0100
Subject: [PATCH 02/16] fix: move manufacturerData into advertisingData JSON
object
---
.../evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
index 0165cbd..1fbb4b3 100644
--- a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
+++ b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
@@ -535,7 +535,7 @@ class AbrevvaPluginBLE : Plugin() {
)
manufacturerData.put("subComponentIdentifier", data.subComponentIdentifier)
}
- bleDeviceData.put("manufacturerData", manufacturerData)
+ advertisementData.put("manufacturerData", manufacturerData)
}
bleDeviceData.put("advertisementData", advertisementData)
From 369f7402961145059f3da47f436014d739434746 Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Fri, 6 Dec 2024 13:10:33 +0100
Subject: [PATCH 03/16] refactor: fix renaming of mobileAccessData to
mediumAccessData; fix test-app
---
src/plugins/ble/client.spec.ts | 2 +-
src/plugins/ble/client.ts | 2 +-
test-app/src/app/ble/ble.component.ts | 14 +++++++-------
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/plugins/ble/client.spec.ts b/src/plugins/ble/client.spec.ts
index 63db001..72fad77 100644
--- a/src/plugins/ble/client.spec.ts
+++ b/src/plugins/ble/client.spec.ts
@@ -269,7 +269,7 @@ describe("AbrevvaBLEClient", () => {
mobileId: "",
mobileDeviceKey: "",
mobileGroupId: "",
- mobileAccessData: "",
+ mediumAccessData: "",
isPermanentRelease: false,
});
expect(result).toEqual("ACCESS_STATUS_AUTHORIZED");
diff --git a/src/plugins/ble/client.ts b/src/plugins/ble/client.ts
index 2425be6..e889f6f 100644
--- a/src/plugins/ble/client.ts
+++ b/src/plugins/ble/client.ts
@@ -33,7 +33,7 @@ export interface AbrevvaBLEClientInterface {
mobileId: string,
mobileDeviceKey: string,
mobileGroupId: string,
- mobileAccessData: string,
+ mediumAccessData: string,
isPermanentRelease: boolean,
): Promise;
startNotifications(
diff --git a/test-app/src/app/ble/ble.component.ts b/test-app/src/app/ble/ble.component.ts
index 35e0425..bd1a854 100644
--- a/test-app/src/app/ble/ble.component.ts
+++ b/test-app/src/app/ble/ble.component.ts
@@ -1,6 +1,6 @@
import { Component, OnInit } from "@angular/core";
import { ChangeDetectorRef } from "@angular/core";
-import { AbrevvaBLEClient, ScanResult } from "@evva/abrevva-capacitor";
+import { AbrevvaBLEClient, BleDevice } from "@evva/abrevva-capacitor";
@Component({
selector: "app-ble",
@@ -10,7 +10,7 @@ import { AbrevvaBLEClient, ScanResult } from "@evva/abrevva-capacitor";
export class BleComponent implements OnInit {
constructor(private readonly changeDetectorRef: ChangeDetectorRef) {}
- results: ScanResult[] = [];
+ results: BleDevice[] = [];
async ngOnInit() {
await AbrevvaBLEClient.initialize({ androidNeverForLocation: true });
@@ -20,9 +20,9 @@ export class BleComponent implements OnInit {
const timeout = 5_000;
this.results = [];
- await AbrevvaBLEClient.requestLEScan({ timeout: timeout }, (result: ScanResult) => {
+ await AbrevvaBLEClient.requestLEScan({ timeout: timeout }, (result: BleDevice) => {
this.results.push(result);
- result.device.deviceId;
+ result.deviceId;
this.changeDetectorRef.detectChanges();
});
setTimeout(() => {
@@ -30,9 +30,9 @@ export class BleComponent implements OnInit {
}, timeout);
}
- async disengage(device: ScanResult) {
+ async disengage(device: BleDevice) {
await AbrevvaBLEClient.connect(
- device.device.deviceId,
+ device.deviceId,
(device) => {
console.log(`disconnected: ${device}`);
},
@@ -44,7 +44,7 @@ export class BleComponent implements OnInit {
"mobileId",
"mobileDeviceKey",
"mobileGroupId",
- "mobileAccessData",
+ "mediumAccessData",
true,
);
}
From 02dfece413b4913fed8894f9db6f644524e2b9d7 Mon Sep 17 00:00:00 2001
From: mhochsto <116495532+mhochsto@users.noreply.github.com>
Date: Fri, 6 Dec 2024 13:42:53 +0100
Subject: [PATCH 04/16] feat: updated ios bridge to match latest sdk release
---
EvvaAbrevvaCapacitor.podspec | 2 +-
ios/Plugin/ble/AbrevvaPluginBLE.swift | 168 +++++++++++++-------------
2 files changed, 84 insertions(+), 86 deletions(-)
diff --git a/EvvaAbrevvaCapacitor.podspec b/EvvaAbrevvaCapacitor.podspec
index 8d23584..8423ba4 100644
--- a/EvvaAbrevvaCapacitor.podspec
+++ b/EvvaAbrevvaCapacitor.podspec
@@ -21,5 +21,5 @@ TODO: Add long description of the pod here.
s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
s.dependency 'Capacitor'
- s.dependency 'AbrevvaSDK', '~> 1.1.0'
+ s.dependency 'AbrevvaSDK', '~> 2.0.0'
end
diff --git a/ios/Plugin/ble/AbrevvaPluginBLE.swift b/ios/Plugin/ble/AbrevvaPluginBLE.swift
index 11b0dbe..29732ee 100644
--- a/ios/Plugin/ble/AbrevvaPluginBLE.swift
+++ b/ios/Plugin/ble/AbrevvaPluginBLE.swift
@@ -81,34 +81,27 @@ public class AbrevvaPluginBLE: CAPPlugin {
@objc
func requestLEScan(_ call: CAPPluginCall) {
guard let bleManager = self.getBleManager(call) else { return }
- let name = call.getString("name")
- let namePrefix = call.getString("namePrefix")
- let allowDuplicates = call.getBool("allowDuplicates", false)
+ let macFilter = call.getString("macFilter")
let timeout = call.getDouble("timeout").map { Int($0) } ?? nil
- bleManager.startScan(
- name,
- namePrefix,
- allowDuplicates,
- { success in
- if success {
- call.resolve()
- } else {
- call.reject("requestLEScan(): failed to start")
- }
- }, { device, advertisementData, rssi in
- self.bleDeviceMap[device.getAddress()] = device
- let data = self.getScanResultDict(device, advertisementData, rssi)
- self.notifyListeners("onScanResult", data: data)
- },
- { address in
- self.notifyListeners("connected|\(address)", data: nil)
- },
- { address in
- self.notifyListeners("disconnected|\(address)", data: nil)
- },
- timeout
- )
+ bleManager.startScan(
+ macFilter,
+ timeout,
+ false,
+ { error in
+ if error == nil {
+ call.resolve()
+ } else {
+ call.reject("requestLEScan(): failed to start")
+ }
+ },
+ { error in },
+ { device, advertisementData, rssi in
+ self.bleDeviceMap[device.getAddress()] = device
+ let data = self.getAdvertismentData(device, rssi)
+ debugPrint(data)
+ self.notifyListeners("onScanResult", data: data)
+ })
}
@objc
@@ -216,7 +209,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
let mobileID = call.getString("mobileId") ?? ""
let mobileDeviceKey = call.getString("mobileDeviceKey") ?? ""
let mobileGroupID = call.getString("mobileGroupId") ?? ""
- let mobileAccessData = call.getString("mobileAccessData") ?? ""
+ let mediumAccessData = call.getString("mediumAccessData") ?? ""
let isPermanentRelease = call.getBool("isPermanentRelease") ?? false
let timeout = call.getDouble("timeout").map { Int($0) } ?? nil
@@ -226,7 +219,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
mobileID,
mobileDeviceKey,
mobileGroupID,
- mobileAccessData,
+ mediumAccessData,
isPermanentRelease,
timeout
)
@@ -328,67 +321,72 @@ public class AbrevvaPluginBLE: CAPPlugin {
return (serviceUUID, characteristicUUID)
}
- private func getBleDeviceDict(_ device: BleDevice) -> [String: String] {
- var bleDevice = [
- "deviceId": device.getAddress()
- ]
- if device.getName() != nil {
- bleDevice["name"] = device.getName()
- }
- return bleDevice
- }
-
- private func getScanResultDict(
+ private func getAdvertismentData(
_ device: BleDevice,
- _ advertisementData: [String: Any],
_ rssi: NSNumber
) -> [String: Any] {
- var data = [
- "device": self.getBleDeviceDict(device),
- "rssi": rssi,
- "txPower": advertisementData[CBAdvertisementDataTxPowerLevelKey] ?? 127,
- "uuids": (advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID] ?? []).map { uuid -> String in
- return CBUUIDToString(uuid)
- }
- ]
-
- let localName = advertisementData[CBAdvertisementDataLocalNameKey] as? String
- if localName != nil {
- data["localName"] = localName
- }
-
- let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data
- if manufacturerData != nil {
- data["manufacturerData"] = self.getManufacturerDataDict(data: manufacturerData!)
- }
-
- let serviceData = advertisementData[CBAdvertisementDataServiceDataKey] as? [CBUUID: Data]
- if serviceData != nil {
- data["serviceData"] = self.getServiceDataDict(data: serviceData!)
- }
- return data
+
+ var bleDeviceData: [String: Any] = [
+ "deviceId": device.getAddress(),
+ "name": device.getName()
+ ]
+
+ var advertismentData: [String: Any] = [
+ "rssi": rssi
+ ]
+ if let isConnectable = device.advertisementData?.isConnectable {
+ advertismentData["isConnectable"] = isConnectable
+ }
+
+ guard let mfData = device.advertisementData?.manufacturerData else {
+ bleDeviceData ["advertisementData"] = advertismentData
+ return bleDeviceData
+ }
+
+ var manufacturerData: [String: Any] = [
+ "companyIdentifier": mfData.companyIdentifier,
+ "version": mfData.version,
+ "mainFirmwareVersionMajor": mfData.mainFirmwareVersionMajor,
+ "mainFirmwareVersionMinor": mfData.mainFirmwareVersionMinor,
+ "mainFirmwareVersionPatch": mfData.mainFirmwareVersionPatch,
+ "componentHAL": mfData.componentHAL,
+ "batteryStatus": mfData.batteryStatus ? "battery-full" : "battery-empty",
+ "mainConstructionMode": mfData.mainConstructionMode,
+ "subConstructionMode": mfData.subConstructionMode,
+ "isOnline": mfData.isOnline,
+ "officeModeEnabled": mfData.officeModeEnabled,
+ "twoFactorRequired": mfData.twoFactorRequired,
+ "officeModeActive": mfData.officeModeActive,
+ "identifier": mfData.identifier,
+ "subFirmwareVersionMajor": mfData.subFirmwareVersionMajor,
+ "subFirmwareVersionMinor": mfData.subFirmwareVersionMinor,
+ "subFirmwareVersionPatch": mfData.subFirmwareVersionPatch,
+ "subComponentIdentifier": mfData.subComponentIdentifier,
+ "componentType": getComponentType(mfData.componentType)
+ ]
+ advertismentData["manufacturerData"] = manufacturerData
+ bleDeviceData["advertisementData"] = advertismentData
+
+ return bleDeviceData
}
- private func getManufacturerDataDict(data: Data) -> [String: String] {
- var company = 0
- var rest = ""
- for (index, byte) in data.enumerated() {
- if index == 0 {
- company += Int(byte)
- } else if index == 1 {
- company += Int(byte) * 256
- } else {
- rest += String(format: "%02hhx ", byte)
- }
- }
- return [String(company): rest]
- }
-
- private func getServiceDataDict(data: [CBUUID: Data]) -> [String: String] {
- var result: [String: String] = [:]
- for (key, value) in data {
- result[CBUUIDToString(key)] = dataToString(value)
- }
- return result
+
+ private func getComponentType(_ componentType: UInt8) -> String {
+ switch componentType {
+ case 98:
+ "escutcheon"
+ case 100:
+ "handle"
+ case 105:
+ "iobox"
+ case 109:
+ "emzy"
+ case 119:
+ "wallreader"
+ case 122:
+ "cylinder"
+ default:
+ "unkown"
}
+ }
}
From b2647e2d44bdbf314ab816159c6ab802955f4cdd Mon Sep 17 00:00:00 2001
From: mhochsto <116495532+mhochsto@users.noreply.github.com>
Date: Mon, 9 Dec 2024 09:36:52 +0100
Subject: [PATCH 05/16] feat: remove unused keys
---
ios/Plugin/ble/AbrevvaPluginBLE.swift | 1 +
1 file changed, 1 insertion(+)
diff --git a/ios/Plugin/ble/AbrevvaPluginBLE.swift b/ios/Plugin/ble/AbrevvaPluginBLE.swift
index 29732ee..72e3088 100644
--- a/ios/Plugin/ble/AbrevvaPluginBLE.swift
+++ b/ios/Plugin/ble/AbrevvaPluginBLE.swift
@@ -364,6 +364,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
"subComponentIdentifier": mfData.subComponentIdentifier,
"componentType": getComponentType(mfData.componentType)
]
+ manufacturerData = manufacturerData.filter({$0.value != nil})
advertismentData["manufacturerData"] = manufacturerData
bleDeviceData["advertisementData"] = advertismentData
From c05e7f2f5edde74678538793eb021e2be1e3ecf7 Mon Sep 17 00:00:00 2001
From: mhochsto <116495532+mhochsto@users.noreply.github.com>
Date: Mon, 9 Dec 2024 14:34:46 +0100
Subject: [PATCH 06/16] fix: sdk version bump
---
EvvaAbrevvaCapacitor.podspec | 2 +-
ios/Plugin/ble/AbrevvaPluginBLE.swift | 26 +++++++++++++++-----------
2 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/EvvaAbrevvaCapacitor.podspec b/EvvaAbrevvaCapacitor.podspec
index 8423ba4..e5ab331 100644
--- a/EvvaAbrevvaCapacitor.podspec
+++ b/EvvaAbrevvaCapacitor.podspec
@@ -21,5 +21,5 @@ TODO: Add long description of the pod here.
s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
s.dependency 'Capacitor'
- s.dependency 'AbrevvaSDK', '~> 2.0.0'
+ s.dependency 'AbrevvaSDK', '~> 2.0.2'
end
diff --git a/ios/Plugin/ble/AbrevvaPluginBLE.swift b/ios/Plugin/ble/AbrevvaPluginBLE.swift
index 72e3088..f4e5647 100644
--- a/ios/Plugin/ble/AbrevvaPluginBLE.swift
+++ b/ios/Plugin/ble/AbrevvaPluginBLE.swift
@@ -85,9 +85,12 @@ public class AbrevvaPluginBLE: CAPPlugin {
let timeout = call.getDouble("timeout").map { Int($0) } ?? nil
bleManager.startScan(
- macFilter,
- timeout,
- false,
+ { device, advertisementData, rssi in
+ self.bleDeviceMap[device.getAddress()] = device
+ let data = self.getAdvertismentData(device, rssi)
+ debugPrint(data)
+ self.notifyListeners("onScanResult", data: data)
+ },
{ error in
if error == nil {
call.resolve()
@@ -96,12 +99,10 @@ public class AbrevvaPluginBLE: CAPPlugin {
}
},
{ error in },
- { device, advertisementData, rssi in
- self.bleDeviceMap[device.getAddress()] = device
- let data = self.getAdvertismentData(device, rssi)
- debugPrint(data)
- self.notifyListeners("onScanResult", data: data)
- })
+ macFilter,
+ false,
+ timeout
+ )
}
@objc
@@ -116,9 +117,12 @@ public class AbrevvaPluginBLE: CAPPlugin {
guard self.getBleManager(call) != nil else { return }
guard let device = self.getDevice(call, checkConnection: false) else { return }
let timeout = call.getDouble("timeout").map { Int($0) } ?? nil
-
Task {
- let success = await self.bleManager!.connect(device, timeout)
+ let success = await self.bleManager!.connect(device, { address in
+ self.notifyListeners("disconnected|\(address)", data: nil)
+ },
+ timeout)
+
if success {
call.resolve()
} else {
From 97aa926747ad890f52c75c2cc1936a0a102ea198 Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Mon, 9 Dec 2024 15:41:39 +0100
Subject: [PATCH 07/16] chore: update deps; run npm fmt; fix test-app
---
ios/Plugin/ble/AbrevvaPluginBLE.swift | 169 +++++++++++++-------------
ios/Podfile | 2 +-
package-lock.json | 6 +-
test-app/package-lock.json | 29 +++--
test-app/src/app/ble/ble.component.ts | 5 +-
5 files changed, 107 insertions(+), 104 deletions(-)
diff --git a/ios/Plugin/ble/AbrevvaPluginBLE.swift b/ios/Plugin/ble/AbrevvaPluginBLE.swift
index f4e5647..1503706 100644
--- a/ios/Plugin/ble/AbrevvaPluginBLE.swift
+++ b/ios/Plugin/ble/AbrevvaPluginBLE.swift
@@ -84,25 +84,25 @@ public class AbrevvaPluginBLE: CAPPlugin {
let macFilter = call.getString("macFilter")
let timeout = call.getDouble("timeout").map { Int($0) } ?? nil
- bleManager.startScan(
- { device, advertisementData, rssi in
- self.bleDeviceMap[device.getAddress()] = device
- let data = self.getAdvertismentData(device, rssi)
- debugPrint(data)
- self.notifyListeners("onScanResult", data: data)
- },
- { error in
- if error == nil {
- call.resolve()
- } else {
- call.reject("requestLEScan(): failed to start")
- }
- },
- { error in },
- macFilter,
- false,
- timeout
- )
+ bleManager.startScan(
+ { device, _, rssi in
+ self.bleDeviceMap[device.getAddress()] = device
+ let data = self.getAdvertismentData(device, rssi)
+ debugPrint(data)
+ self.notifyListeners("onScanResult", data: data)
+ },
+ { error in
+ if error == nil {
+ call.resolve()
+ } else {
+ call.reject("requestLEScan(): failed to start")
+ }
+ },
+ { _ in },
+ macFilter,
+ false,
+ timeout
+ )
}
@objc
@@ -118,11 +118,11 @@ public class AbrevvaPluginBLE: CAPPlugin {
guard let device = self.getDevice(call, checkConnection: false) else { return }
let timeout = call.getDouble("timeout").map { Int($0) } ?? nil
Task {
- let success = await self.bleManager!.connect(device, { address in
- self.notifyListeners("disconnected|\(address)", data: nil)
- },
- timeout)
-
+ let success = await self.bleManager!.connect(device, { address in
+ self.notifyListeners("disconnected|\(address)", data: nil)
+ },
+ timeout)
+
if success {
call.resolve()
} else {
@@ -329,69 +329,68 @@ public class AbrevvaPluginBLE: CAPPlugin {
_ device: BleDevice,
_ rssi: NSNumber
) -> [String: Any] {
-
- var bleDeviceData: [String: Any] = [
- "deviceId": device.getAddress(),
- "name": device.getName()
- ]
-
- var advertismentData: [String: Any] = [
- "rssi": rssi
- ]
- if let isConnectable = device.advertisementData?.isConnectable {
- advertismentData["isConnectable"] = isConnectable
- }
-
- guard let mfData = device.advertisementData?.manufacturerData else {
- bleDeviceData ["advertisementData"] = advertismentData
+
+ var bleDeviceData: [String: Any] = [
+ "deviceId": device.getAddress(),
+ "name": device.getName()
+ ]
+
+ var advertismentData: [String: Any] = [
+ "rssi": rssi
+ ]
+ if let isConnectable = device.advertisementData?.isConnectable {
+ advertismentData["isConnectable"] = isConnectable
+ }
+
+ guard let mfData = device.advertisementData?.manufacturerData else {
+ bleDeviceData ["advertisementData"] = advertismentData
+ return bleDeviceData
+ }
+
+ var manufacturerData: [String: Any] = [
+ "companyIdentifier": mfData.companyIdentifier,
+ "version": mfData.version,
+ "mainFirmwareVersionMajor": mfData.mainFirmwareVersionMajor,
+ "mainFirmwareVersionMinor": mfData.mainFirmwareVersionMinor,
+ "mainFirmwareVersionPatch": mfData.mainFirmwareVersionPatch,
+ "componentHAL": mfData.componentHAL,
+ "batteryStatus": mfData.batteryStatus ? "battery-full" : "battery-empty",
+ "mainConstructionMode": mfData.mainConstructionMode,
+ "subConstructionMode": mfData.subConstructionMode,
+ "isOnline": mfData.isOnline,
+ "officeModeEnabled": mfData.officeModeEnabled,
+ "twoFactorRequired": mfData.twoFactorRequired,
+ "officeModeActive": mfData.officeModeActive,
+ "identifier": mfData.identifier,
+ "subFirmwareVersionMajor": mfData.subFirmwareVersionMajor,
+ "subFirmwareVersionMinor": mfData.subFirmwareVersionMinor,
+ "subFirmwareVersionPatch": mfData.subFirmwareVersionPatch,
+ "subComponentIdentifier": mfData.subComponentIdentifier,
+ "componentType": getComponentType(mfData.componentType)
+ ]
+ manufacturerData = manufacturerData.filter({$0.value != nil})
+ advertismentData["manufacturerData"] = manufacturerData
+ bleDeviceData["advertisementData"] = advertismentData
+
return bleDeviceData
- }
-
- var manufacturerData: [String: Any] = [
- "companyIdentifier": mfData.companyIdentifier,
- "version": mfData.version,
- "mainFirmwareVersionMajor": mfData.mainFirmwareVersionMajor,
- "mainFirmwareVersionMinor": mfData.mainFirmwareVersionMinor,
- "mainFirmwareVersionPatch": mfData.mainFirmwareVersionPatch,
- "componentHAL": mfData.componentHAL,
- "batteryStatus": mfData.batteryStatus ? "battery-full" : "battery-empty",
- "mainConstructionMode": mfData.mainConstructionMode,
- "subConstructionMode": mfData.subConstructionMode,
- "isOnline": mfData.isOnline,
- "officeModeEnabled": mfData.officeModeEnabled,
- "twoFactorRequired": mfData.twoFactorRequired,
- "officeModeActive": mfData.officeModeActive,
- "identifier": mfData.identifier,
- "subFirmwareVersionMajor": mfData.subFirmwareVersionMajor,
- "subFirmwareVersionMinor": mfData.subFirmwareVersionMinor,
- "subFirmwareVersionPatch": mfData.subFirmwareVersionPatch,
- "subComponentIdentifier": mfData.subComponentIdentifier,
- "componentType": getComponentType(mfData.componentType)
- ]
- manufacturerData = manufacturerData.filter({$0.value != nil})
- advertismentData["manufacturerData"] = manufacturerData
- bleDeviceData["advertisementData"] = advertismentData
-
- return bleDeviceData
}
-
- private func getComponentType(_ componentType: UInt8) -> String {
- switch componentType {
- case 98:
- "escutcheon"
- case 100:
- "handle"
- case 105:
- "iobox"
- case 109:
- "emzy"
- case 119:
- "wallreader"
- case 122:
- "cylinder"
- default:
- "unkown"
+ private func getComponentType(_ componentType: UInt8) -> String {
+ switch componentType {
+ case 98:
+ "escutcheon"
+ case 100:
+ "handle"
+ case 105:
+ "iobox"
+ case 109:
+ "emzy"
+ case 119:
+ "wallreader"
+ case 122:
+ "cylinder"
+ default:
+ "unkown"
+ }
}
- }
}
diff --git a/ios/Podfile b/ios/Podfile
index 8552ffd..1687c08 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -13,7 +13,7 @@ end
target 'Plugin' do
capacitor_pods
- pod 'AbrevvaSDK'
+ pod 'AbrevvaSDK', '~> 2.0.2'
end
target 'PluginTests' do
diff --git a/package-lock.json b/package-lock.json
index cfef710..48e6d0d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5640,9 +5640,9 @@
}
},
"node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"dependencies": {
"path-key": "^3.1.0",
diff --git a/test-app/package-lock.json b/test-app/package-lock.json
index cce29a7..b4acdf8 100644
--- a/test-app/package-lock.json
+++ b/test-app/package-lock.json
@@ -64,7 +64,7 @@
},
"..": {
"name": "@evva/abrevva-capacitor",
- "version": "2.0.1",
+ "version": "3.0.2",
"license": "SEE LICENSE IN ",
"dependencies": {
"throat": "^6.0.2"
@@ -79,7 +79,7 @@
"@capacitor/ios": "^6.1.2",
"@ionic/swiftlint-config": "^1.1.2",
"@release-it/conventional-changelog": "^8.0.2",
- "@types/jest": "^29.5.13",
+ "@types/jest": "^29.5.14",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.7.4",
"auto-changelog": "^2.5.0",
@@ -93,6 +93,7 @@
"rimraf": "^6.0.1",
"rollup": "^3.29.4",
"swiftlint": "^1.0.2",
+ "ts-jest": "^29.2.5",
"typescript": "~5.3.3"
},
"peerDependencies": {
@@ -7111,9 +7112,9 @@
}
},
"node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"dependencies": {
"path-key": "^3.1.0",
@@ -8395,9 +8396,9 @@
"dev": true
},
"node_modules/express": {
- "version": "4.21.1",
- "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
- "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
+ "version": "4.21.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+ "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"dev": true,
"dependencies": {
"accepts": "~1.3.8",
@@ -8419,7 +8420,7 @@
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
- "path-to-regexp": "0.1.10",
+ "path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7",
"qs": "6.13.0",
"range-parser": "~1.2.1",
@@ -8434,6 +8435,10 @@
},
"engines": {
"node": ">= 0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
"node_modules/express/node_modules/cookie": {
@@ -12863,9 +12868,9 @@
"dev": true
},
"node_modules/path-to-regexp": {
- "version": "0.1.10",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
- "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"dev": true
},
"node_modules/path-type": {
diff --git a/test-app/src/app/ble/ble.component.ts b/test-app/src/app/ble/ble.component.ts
index bd1a854..cca104b 100644
--- a/test-app/src/app/ble/ble.component.ts
+++ b/test-app/src/app/ble/ble.component.ts
@@ -22,7 +22,6 @@ export class BleComponent implements OnInit {
this.results = [];
await AbrevvaBLEClient.requestLEScan({ timeout: timeout }, (result: BleDevice) => {
this.results.push(result);
- result.deviceId;
this.changeDetectorRef.detectChanges();
});
setTimeout(() => {
@@ -33,14 +32,14 @@ export class BleComponent implements OnInit {
async disengage(device: BleDevice) {
await AbrevvaBLEClient.connect(
device.deviceId,
- (device) => {
+ (device: BleDevice) => {
console.log(`disconnected: ${device}`);
},
{ timeout: 1_000 },
);
await AbrevvaBLEClient.disengage(
- "deviveId",
+ "deviceId",
"mobileId",
"mobileDeviceKey",
"mobileGroupId",
From b98e68cbd5224de8a6fb06d902197e7b618b3df9 Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Mon, 9 Dec 2024 15:48:36 +0100
Subject: [PATCH 08/16] fix: missing allowDuplicates property on scanStart
---
.../evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
index 1fbb4b3..ba7a223 100644
--- a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
+++ b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
@@ -216,7 +216,7 @@ class AbrevvaPluginBLE : Plugin() {
} else {
call.reject("requestLEScan(): failed to start")
}
- }, {}, macFilter, timeout)
+ }, {}, macFilter, false, timeout)
}
@PluginMethod
From 37e71f51025332bdc4ab3400f8b728e141b0adfd Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Tue, 10 Dec 2024 13:26:46 +0100
Subject: [PATCH 09/16] feat: add support for missing scan closures
---
.../plugins/capacitor/AbrevvaPluginBLE.kt | 25 +++++----
src/plugins/ble/client.spec.ts | 45 ++++++++++------
src/plugins/ble/client.ts | 51 ++++++++++++++-----
src/plugins/ble/definitions.ts | 6 ++-
4 files changed, 86 insertions(+), 41 deletions(-)
diff --git a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
index ba7a223..4ff0b02 100644
--- a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
+++ b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
@@ -197,30 +197,33 @@ class AbrevvaPluginBLE : Plugin() {
}
@PluginMethod
- fun requestLEScan(call: PluginCall) {
+ fun startScan(call: PluginCall) {
val macFilter = call.getString("macFilter", null)
val timeout = call.getFloat("timeout", 15000.0F)!!.toLong()
this.manager.startScan({ device ->
- Logger.debug(tag, "Found device: ${device.address}")
-
+ Logger.debug(tag, "onScanResult(): device found: ${device.address}")
val bleDevice = getBleDeviceData(device)
try {
notifyListeners("onScanResult", bleDevice)
} catch (e: Exception) {
- Logger.error(tag, "requestLEScan()", e)
+ Logger.error(tag, "onScanResult()", e)
}
}, { success ->
- if (success) {
- call.resolve()
- } else {
- call.reject("requestLEScan(): failed to start")
- }
- }, {}, macFilter, false, timeout)
+ val data = JSObject()
+ data.put("value", success)
+ notifyListeners("onScanStart", data)
+ call.resolve()
+ }, { success ->
+ val data = JSObject()
+ data.put("value", success)
+ notifyListeners("onScanStop", data)
+ call.resolve()
+ }, macFilter, false, timeout)
}
@PluginMethod
- fun stopLEScan(call: PluginCall) {
+ fun stopScan(call: PluginCall) {
manager.stopScan()
call.resolve()
}
diff --git a/src/plugins/ble/client.spec.ts b/src/plugins/ble/client.spec.ts
index 72fad77..4cea663 100644
--- a/src/plugins/ble/client.spec.ts
+++ b/src/plugins/ble/client.spec.ts
@@ -10,7 +10,9 @@ import { AbrevvaBLE } from "./plugin";
interface AbrevvaBLEClientWithPrivate extends AbrevvaBLEClientInterface {
eventListeners: Map;
- scanListener: PluginListenerHandle | null;
+ scanResultListener: PluginListenerHandle | null;
+ scanStartListener: PluginListenerHandle | null;
+ scanStopListener: PluginListenerHandle | null;
}
jest.mock("@capacitor/core", () => {
@@ -30,8 +32,8 @@ jest.mock("./plugin", () => {
startEnabledNotifications: jest.fn(),
stopEnabledNotifications: jest.fn(),
requestDevice: jest.fn(),
- requestLEScan: jest.fn(),
- stopLEScan: jest.fn(),
+ startScan: jest.fn(),
+ stopScan: jest.fn(),
connect: jest.fn(),
createBond: jest.fn(),
isBonded: jest.fn(),
@@ -125,30 +127,41 @@ describe("AbrevvaBLEClient", () => {
).toBeUndefined();
});
- it("should run requestLEScan", async () => {
- const mockCallback = jest.fn();
- const mockScanListener = {
+ it("should run startScan", async () => {
+ const mockScanResultCallback = jest.fn();
+ const mockScanStartCallback = jest.fn();
+ const mockScanStopCallback = jest.fn();
+
+ const mockScanResultListener = {
remove: jest.fn(),
};
- (AbrevvaBLE.addListener as jest.Mock).mockReturnValue(mockScanListener);
- await AbrevvaBLEClient.requestLEScan({}, mockCallback);
+
+ (AbrevvaBLE.addListener as jest.Mock).mockReturnValue(mockScanResultListener);
+ await AbrevvaBLEClient.startScan({}, mockScanResultCallback, mockScanStartCallback, mockScanStopCallback);
+
expect(AbrevvaBLE.addListener).toHaveBeenCalledWith("onScanResult", expect.any(Function));
- expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanListener).toBe(mockScanListener);
- expect(AbrevvaBLE.requestLEScan).toHaveBeenCalledTimes(1);
+ expect(AbrevvaBLE.addListener).toHaveBeenCalledWith("onScanStart", expect.any(Function));
+ expect(AbrevvaBLE.addListener).toHaveBeenCalledWith("onScanStop", expect.any(Function));
+
+ expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanResultListener).toBe(
+ mockScanResultListener,
+ );
+
+ expect(AbrevvaBLE.startScan).toHaveBeenCalledTimes(1);
});
- it("should run stopLEScan", async () => {
+ it("should run stopScan", async () => {
const mockCallback = jest.fn();
const mockScanListener = {
remove: jest.fn(),
};
(AbrevvaBLE.addListener as jest.Mock).mockReturnValue(mockScanListener);
- await AbrevvaBLEClient.requestLEScan({}, mockCallback);
- expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanListener).toBe(mockScanListener);
- await AbrevvaBLEClient.stopLEScan();
+ await AbrevvaBLEClient.startScan({}, mockCallback);
+ expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanResultListener).toBe(mockScanListener);
+ await AbrevvaBLEClient.stopScan();
expect(mockScanListener.remove).toHaveBeenCalledTimes(1);
- expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanListener).toBe(null);
- expect(AbrevvaBLE.stopLEScan).toHaveBeenCalledTimes(1);
+ expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanResultListener).toBe(null);
+ expect(AbrevvaBLE.stopScan).toHaveBeenCalledTimes(1);
});
it("should run connect without disconnect callback", async () => {
diff --git a/src/plugins/ble/client.ts b/src/plugins/ble/client.ts
index e889f6f..815172e 100644
--- a/src/plugins/ble/client.ts
+++ b/src/plugins/ble/client.ts
@@ -15,8 +15,13 @@ export interface AbrevvaBLEClientInterface {
openLocationSettings(): Promise;
openBluetoothSettings(): Promise;
openAppSettings(): Promise;
- requestLEScan(options: BleScannerOptions, callback: (result: BleDevice) => void): Promise;
- stopLEScan(): Promise;
+ startScan(
+ options: BleScannerOptions,
+ onScanResult: (result: BleDevice) => void,
+ onScanStart?: (success: boolean) => void,
+ onScanStop?: (success: boolean) => void,
+ ): Promise;
+ stopScan(): Promise;
connect(deviceId: string, onDisconnect?: (deviceId: string) => void, options?: TimeoutOptions): Promise;
disconnect(deviceId: string): Promise;
read(deviceId: string, service: string, characteristic: string, options?: TimeoutOptions): Promise;
@@ -46,7 +51,10 @@ export interface AbrevvaBLEClientInterface {
}
class AbrevvaBLEClientClass implements AbrevvaBLEClientInterface {
- private scanListener: PluginListenerHandle | null = null;
+ private scanResultListener: PluginListenerHandle | null = null;
+ private scanStartListener: PluginListenerHandle | null = null;
+ private scanStopListener: PluginListenerHandle | null = null;
+
private eventListeners = new Map();
private queue = getQueue(true);
@@ -109,21 +117,40 @@ class AbrevvaBLEClientClass implements AbrevvaBLEClientInterface {
});
}
- async requestLEScan(options: BleScannerOptions, callback: (result: BleDevice) => void): Promise {
+ async startScan(
+ options: BleScannerOptions,
+ onScanResult: (result: BleDevice) => void,
+ onScanStart?: (success: boolean) => void,
+ onScanStop?: (success: boolean) => void,
+ ): Promise {
await this.queue(async () => {
- await this.scanListener?.remove();
- this.scanListener = AbrevvaBLE.addListener("onScanResult", (device: BleDevice) => {
- callback(device);
+ await this.scanResultListener?.remove();
+ this.scanResultListener = AbrevvaBLE.addListener("onScanResult", (device: BleDevice) => {
+ onScanResult(device);
});
- await AbrevvaBLE.requestLEScan(options);
+ if (onScanStart) {
+ await this.scanStartListener?.remove();
+ this.scanStartListener = AbrevvaBLE.addListener("onScanStart", (result) => {
+ onScanStart(result.value);
+ this.scanStartListener?.remove();
+ });
+ }
+ if (onScanStop) {
+ await this.scanStopListener?.remove();
+ this.scanStopListener = AbrevvaBLE.addListener("onScanStop", (result) => {
+ onScanStop(result.value);
+ this.scanStopListener?.remove();
+ });
+ }
+ await AbrevvaBLE.startScan(options);
});
}
- async stopLEScan(): Promise {
+ async stopScan(): Promise {
await this.queue(async () => {
- await this.scanListener?.remove();
- this.scanListener = null;
- await AbrevvaBLE.stopLEScan();
+ await this.scanResultListener?.remove();
+ this.scanResultListener = null;
+ await AbrevvaBLE.stopScan();
});
}
diff --git a/src/plugins/ble/definitions.ts b/src/plugins/ble/definitions.ts
index 3f6cb00..96d23d1 100644
--- a/src/plugins/ble/definitions.ts
+++ b/src/plugins/ble/definitions.ts
@@ -100,11 +100,13 @@ export interface AbrevvaBLEInterface {
openLocationSettings(): Promise;
openBluetoothSettings(): Promise;
openAppSettings(): Promise;
- requestLEScan(options?: BleScannerOptions): Promise;
- stopLEScan(): Promise;
+ startScan(options?: BleScannerOptions): Promise;
+ stopScan(): Promise;
addListener(eventName: "onEnabledChanged", listenerFunc: (result: BooleanResult) => void): PluginListenerHandle;
addListener(eventName: string, listenerFunc: (event: ReadResult) => void): PluginListenerHandle;
addListener(eventName: "onScanResult", listenerFunc: (result: BleDevice) => void): PluginListenerHandle;
+ addListener(eventName: "onScanStart", listenerFunc: (success: BooleanResult) => void): PluginListenerHandle;
+ addListener(eventName: "onScanStop", listenerFunc: (success: BooleanResult) => void): PluginListenerHandle;
connect(options: DeviceIdOptions & TimeoutOptions): Promise;
disconnect(options: DeviceIdOptions): Promise;
read(options: ReadOptions & TimeoutOptions): Promise;
From 8bdb13cfceac4e4bdf858671f789033a722ec995 Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Tue, 10 Dec 2024 13:46:17 +0100
Subject: [PATCH 10/16] refactor: rename scan methods and add closure logic for
scanStop
---
.editorconfig | 5 ++++-
README.md | 6 ++++--
ios/Plugin/ble/AbrevvaPluginBLE.m | 4 ++--
ios/Plugin/ble/AbrevvaPluginBLE.swift | 15 ++++++---------
4 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/.editorconfig b/.editorconfig
index 21d392b..29df28b 100755
--- a/.editorconfig
+++ b/.editorconfig
@@ -11,7 +11,10 @@ trim_trailing_whitespace = true
[*.java]
ij_java_imports_layout = $*, |, javax.**, java.**, |, *
-[{*.gradle,*.kt}]
+[*.swift]
+indent_size = 4
+
+[{*.gradle,*.kt,*.kts}]
indent_size = 4
[*.md]
diff --git a/README.md b/README.md
index 39445b8..3800eba 100644
--- a/README.md
+++ b/README.md
@@ -114,11 +114,13 @@ const status = await AbrevvaBLEClient.disengage(
| **openLocationSettings** | () => Promise<void> |
| **openBluetoothSettings** | () => Promise<void> |
| **openAppSettings** | () => Promise<void> |
-| **requestLEScan** | (options?: BleScannerOptions \| undefined) => Promise<void> |
-| **stopLEScan** | () => Promise<void> |
+| **startScan** | (options?: BleScannerOptions \| undefined) => Promise<void> |
+| **stopScan** | () => Promise<void> |
| **addListener** | (eventName: "onEnabledChanged", listenerFunc: (result: BooleanResult) => void) => PluginListenerHandle |
| **addListener** | (eventName: string, listenerFunc: (event: ReadResult) => void) => PluginListenerHandle |
| **addListener** | (eventName: "onScanResult", listenerFunc: (result: BleDevice) => void) => PluginListenerHandle |
+| **addListener** | (eventName: "onScanStart", listenerFunc: (success: BooleanResult) => void) => PluginListenerHandle |
+| **addListener** | (eventName: "onScanStop", listenerFunc: (success: BooleanResult) => void) => PluginListenerHandle |
| **connect** | (options: DeviceIdOptions & TimeoutOptions) => Promise<void> |
| **disconnect** | (options: DeviceIdOptions) => Promise<void> |
| **read** | (options: ReadOptions & TimeoutOptions) => Promise<ReadResult> |
diff --git a/ios/Plugin/ble/AbrevvaPluginBLE.m b/ios/Plugin/ble/AbrevvaPluginBLE.m
index 730493d..be21f77 100644
--- a/ios/Plugin/ble/AbrevvaPluginBLE.m
+++ b/ios/Plugin/ble/AbrevvaPluginBLE.m
@@ -10,8 +10,8 @@
CAP_PLUGIN_METHOD(openLocationSettings, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(openBluetoothSettings, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(openAppSettings, CAPPluginReturnPromise);
- CAP_PLUGIN_METHOD(requestLEScan, CAPPluginReturnPromise);
- CAP_PLUGIN_METHOD(stopLEScan, CAPPluginReturnPromise);
+ CAP_PLUGIN_METHOD(startScan, CAPPluginReturnPromise);
+ CAP_PLUGIN_METHOD(stopScan, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(connect, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(disconnect, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(read, CAPPluginReturnPromise);
diff --git a/ios/Plugin/ble/AbrevvaPluginBLE.swift b/ios/Plugin/ble/AbrevvaPluginBLE.swift
index 1503706..b7f956b 100644
--- a/ios/Plugin/ble/AbrevvaPluginBLE.swift
+++ b/ios/Plugin/ble/AbrevvaPluginBLE.swift
@@ -79,7 +79,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
}
@objc
- func requestLEScan(_ call: CAPPluginCall) {
+ func startScan(_ call: CAPPluginCall) {
guard let bleManager = self.getBleManager(call) else { return }
let macFilter = call.getString("macFilter")
let timeout = call.getDouble("timeout").map { Int($0) } ?? nil
@@ -88,17 +88,14 @@ public class AbrevvaPluginBLE: CAPPlugin {
{ device, _, rssi in
self.bleDeviceMap[device.getAddress()] = device
let data = self.getAdvertismentData(device, rssi)
- debugPrint(data)
self.notifyListeners("onScanResult", data: data)
},
{ error in
- if error == nil {
- call.resolve()
- } else {
- call.reject("requestLEScan(): failed to start")
- }
+ call.resolve(["value": error == nil])
+ },
+ { error in
+ call.resolve(["value": error == nil])
},
- { _ in },
macFilter,
false,
timeout
@@ -106,7 +103,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
}
@objc
- func stopLEScan(_ call: CAPPluginCall) {
+ func stopScan(_ call: CAPPluginCall) {
guard let bleManager = self.getBleManager(call) else { return }
bleManager.stopScan()
call.resolve()
From d82162595c65e37bc0c3945957aaf31e26d71eb6 Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Tue, 10 Dec 2024 13:51:28 +0100
Subject: [PATCH 11/16] fix: add missing notifyListeners for scanStart/Stop
---
ios/Plugin/ble/AbrevvaPluginBLE.swift | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/ios/Plugin/ble/AbrevvaPluginBLE.swift b/ios/Plugin/ble/AbrevvaPluginBLE.swift
index b7f956b..0ef2144 100644
--- a/ios/Plugin/ble/AbrevvaPluginBLE.swift
+++ b/ios/Plugin/ble/AbrevvaPluginBLE.swift
@@ -91,10 +91,12 @@ public class AbrevvaPluginBLE: CAPPlugin {
self.notifyListeners("onScanResult", data: data)
},
{ error in
- call.resolve(["value": error == nil])
+ self.notifyListeners("onScanStart", data: ["value": error == nil])
+ call.resolve()
},
{ error in
- call.resolve(["value": error == nil])
+ self.notifyListeners("onScanStop", data: ["value": error == nil])
+ call.resolve()
},
macFilter,
false,
From 390109217e1740e45e12157ebd1587e66d32e8ac Mon Sep 17 00:00:00 2001
From: mhochsto <116495532+mhochsto@users.noreply.github.com>
Date: Tue, 10 Dec 2024 13:57:39 +0100
Subject: [PATCH 12/16] feat: sdk version bump to 3.0.0
---
EvvaAbrevvaCapacitor.podspec | 2 +-
ios/Plugin/ble/AbrevvaPluginBLE.swift | 9 ++++-----
ios/Podfile | 2 +-
3 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/EvvaAbrevvaCapacitor.podspec b/EvvaAbrevvaCapacitor.podspec
index e5ab331..74e5a4c 100644
--- a/EvvaAbrevvaCapacitor.podspec
+++ b/EvvaAbrevvaCapacitor.podspec
@@ -21,5 +21,5 @@ TODO: Add long description of the pod here.
s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
s.dependency 'Capacitor'
- s.dependency 'AbrevvaSDK', '~> 2.0.2'
+ s.dependency 'AbrevvaSDK', '~> 3.0.0'
end
diff --git a/ios/Plugin/ble/AbrevvaPluginBLE.swift b/ios/Plugin/ble/AbrevvaPluginBLE.swift
index b7f956b..65d1972 100644
--- a/ios/Plugin/ble/AbrevvaPluginBLE.swift
+++ b/ios/Plugin/ble/AbrevvaPluginBLE.swift
@@ -85,9 +85,9 @@ public class AbrevvaPluginBLE: CAPPlugin {
let timeout = call.getDouble("timeout").map { Int($0) } ?? nil
bleManager.startScan(
- { device, _, rssi in
+ { device in
self.bleDeviceMap[device.getAddress()] = device
- let data = self.getAdvertismentData(device, rssi)
+ let data = self.getAdvertismentData(device)
self.notifyListeners("onScanResult", data: data)
},
{ error in
@@ -323,8 +323,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
}
private func getAdvertismentData(
- _ device: BleDevice,
- _ rssi: NSNumber
+ _ device: BleDevice
) -> [String: Any] {
var bleDeviceData: [String: Any] = [
@@ -333,7 +332,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
]
var advertismentData: [String: Any] = [
- "rssi": rssi
+ "rssi": device.advertisementData?.rssi
]
if let isConnectable = device.advertisementData?.isConnectable {
advertismentData["isConnectable"] = isConnectable
diff --git a/ios/Podfile b/ios/Podfile
index 1687c08..378f94a 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -13,7 +13,7 @@ end
target 'Plugin' do
capacitor_pods
- pod 'AbrevvaSDK', '~> 2.0.2'
+ pod 'AbrevvaSDK', '~> 3.0.0'
end
target 'PluginTests' do
From d2295d0218ad5c3e573b2e0fb649a2f657dae916 Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Tue, 10 Dec 2024 15:10:54 +0100
Subject: [PATCH 13/16] chore: update deps; run fmt
---
EvvaAbrevvaCapacitor.podspec | 2 +-
android/build.gradle | 2 +-
ios/Plugin/ble/AbrevvaPluginBLE.swift | 4 ++--
ios/Podfile | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/EvvaAbrevvaCapacitor.podspec b/EvvaAbrevvaCapacitor.podspec
index 74e5a4c..8a3531e 100644
--- a/EvvaAbrevvaCapacitor.podspec
+++ b/EvvaAbrevvaCapacitor.podspec
@@ -21,5 +21,5 @@ TODO: Add long description of the pod here.
s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
s.dependency 'Capacitor'
- s.dependency 'AbrevvaSDK', '~> 3.0.0'
+ s.dependency 'AbrevvaSDK', '~> 3.0.1'
end
diff --git a/android/build.gradle b/android/build.gradle
index 4749ff4..cd17235 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -70,7 +70,7 @@ dependencies {
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation "androidx.core:core-ktx:$coreKtx"
- implementation group: "com.evva.xesar", name: "abrevva-sdk-android", version: "3.0.0"
+ implementation group: "com.evva.xesar", name: "abrevva-sdk-android", version: "3.0.1"
testImplementation "junit:junit:$junitVersion"
diff --git a/ios/Plugin/ble/AbrevvaPluginBLE.swift b/ios/Plugin/ble/AbrevvaPluginBLE.swift
index 83482d9..7457341 100644
--- a/ios/Plugin/ble/AbrevvaPluginBLE.swift
+++ b/ios/Plugin/ble/AbrevvaPluginBLE.swift
@@ -87,7 +87,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
bleManager.startScan(
{ device in
self.bleDeviceMap[device.getAddress()] = device
- let data = self.getAdvertismentData(device)
+ let data = self.getAdvertismentData(device)
self.notifyListeners("onScanResult", data: data)
},
{ error in
@@ -334,7 +334,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
]
var advertismentData: [String: Any] = [
- "rssi": device.advertisementData?.rssi
+ "rssi": device.advertisementData?.rssi
]
if let isConnectable = device.advertisementData?.isConnectable {
advertismentData["isConnectable"] = isConnectable
diff --git a/ios/Podfile b/ios/Podfile
index 378f94a..81118e7 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -13,7 +13,7 @@ end
target 'Plugin' do
capacitor_pods
- pod 'AbrevvaSDK', '~> 3.0.0'
+ pod 'AbrevvaSDK', '~> 3.0.1'
end
target 'PluginTests' do
From 50c25b49b1c504589625f7791c05ee930634f149 Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Tue, 10 Dec 2024 15:26:36 +0100
Subject: [PATCH 14/16] refactor: allow for optional values in advertisement
map
---
ios/Plugin/ble/AbrevvaPluginBLE.swift | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/ios/Plugin/ble/AbrevvaPluginBLE.swift b/ios/Plugin/ble/AbrevvaPluginBLE.swift
index 7457341..7cdbd32 100644
--- a/ios/Plugin/ble/AbrevvaPluginBLE.swift
+++ b/ios/Plugin/ble/AbrevvaPluginBLE.swift
@@ -326,14 +326,14 @@ public class AbrevvaPluginBLE: CAPPlugin {
private func getAdvertismentData(
_ device: BleDevice
- ) -> [String: Any] {
+ ) -> [String: Any?] {
- var bleDeviceData: [String: Any] = [
+ var bleDeviceData: [String: Any?] = [
"deviceId": device.getAddress(),
"name": device.getName()
]
- var advertismentData: [String: Any] = [
+ var advertismentData: [String: Any?] = [
"rssi": device.advertisementData?.rssi
]
if let isConnectable = device.advertisementData?.isConnectable {
@@ -345,7 +345,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
return bleDeviceData
}
- var manufacturerData: [String: Any] = [
+ var manufacturerData: [String: Any?] = [
"companyIdentifier": mfData.companyIdentifier,
"version": mfData.version,
"mainFirmwareVersionMajor": mfData.mainFirmwareVersionMajor,
@@ -366,7 +366,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
"subComponentIdentifier": mfData.subComponentIdentifier,
"componentType": getComponentType(mfData.componentType)
]
- manufacturerData = manufacturerData.filter({$0.value != nil})
+
advertismentData["manufacturerData"] = manufacturerData
bleDeviceData["advertisementData"] = advertismentData
From 59237e34fbef5683d88c60fb13cd443d814a3680 Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Wed, 11 Dec 2024 10:13:09 +0100
Subject: [PATCH 15/16] feat: add support for allowDuplicates; introduce
DisengageStatusType enum
---
README.md | 110 ++++++++++++++++--
.../plugins/capacitor/AbrevvaPluginBLE.kt | 3 +-
ios/Plugin/ble/AbrevvaPluginBLE.swift | 5 +-
src/plugins/ble/client.spec.ts | 6 +-
src/plugins/ble/client.ts | 38 ++++--
src/plugins/ble/definitions.ts | 27 +++++
6 files changed, 160 insertions(+), 29 deletions(-)
diff --git a/README.md b/README.md
index 3800eba..998845c 100644
--- a/README.md
+++ b/README.md
@@ -54,40 +54,125 @@ npx cap sync
import { AbrevvaBLEClient, ScanResult } from "@evva/abrevva-capacitor";
class ExampleClass {
- private results: ScanResult[];
+ private devices: BleDevice[];
async startScan(event: any) {
- this.results = [];
-
- await AbrevvaBLEClient.requestLEScan({ timeout: 5_000 }, (result: ScanResult) => {
- this.results.push(result);
+ this.devices = [];
+
+ await AbrevvaBLEClient.initialize()
+ await AbrevvaBLEClient.startScan({ timeout: 5_000 }, (device: BleDevice) => {
+ this.devices.push(device);
+ }, (success: boolean) => {
+ console.log(`Scan started, success: ${success}`);
+ }, (success: boolean) => {
+ console.log(`Scan stopped, success: ${success}`);
});
}
}
```
+### Read EVVA component advertisement
+
+Get the EVVA advertisement data from a scanned EVVA component.
+
+```typescript
+const ad = device.advertisementData
+console.log(ad?.rssi)
+console.log(ad?.isConnectable)
+
+const md = ad?.manufacturerData
+console.log(md?.batteryStatus)
+console.log(md?.isOnline)
+console.log(md?.officeModeEnabled)
+console.log(md?.officeModeActive)
+// ...
+```
+
+There are several properties that can be accessed from the advertisement.
+
+```typescript
+export interface BleDeviceAdvertisementData {
+ rssi?: number;
+ isConnectable?: boolean;
+ manufacturerData?: BleDeviceManufacturerData;
+}
+
+export interface BleDeviceManufacturerData {
+ companyIdentifier?: string;
+ version?: number;
+ componentType?: "handle" | "escutcheon" | "cylinder" | "wallreader" | "emzy" | "iobox" | "unknown";
+ mainFirmwareVersionMajor?: number;
+ mainFirmwareVersionMinor?: number;
+ mainFirmwareVersionPatch?: number;
+ componentHAL?: string;
+ batteryStatus?: "battery-full" | "battery-empty";
+ mainConstructionMode?: boolean;
+ subConstructionMode?: boolean;
+ isOnline?: boolean;
+ officeModeEnabled?: boolean;
+ twoFactorRequired?: boolean;
+ officeModeActive?: boolean;
+ identifier?: string;
+ subFirmwareVersionMajor?: number;
+ subFirmwareVersionMinor?: number;
+ subFirmwareVersionPatch?: number;
+ subComponentIdentifier?: string;
+}
+```
+
### Localize EVVA component
-With the signalize method you can localize EVVA components. On a successful signalization the component will emit a melody indicating its location.
+With the signalize method you can localize scanned EVVA components. On a successful signalization the component will emit a melody indicating its location.
```typescript
const success = await AbrevvaBLEClient.signalize('deviceId');
```
-### Perform disengage on EVVA components
+### Disengage EVVA components
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.
```typescript
const status = await AbrevvaBLEClient.disengage(
+ 'deviceId',
'mobileId',
'mobileDeviceKey',
'mobileGroupId',
- 'mobileAccessData',
+ 'mediumAccessData',
false,
);
```
+There are several access status types upon attempting the component disengage.
+
+```typescript
+export enum DisengageStatusType {
+ /// Component
+ Authorized = "AUTHORIZED",
+ AuthorizedPermanentEngage = "AUTHORIZED_PERMANENT_ENGAGE",
+ AuthorizedPermanentDisengage = "AUTHORIZED_PERMANENT_DISENGAGE",
+ AuthorizedBatteryLow = "AUTHORIZED_BATTERY_LOW",
+ AuthorizedOffline = "AUTHORIZED_OFFLINE",
+ Unauthorized = "UNAUTHORIZED",
+ UnauthorizedOffline = "UNAUTHORIZED_OFFLINE",
+ SignalLocalization = "SIGNAL_LOCALIZATION",
+ MediumDefectOnline = "MEDIUM_DEFECT_ONLINE",
+ MediumBlacklisted = "MEDIUM_BLACKLISTED",
+ Error = "ERROR",
+
+ /// Interface
+ UnableToConnect = "UNABLE_TO_CONNECT",
+ UnableToSetNotifications = "UNABLE_TO_SET_NOTIFICATIONS",
+ UnableToReadChallenge = "UNABLE_TO_READ_CHALLENGE",
+ UnableToWriteMDF = "UNABLE_TO_WRITE_MDF",
+ AccessCipherError = "ACCESS_CIPHER_ERROR",
+ BleAdapterDisabled = "BLE_ADAPTER_DISABLED",
+ UnknownDevice = "UNKNOWN_DEVICE",
+ UnknownStatusCode = "UNKNOWN_STATUS_CODE",
+ Timeout = "TIMEOUT",
+}
+```
+
## API
@@ -147,10 +232,11 @@ const status = await AbrevvaBLEClient.disengage(
#### BleScannerOptions
-| Prop | Type |
-| --------------- | ------------------- |
-| **`macFilter`** | string
|
-| **`timeout`** | number
|
+| Prop | Type |
+| --------------------- | -------------------- |
+| **`macFilter`** | string
|
+| **`allowDuplicates`** | boolean
|
+| **`timeout`** | number
|
#### PluginListenerHandle
diff --git a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
index 4ff0b02..f022445 100644
--- a/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
+++ b/android/src/main/java/com/evva/xesar/abrevva/plugins/capacitor/AbrevvaPluginBLE.kt
@@ -199,6 +199,7 @@ class AbrevvaPluginBLE : Plugin() {
@PluginMethod
fun startScan(call: PluginCall) {
val macFilter = call.getString("macFilter", null)
+ val allowDuplicates = call.getBoolean("allowDuplicates", false)
val timeout = call.getFloat("timeout", 15000.0F)!!.toLong()
this.manager.startScan({ device ->
@@ -219,7 +220,7 @@ class AbrevvaPluginBLE : Plugin() {
data.put("value", success)
notifyListeners("onScanStop", data)
call.resolve()
- }, macFilter, false, timeout)
+ }, macFilter, allowDuplicates, timeout)
}
@PluginMethod
diff --git a/ios/Plugin/ble/AbrevvaPluginBLE.swift b/ios/Plugin/ble/AbrevvaPluginBLE.swift
index 7cdbd32..2946dd2 100644
--- a/ios/Plugin/ble/AbrevvaPluginBLE.swift
+++ b/ios/Plugin/ble/AbrevvaPluginBLE.swift
@@ -82,13 +82,14 @@ public class AbrevvaPluginBLE: CAPPlugin {
func startScan(_ call: CAPPluginCall) {
guard let bleManager = self.getBleManager(call) else { return }
let macFilter = call.getString("macFilter")
+ let allowDuplicates = call.getBool("allowDuplicates") ?? false
let timeout = call.getDouble("timeout").map { Int($0) } ?? nil
bleManager.startScan(
{ device in
self.bleDeviceMap[device.getAddress()] = device
let data = self.getAdvertismentData(device)
- self.notifyListeners("onScanResult", data: data)
+ self.notifyListeners("onScanResult", data: data as [String: Any])
},
{ error in
self.notifyListeners("onScanStart", data: ["value": error == nil])
@@ -99,7 +100,7 @@ public class AbrevvaPluginBLE: CAPPlugin {
call.resolve()
},
macFilter,
- false,
+ allowDuplicates,
timeout
)
}
diff --git a/src/plugins/ble/client.spec.ts b/src/plugins/ble/client.spec.ts
index 4cea663..9f0e416 100644
--- a/src/plugins/ble/client.spec.ts
+++ b/src/plugins/ble/client.spec.ts
@@ -5,7 +5,7 @@ import { Capacitor } from "@capacitor/core";
import type { AbrevvaBLEClientInterface } from "./client";
import { AbrevvaBLEClient } from "./client";
import { hexStringToDataView, numbersToDataView } from "./conversion";
-import type { BleDevice } from "./definitions";
+import { BleDevice, DisengageStatusType } from "./definitions";
import { AbrevvaBLE } from "./plugin";
interface AbrevvaBLEClientWithPrivate extends AbrevvaBLEClientInterface {
@@ -274,7 +274,7 @@ describe("AbrevvaBLEClient", () => {
expect(Capacitor.getPlatform()).toBe("android");
(AbrevvaBLE.disengage as jest.Mock).mockReturnValue({
- value: "ACCESS_STATUS_AUTHORIZED",
+ value: DisengageStatusType.Authorized,
});
const result = await AbrevvaBLEClient.disengage(mockDevice.deviceId, "", "", "", "", false);
expect(AbrevvaBLE.disengage).toHaveBeenCalledWith({
@@ -285,7 +285,7 @@ describe("AbrevvaBLEClient", () => {
mediumAccessData: "",
isPermanentRelease: false,
});
- expect(result).toEqual("ACCESS_STATUS_AUTHORIZED");
+ expect(result).toEqual(DisengageStatusType.Authorized);
});
it("should run startNotifications", async () => {
diff --git a/src/plugins/ble/client.ts b/src/plugins/ble/client.ts
index 815172e..944114a 100644
--- a/src/plugins/ble/client.ts
+++ b/src/plugins/ble/client.ts
@@ -1,7 +1,15 @@
import type { PluginListenerHandle } from "@capacitor/core";
import { dataViewToHexString, hexStringToDataView } from "./conversion";
-import type { InitializeOptions, TimeoutOptions, ReadResult, BleScannerOptions, BleDevice, Data } from "./definitions";
+import {
+ BleDevice,
+ BleScannerOptions,
+ Data,
+ DisengageStatusType,
+ InitializeOptions,
+ ReadResult,
+ TimeoutOptions,
+} from "./definitions";
import { AbrevvaBLE } from "./plugin";
import { getQueue } from "./queue";
import { validateUUID } from "./validators";
@@ -227,7 +235,7 @@ class AbrevvaBLEClientClass implements AbrevvaBLEClientInterface {
isPermanentRelease: boolean,
onConnect?: (address: string) => void,
onDisconnect?: (address: string) => void,
- ): Promise {
+ ): Promise {
return await this.queue(async () => {
if (onConnect) {
await this.eventListeners.get(`connected|${deviceId}`)?.remove();
@@ -248,16 +256,24 @@ class AbrevvaBLEClientClass implements AbrevvaBLEClientInterface {
);
}
- const result = await AbrevvaBLE.disengage({
- deviceId,
- mobileId,
- mobileDeviceKey,
- mobileGroupId,
- mediumAccessData,
- isPermanentRelease,
- });
+ const status = (
+ await AbrevvaBLE.disengage({
+ deviceId,
+ mobileId,
+ mobileDeviceKey,
+ mobileGroupId,
+ mediumAccessData,
+ isPermanentRelease,
+ })
+ ).value;
- return result.value;
+ let result: DisengageStatusType;
+ if (Object.values(DisengageStatusType).some((val: string) => val === status)) {
+ result = status;
+ } else {
+ result = DisengageStatusType.Error;
+ }
+ return result;
});
}
diff --git a/src/plugins/ble/definitions.ts b/src/plugins/ble/definitions.ts
index 96d23d1..7e56377 100644
--- a/src/plugins/ble/definitions.ts
+++ b/src/plugins/ble/definitions.ts
@@ -24,6 +24,7 @@ export interface TimeoutOptions {
export interface BleScannerOptions {
macFilter?: string;
+ allowDuplicates?: boolean;
timeout?: number;
}
@@ -91,6 +92,32 @@ export interface DisengageOptions {
isPermanentRelease: boolean;
}
+export enum DisengageStatusType {
+ /// Component
+ Authorized = "AUTHORIZED",
+ AuthorizedPermanentEngage = "AUTHORIZED_PERMANENT_ENGAGE",
+ AuthorizedPermanentDisengage = "AUTHORIZED_PERMANENT_DISENGAGE",
+ AuthorizedBatteryLow = "AUTHORIZED_BATTERY_LOW",
+ AuthorizedOffline = "AUTHORIZED_OFFLINE",
+ Unauthorized = "UNAUTHORIZED",
+ UnauthorizedOffline = "UNAUTHORIZED_OFFLINE",
+ SignalLocalization = "SIGNAL_LOCALIZATION",
+ MediumDefectOnline = "MEDIUM_DEFECT_ONLINE",
+ MediumBlacklisted = "MEDIUM_BLACKLISTED",
+ Error = "ERROR",
+
+ /// Interface
+ UnableToConnect = "UNABLE_TO_CONNECT",
+ UnableToSetNotifications = "UNABLE_TO_SET_NOTIFICATIONS",
+ UnableToReadChallenge = "UNABLE_TO_READ_CHALLENGE",
+ UnableToWriteMDF = "UNABLE_TO_WRITE_MDF",
+ AccessCipherError = "ACCESS_CIPHER_ERROR",
+ BleAdapterDisabled = "BLE_ADAPTER_DISABLED",
+ UnknownDevice = "UNKNOWN_DEVICE",
+ UnknownStatusCode = "UNKNOWN_STATUS_CODE",
+ Timeout = "TIMEOUT",
+}
+
export interface AbrevvaBLEInterface {
initialize(options?: InitializeOptions): Promise;
isEnabled(): Promise;
From fd018ae760e67cd6baf726cea37b2fd158f75680 Mon Sep 17 00:00:00 2001
From: 0x7061 <1425202+0x7061@users.noreply.github.com>
Date: Wed, 11 Dec 2024 10:23:07 +0100
Subject: [PATCH 16/16] chore: fix test-app and bump deps
---
test-app/package-lock.json | 6 +++---
test-app/src/app/ble/ble.component.ts | 13 +++----------
2 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/test-app/package-lock.json b/test-app/package-lock.json
index b4acdf8..aae26ee 100644
--- a/test-app/package-lock.json
+++ b/test-app/package-lock.json
@@ -11652,9 +11652,9 @@
"dev": true
},
"node_modules/nanoid": {
- "version": "3.3.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "version": "3.3.8",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
+ "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"dev": true,
"funding": [
{
diff --git a/test-app/src/app/ble/ble.component.ts b/test-app/src/app/ble/ble.component.ts
index cca104b..8105532 100644
--- a/test-app/src/app/ble/ble.component.ts
+++ b/test-app/src/app/ble/ble.component.ts
@@ -20,7 +20,7 @@ export class BleComponent implements OnInit {
const timeout = 5_000;
this.results = [];
- await AbrevvaBLEClient.requestLEScan({ timeout: timeout }, (result: BleDevice) => {
+ await AbrevvaBLEClient.startScan({ timeout: timeout }, (result: BleDevice) => {
this.results.push(result);
this.changeDetectorRef.detectChanges();
});
@@ -30,16 +30,9 @@ export class BleComponent implements OnInit {
}
async disengage(device: BleDevice) {
- await AbrevvaBLEClient.connect(
- device.deviceId,
- (device: BleDevice) => {
- console.log(`disconnected: ${device}`);
- },
- { timeout: 1_000 },
- );
-
+ await AbrevvaBLEClient.stopScan();
await AbrevvaBLEClient.disengage(
- "deviceId",
+ device.deviceId,
"mobileId",
"mobileDeviceKey",
"mobileGroupId",