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
end
Initialize and scan for EVVA components
import { 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 } ` ) ;
} ) ;
}
}
Read EVVA component advertisement
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' ) ;
Disengage EVVA components
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 mobileId string 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" ,
}
Coding Identification Media
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 } ` ) ;
}
}
}
Prop
Type
androidNeverForLocation
boolean
Prop
Type
macFilter
string
allowDuplicates
boolean
timeout
number
Prop
Type
remove
() => Promise<void>
BleDeviceAdvertisementData
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
deviceId
string
service
string
characteristic
string
Prop
Type
deviceId
string
service
string
characteristic
string
value
string
Prop
Type
deviceId
string
Prop
Type
deviceId
string
mobileId
string
mobileDeviceKey
string
mobileGroupId
string
mediumAccessData
string
isPermanentRelease
boolean
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; }>
AbrevvaCodingStationInterface
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"