The EVVA Abrevva Capacitor Plugin 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 | Version |
|---|---|
| Capacitor | 7+ |
| Java | 17+ |
| Android | 11+ |
| Android API | 30+ |
| Kotlin | 2.x |
| iOS | 16.0+ |
| Xcode | 15.3+ |
| Swift | 5.10+ |
npm install @evva/abrevva-capacitor
npx cap sync
In your app add a post_install hook in your Podfile to resolve a nasty CocoaPods limitation with XCFrameworks.
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
endimport { AbrevvaBLEClient, BleDevice } from "@evva/abrevva-capacitor";
class ExampleClass {
private devices: BleDevice[];
async startScan(event: any) {
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}`);
});
}
}Get the EVVA advertisement data from a scanned EVVA component.
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.
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;
}With the signalize method you can localize scanned EVVA components. On a successful signalization the component will emit a melody indicating its location.
const success = await AbrevvaBLEClient.signalize('deviceId');For the component disengage you have to provide access credentials to the EVVA component. Those are generally acquired from the Xesar software.
Note: Since 6.1.0 the
mobileIdstring can be passed as is, without sha256 hashing the input first.
const result = await AbrevvaBLEClient.disengageWithXvnResponse(
'deviceId',
'mobileId', // `xsMobileId` string from medium blob data
'mobileDeviceKey', // `xsMOBDK` string from medium blob data
'mobileGroupId', // `xsMOBGID` string from medium blob data
'mediumAccessData', // `mediumDataFrame` string from medium blob data
false, // office mode flag
);
console.log(`status=${result.status} xvnData=${result.xvnData}`)There are several access status types upon attempting the component disengage.
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",
}Use the CodingStation to write or update access data onto an EVVA identification medium.
import { AbrevvaCodingStation } from "@evva/abrevva-capacitor";
export class ExampleClass {
async writeMedium() {
try {
await AbrevvaCodingStation.register({
url: "url",
clientId: "clientId",
username: "username",
password: "password",
});
await AbrevvaCodingStation.connect();
await AbrevvaCodingStation.write();
await AbrevvaCodingStation.disconnect();
} catch (e) {
console.log(`Failed to write medium: ${e}`);
}
}
}| 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> |
| 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> |
| write | (options: WriteOptions & TimeoutOptions) => Promise<void> |
| signalize | (options: SignalizeOptions) => Promise<void> |
| disengage | (options: DisengageOptions) => Promise<StringResult> |
| disengageWithXvnResponse | (options: DisengageOptions) => Promise<DisengageResult> |
| startNotifications | (options: ReadOptions) => Promise<void> |
| stopNotifications | (options: ReadOptions) => Promise<void> |
| Prop | Type |
|---|---|
androidNeverForLocation |
boolean |
| Prop | Type |
|---|---|
value |
boolean |
| Prop | Type |
|---|---|
macFilter |
string |
allowDuplicates |
boolean |
timeout |
number |
| Prop | Type |
|---|---|
remove |
() => Promise<void> |
| Prop | Type |
|---|---|
value |
string |
| Prop | Type |
|---|---|
deviceId |
string |
name |
string |
advertisementData |
BleDeviceAdvertisementData |
| Prop | Type |
|---|---|
rssi |
number |
isConnectable |
boolean |
manufacturerData |
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 |
| Prop | Type |
|---|---|
deviceId |
string |
| Prop | Type |
|---|---|
timeout |
number |
| Prop | Type |
|---|---|
deviceId |
string |
service |
string |
characteristic |
string |
| Prop | Type |
|---|---|
deviceId |
string |
service |
string |
characteristic |
string |
value |
string |
| Prop | Type |
|---|---|
deviceId |
string |
| Prop | Type |
|---|---|
value |
string |
| Prop | Type |
|---|---|
deviceId |
string |
mobileId |
string |
mobileDeviceKey |
string |
mobileGroupId |
string |
mediumAccessData |
string |
isPermanentRelease |
boolean |
| Prop | Type |
|---|---|
status |
DisengageStatusType |
xvnData |
string |
| Method | Signature |
|---|---|
| encrypt | (options: { key: string; iv: string; adata: string; pt: string; tagLength: number; }) => Promise<{ cipherText: string; authTag: string; }> |
| encryptFile | (options: { sharedSecret: string; ptPath: string; ctPath: string; }) => Promise<void> |
| decrypt | (options: { key: string; iv: string; adata: string; ct: string; tagLength: number; }) => Promise<{ plainText: string; authOk: boolean; }> |
| decryptFile | (options: { sharedSecret: string; ctPath: string; ptPath: string; }) => Promise<void> |
| decryptFileFromURL | (options: { sharedSecret: string; url: string; ptPath: string; }) => Promise<void> |
| generateKeyPair | () => Promise<{ privateKey: string; publicKey: string; }> |
| computeSharedSecret | (options: { privateKey: string; peerPublicKey: string; }) => Promise<{ sharedSecret: string; }> |
| computeED25519PublicKey | (options: { privateKey: string; }) => Promise<{ publicKey: string; }> |
| sign | (options: { privateKey: string; data: string; }) => Promise<{ signature: string; }> |
| verify | (options: { publicKey: string; data: string; signature: string; }) => Promise<void> |
| random | (options: { numBytes: number; }) => Promise<{ value: string; }> |
| derive | (options: { key: string; salt: string; info: string; length: number; }) => Promise<{ value: string; }> |
| Method | Signature |
|---|---|
| register | (options: CSConnectionOptions) => Promise<void> |
| connect | () => Promise<void> |
| disconnect | () => Promise<void> |
| write | () => Promise<void> |
| Prop | Type |
|---|---|
url |
string |
clientId |
string |
username |
string |
password |
string |
| Members | Value |
|---|---|
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" |
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" |