homebridge-ttlock-accesscode 1.0.1 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +5 -5
  2. package/config.schema.json +31 -4
  3. package/dist/api/ttlockApi.d.ts +9 -8
  4. package/dist/api/ttlockApi.js +128 -67
  5. package/dist/api/ttlockApi.js.map +1 -1
  6. package/dist/api/usageTracker.d.ts +37 -0
  7. package/dist/api/usageTracker.js +276 -0
  8. package/dist/api/usageTracker.js.map +1 -0
  9. package/dist/config.d.ts +6 -0
  10. package/dist/config.js +23 -11
  11. package/dist/config.js.map +1 -1
  12. package/dist/devices/accessoryInformation.d.ts +3 -0
  13. package/dist/devices/accessoryInformation.js +28 -0
  14. package/dist/devices/accessoryInformation.js.map +1 -0
  15. package/dist/devices/baseDevice.d.ts +58 -0
  16. package/dist/devices/baseDevice.js +376 -0
  17. package/dist/devices/baseDevice.js.map +1 -0
  18. package/dist/devices/create.d.ts +4 -0
  19. package/dist/devices/create.js +27 -0
  20. package/dist/devices/create.js.map +1 -0
  21. package/dist/devices/descriptorHelpers.d.ts +5 -0
  22. package/dist/devices/descriptorHelpers.js +82 -0
  23. package/dist/devices/descriptorHelpers.js.map +1 -0
  24. package/dist/devices/deviceManager.d.ts +19 -0
  25. package/dist/devices/deviceManager.js +74 -0
  26. package/dist/devices/deviceManager.js.map +1 -0
  27. package/dist/devices/deviceTypes.d.ts +44 -0
  28. package/dist/devices/deviceTypes.js +2 -0
  29. package/dist/devices/deviceTypes.js.map +1 -0
  30. package/dist/devices/homekitLock.d.ts +18 -0
  31. package/dist/devices/homekitLock.js +191 -0
  32. package/dist/devices/homekitLock.js.map +1 -0
  33. package/dist/index.js +1 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/platform.d.ts +45 -19
  36. package/dist/platform.js +397 -234
  37. package/dist/platform.js.map +1 -1
  38. package/dist/taskQueue.d.ts +12 -0
  39. package/dist/taskQueue.js +50 -0
  40. package/dist/taskQueue.js.map +1 -0
  41. package/dist/utils.d.ts +10 -2
  42. package/dist/utils.js +50 -5
  43. package/dist/utils.js.map +1 -1
  44. package/package.json +32 -21
  45. package/dist/homekitDevice.d.ts +0 -44
  46. package/dist/homekitDevice.js +0 -502
  47. package/dist/homekitDevice.js.map +0 -1
  48. package/dist/platformAccessoryInformation.d.ts +0 -3
  49. package/dist/platformAccessoryInformation.js +0 -35
  50. package/dist/platformAccessoryInformation.js.map +0 -1
  51. package/dist/types/index.d.ts +0 -39
  52. package/dist/types/index.js +0 -2
  53. package/dist/types/index.js.map +0 -1
@@ -0,0 +1,44 @@
1
+ import type { Characteristic, CharacteristicValue, WithUUID } from 'homebridge';
2
+ import type HomeKitDevice from './baseDevice.js';
3
+ import type TTLockAccessCodePlatform from '../platform.js';
4
+ export type TTLockDevice = Lock;
5
+ export interface SysInfo {
6
+ alias: string;
7
+ battery: number;
8
+ device_id: string;
9
+ fw_ver: string;
10
+ hw_ver: string;
11
+ mac: string;
12
+ model: string;
13
+ passcodes?: Passcode[];
14
+ state: number;
15
+ [key: string]: string | number | boolean | Passcode[] | undefined;
16
+ }
17
+ export interface Lock {
18
+ feature_info: FeatureInfo;
19
+ last_seen: Date;
20
+ offline: boolean;
21
+ sys_info: SysInfo;
22
+ }
23
+ export interface FeatureInfo {
24
+ passcode: boolean;
25
+ }
26
+ export interface Passcode {
27
+ passcode_id: string;
28
+ index: string;
29
+ lock_id: string;
30
+ passcode: string;
31
+ }
32
+ export interface DescriptorContext {
33
+ platform: TTLockAccessCodePlatform;
34
+ device: HomeKitDevice;
35
+ }
36
+ export interface CharacteristicDescriptor {
37
+ type: WithUUID<new () => Characteristic>;
38
+ name?: string;
39
+ writable?: boolean;
40
+ syncGroup?: string;
41
+ getInitial(context?: DescriptorContext): CharacteristicValue;
42
+ getCurrent(context?: DescriptorContext): CharacteristicValue;
43
+ applySet?(value: CharacteristicValue, context: DescriptorContext): Promise<void | string>;
44
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=deviceTypes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deviceTypes.js","sourceRoot":"","sources":["../../src/devices/deviceTypes.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import type { Service, WithUUID } from 'homebridge';
2
+ import HomeKitDevice from './baseDevice.js';
3
+ import type TTLockAccessCodePlatform from '../platform.js';
4
+ import type { Lock, CharacteristicDescriptor } from './deviceTypes.js';
5
+ export default class HomeKitDeviceLock extends HomeKitDevice {
6
+ ttlockDevice: Lock;
7
+ private hasPasscode;
8
+ private lockBusy;
9
+ constructor(platform: TTLockAccessCodePlatform, ttlockDevice: Lock);
10
+ initialize(): Promise<void>;
11
+ protected getServiceTypes(): WithUUID<typeof Service>[];
12
+ protected buildDescriptors(service: Service): CharacteristicDescriptor[];
13
+ private getAccessCodeSupportedConfiguration;
14
+ private setAccessCodeControlPoint;
15
+ private getConfigurationState;
16
+ protected updateAllServicesAndCharacteristics(forceUpdate: boolean): Promise<void>;
17
+ identify(): void;
18
+ }
@@ -0,0 +1,191 @@
1
+ import pkg from 'ber-tlv';
2
+ import HomeKitDevice from './baseDevice.js';
3
+ import { buildLockDescriptors, buildBatteryDescriptors, buildAccessCodeDescriptors, } from './descriptorHelpers.js';
4
+ const { TlvFactory } = pkg;
5
+ export default class HomeKitDeviceLock extends HomeKitDevice {
6
+ ttlockDevice;
7
+ hasPasscode;
8
+ lockBusy = false;
9
+ constructor(platform, ttlockDevice) {
10
+ super(platform, ttlockDevice, 6 /* Categories.DOOR_LOCK */, 'DOOR_LOCK');
11
+ this.ttlockDevice = ttlockDevice;
12
+ this.hasPasscode = !!ttlockDevice.feature_info.passcode;
13
+ this.setupServices();
14
+ }
15
+ async initialize() {
16
+ await this.startPolling();
17
+ }
18
+ getServiceTypes() {
19
+ const types = [this.platform.Service.LockMechanism, this.platform.Service.Battery];
20
+ if (this.hasPasscode) {
21
+ types.push(this.platform.Service.AccessCode);
22
+ }
23
+ return types;
24
+ }
25
+ buildDescriptors(service) {
26
+ const C = this.platform.Characteristic;
27
+ if (service.UUID === this.platform.Service.LockMechanism.UUID) {
28
+ return buildLockDescriptors(C, async (value, context) => {
29
+ await this.deviceManager.controlDevice(context.device.id, 'state', value);
30
+ });
31
+ }
32
+ if (service.UUID === this.platform.Service.Battery.UUID) {
33
+ return buildBatteryDescriptors(C);
34
+ }
35
+ if (service.UUID === this.platform.Service.AccessCode.UUID) {
36
+ return buildAccessCodeDescriptors(C, () => this.getAccessCodeSupportedConfiguration(), async (value, context) => {
37
+ return await this.setAccessCodeControlPoint(context.device.ttlockDevice.sys_info, value);
38
+ }, () => this.getConfigurationState());
39
+ }
40
+ return [];
41
+ }
42
+ getAccessCodeSupportedConfiguration() {
43
+ const configuration = {
44
+ '01': Buffer.from([1]),
45
+ '02': Buffer.from([6]),
46
+ '03': Buffer.from([9]),
47
+ '04': Buffer.from([10]),
48
+ };
49
+ const tlvBuffer = [];
50
+ for (const [key, value] of Object.entries(configuration)) {
51
+ const keyInt = parseInt(key, 16);
52
+ tlvBuffer.push(Buffer.from([keyInt, value.length, ...value]));
53
+ }
54
+ return Buffer.concat(tlvBuffer).toString('base64') ?? 'AQEBAgEGAwEJBAEK';
55
+ }
56
+ async setAccessCodeControlPoint(device, value) {
57
+ try {
58
+ this.lockBusy = true;
59
+ this.isUpdating = true;
60
+ const decodedTlv = TlvFactory.parse(Buffer.from(String(value), 'base64').toString('hex'));
61
+ this.log.debug(`Decoded TLV for AccessCodeControlPoint on ${this.name}:`, decodedTlv);
62
+ let responseTlv = '';
63
+ let response = '';
64
+ let requestType = '';
65
+ let identifier = '', accessCode = '', flags = '', status = '';
66
+ switch (Number(decodedTlv[0].value.toString('hex'))) {
67
+ case 1: {
68
+ requestType = 'List';
69
+ responseTlv = '010101';
70
+ device.passcodes.forEach((pc, index) => {
71
+ identifier = TlvFactory.serialize(TlvFactory.primitiveTlv('01', String(pc.index).padStart(2, '0'))).toString('hex');
72
+ accessCode = TlvFactory.serialize(TlvFactory.primitiveTlv('02', Buffer.from(pc.passcode).toString('hex'))).toString('hex');
73
+ flags = TlvFactory.serialize(TlvFactory.primitiveTlv('03', '00')).toString('hex');
74
+ status = TlvFactory.serialize(TlvFactory.primitiveTlv('04', '00')).toString('hex');
75
+ this.log.debug(`Passcode ${pc.passcode} found on ${this.name}`);
76
+ responseTlv += TlvFactory.serialize(TlvFactory.primitiveTlv('03', identifier + accessCode + flags + status)).toString('hex') + (index !== (device.passcodes.length - 1) ? '0000' : '');
77
+ });
78
+ response = Buffer.from(responseTlv, 'hex').toString('base64');
79
+ break;
80
+ }
81
+ case 2: {
82
+ requestType = 'Read';
83
+ responseTlv = '010102';
84
+ if (device.passcodes.length > 0) {
85
+ for (let index = 1; index < decodedTlv.length; ++index) {
86
+ const element = decodedTlv[index];
87
+ const readReq = TlvFactory.parse(element.value);
88
+ if (readReq.length > 0) {
89
+ const passcodeIndexHex = readReq[0].value.toString('hex');
90
+ const passcodeIndex = parseInt(passcodeIndexHex, 16);
91
+ const pc = device.passcodes[passcodeIndex];
92
+ if (pc) {
93
+ this.log.debug(`Reading passcode ${pc.passcode} on ${this.name}`);
94
+ identifier = TlvFactory.serialize(TlvFactory.primitiveTlv('01', String(pc.index).padStart(2, '0'))).toString('hex');
95
+ accessCode = TlvFactory.serialize(TlvFactory.primitiveTlv('02', Buffer.from(pc.passcode).toString('hex'))).toString('hex');
96
+ flags = TlvFactory.serialize(TlvFactory.primitiveTlv('03', '00')).toString('hex');
97
+ status = TlvFactory.serialize(TlvFactory.primitiveTlv('04', '00')).toString('hex');
98
+ }
99
+ }
100
+ responseTlv += TlvFactory.serialize(TlvFactory.primitiveTlv('03', identifier + accessCode + flags + status)).toString('hex') + (index !== (decodedTlv.length - 1) ? '0000' : '');
101
+ }
102
+ }
103
+ response = Buffer.from(responseTlv, 'hex').toString('base64');
104
+ break;
105
+ }
106
+ case 3: {
107
+ requestType = 'Add';
108
+ responseTlv = '010103';
109
+ for (let index = 1; index < decodedTlv.length; index++) {
110
+ const addReq = TlvFactory.parse(decodedTlv[index].value);
111
+ if (addReq.length > 0) {
112
+ const newPassCodeHex = addReq[0];
113
+ const newPassCode = newPassCodeHex.value.toString();
114
+ let pc = device.passcodes.find(p => p.passcode === newPassCode);
115
+ if (!pc) {
116
+ this.log.info(`Adding new passcode ${newPassCode} to ${this.name}`);
117
+ try {
118
+ const newPc = await this.deviceManager
119
+ .managePasscodes(device.device_id, 'add', newPassCode);
120
+ device.passcodes = await this.deviceManager.managePasscodes(device.device_id, 'get');
121
+ pc = device.passcodes.find((p) => p.passcode_id === newPc.keyboardPwdId.toString() ||
122
+ p.passcode === newPassCode);
123
+ }
124
+ catch (err) {
125
+ this.log.error(`Failed to add passcode ${newPassCode} to ${this.name}`, err);
126
+ }
127
+ }
128
+ else {
129
+ this.log.debug(`Passcode ${newPassCode} already exists on ${this.name}`);
130
+ }
131
+ if (pc) {
132
+ identifier = TlvFactory.serialize(TlvFactory.primitiveTlv('01', String(pc.index).padStart(2, '0'))).toString('hex');
133
+ accessCode = TlvFactory.serialize(TlvFactory.primitiveTlv('02', Buffer.from(pc.passcode).toString('hex'))).toString('hex');
134
+ flags = TlvFactory.serialize(TlvFactory.primitiveTlv('03', '00')).toString('hex');
135
+ status = TlvFactory.serialize(TlvFactory.primitiveTlv('04', '00')).toString('hex');
136
+ responseTlv += TlvFactory.serialize(TlvFactory.primitiveTlv('03', identifier + accessCode + flags + status)).toString('hex') + (index !== (decodedTlv.length - 1) ? '0000' : '');
137
+ }
138
+ }
139
+ }
140
+ response = Buffer.from(responseTlv, 'hex').toString('base64');
141
+ break;
142
+ }
143
+ case 5: {
144
+ requestType = 'Delete';
145
+ responseTlv = '010105';
146
+ const deleteReq = TlvFactory.parse(decodedTlv[1].value);
147
+ if (deleteReq.length > 0) {
148
+ const deletePassCodeIndexHex = deleteReq[0].value.toString('hex');
149
+ const deletePassCodeIndex = parseInt(deletePassCodeIndexHex, 16);
150
+ const pc = device.passcodes[deletePassCodeIndex];
151
+ if (pc) {
152
+ this.log.info(`Deleting passcode ${pc.passcode} on ${this.name}`);
153
+ await this.deviceManager.managePasscodes(device.device_id, 'delete', pc.passcode_id);
154
+ device.passcodes = await this.deviceManager.managePasscodes(device.device_id, 'get');
155
+ identifier = TlvFactory.serialize(TlvFactory.primitiveTlv('01', String(pc.index).padStart(2, '0'))).toString('hex');
156
+ accessCode = TlvFactory.serialize(TlvFactory.primitiveTlv('02', Buffer.from(pc.passcode).toString('hex'))).toString('hex');
157
+ flags = TlvFactory.serialize(TlvFactory.primitiveTlv('03', '00')).toString('hex');
158
+ status = TlvFactory.serialize(TlvFactory.primitiveTlv('04', '00')).toString('hex');
159
+ responseTlv += TlvFactory.serialize(TlvFactory.primitiveTlv('03', identifier + accessCode + flags + status)).toString('hex');
160
+ }
161
+ }
162
+ response = Buffer.from(responseTlv, 'hex').toString('base64');
163
+ break;
164
+ }
165
+ }
166
+ this.log.info(`Access Code Control ${requestType} Request completed for ${this.name}`);
167
+ return response;
168
+ }
169
+ catch (error) {
170
+ this.log.error('Error processing AccessCodeControlPoint', error);
171
+ this.ttlockDevice.offline = true;
172
+ await this.stopPolling();
173
+ return '';
174
+ }
175
+ finally {
176
+ this.lockBusy = false;
177
+ this.isUpdating = false;
178
+ this.updateEmitter.emit('updateComplete');
179
+ }
180
+ }
181
+ getConfigurationState() {
182
+ return this.lockBusy ? 0 : 1;
183
+ }
184
+ async updateAllServicesAndCharacteristics(forceUpdate) {
185
+ await super.updateAllServicesAndCharacteristics(forceUpdate);
186
+ }
187
+ identify() {
188
+ this.log.info('identify');
189
+ }
190
+ }
191
+ //# sourceMappingURL=homekitLock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"homekitLock.js","sourceRoot":"","sources":["../../src/devices/homekitLock.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { TTLockAccessCodePlatform } from './platform.js';
1
+ import TTLockAccessCodePlatform from './platform.js';
2
2
  import { PLATFORM_NAME } from './settings.js';
3
3
  export default (api) => {
4
4
  api.registerPlatform(PLATFORM_NAME, TTLockAccessCodePlatform);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,eAAe,CAAC,GAAQ,EAAE,EAAE;IAC1B,GAAG,CAAC,gBAAgB,CAAC,aAAa,EAAE,wBAAwB,CAAC,CAAC;AAChE,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,wBAAwB,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,eAAe,CAAC,GAAQ,EAAQ,EAAE;IAChC,GAAG,CAAC,gBAAgB,CAAC,aAAa,EAAE,wBAAwB,CAAC,CAAC;AAChE,CAAC,CAAC"}
@@ -1,42 +1,68 @@
1
- import type { API, DynamicPlatformPlugin, Logging, PlatformAccessory, PlatformConfig, WithUUID } from 'homebridge';
1
+ import type { API, Characteristic, DynamicPlatformPlugin, Logging, PlatformAccessory, PlatformConfig, Service, WithUUID } from 'homebridge';
2
2
  import { EventEmitter } from 'node:events';
3
+ import DeviceManager from './devices/deviceManager.js';
4
+ import { TaskQueue } from './taskQueue.js';
3
5
  import { TTLockApi } from './api/ttlockApi.js';
6
+ import { UsageTracker } from './api/usageTracker.js';
4
7
  import type { TTLockAccessCodeConfig } from './config.js';
5
- export type TTLockAccessoryContext = {
6
- id?: string;
8
+ export type TTLockAccessCodeAccessoryContext = {
9
+ deviceId?: string;
7
10
  lastSeen?: Date;
8
11
  offline?: boolean;
9
12
  };
10
- export declare class TTLockAccessCodePlatform implements DynamicPlatformPlugin {
13
+ export default class TTLockAccessCodePlatform implements DynamicPlatformPlugin {
11
14
  readonly log: Logging;
12
15
  readonly api: API;
13
- private readonly homekitDevicesById;
14
- readonly configuredAccessories: Map<string, PlatformAccessory<TTLockAccessoryContext>>;
15
- readonly offlineAccessories: Map<string, PlatformAccessory<TTLockAccessoryContext>>;
16
+ readonly Characteristic: typeof Characteristic;
17
+ readonly configuredAccessories: Map<string, PlatformAccessory<TTLockAccessCodeAccessoryContext>>;
18
+ readonly offlineAccessories: Map<string, PlatformAccessory<TTLockAccessCodeAccessoryContext>>;
19
+ readonly Service: typeof Service;
16
20
  config: TTLockAccessCodeConfig;
21
+ deviceManager: DeviceManager | undefined;
17
22
  isShuttingDown: boolean;
18
- ongoingTasks: Promise<void>[];
19
- periodicDeviceDiscoveryEmitter: EventEmitter<[never]>;
20
23
  periodicDeviceDiscovering: boolean;
24
+ periodicDeviceDiscoveryEmitter: EventEmitter;
21
25
  ttLockApi: TTLockApi | undefined;
26
+ usageTracker: UsageTracker | undefined;
27
+ taskQueue: TaskQueue;
28
+ private readonly homekitDevicesById;
29
+ private deviceDiscoveredHandler?;
30
+ private platformInitialization;
22
31
  constructor(log: Logging, config: PlatformConfig, api: API);
23
- private createAndAuthenticateApi;
32
+ private setupDeviceEventEmitter;
33
+ initializePlatform(): Promise<void>;
34
+ private logInitializationDetails;
35
+ private verifyEnvironment;
36
+ private didFinishLaunching;
37
+ private setupPeriodicDiscovery;
24
38
  private discoverDevices;
25
- private getDetailedLocks;
26
- private foundDevice;
27
39
  private periodicDeviceDiscovery;
28
- private findDiscoveredDevice;
29
- private updateAccessoryDeviceStatus;
30
- private updateOrCreateHomeKitDevice;
31
- private updateAccessoryStatus;
40
+ private processDevice;
41
+ private handleOfflineDevices;
32
42
  private handleOfflineAccessory;
33
- registerPlatformAccessory(platformAccessory: PlatformAccessory<TTLockAccessoryContext>): void;
34
- configureAccessory(platformAccessory: PlatformAccessory<TTLockAccessoryContext>): void;
35
- getServiceName(service: {
43
+ private findPlatformAccessory;
44
+ private updateExistingDevice;
45
+ private addNewDevice;
46
+ private updateAccessoryStatus;
47
+ private startTTLockApi;
48
+ private stopTTLockApi;
49
+ private createAndAuthenticateApi;
50
+ computeEffectivePollingInterval(deviceCount: number, userIntervalMs: number): number;
51
+ private reschedulePolling;
52
+ lsc(serviceOrCharacteristic: Service | Characteristic | {
53
+ UUID: string;
54
+ }, characteristic?: Characteristic | {
36
55
  UUID: string;
37
56
  }): string;
57
+ getServiceName(service: {
58
+ UUID: string;
59
+ }): string | undefined;
38
60
  getCharacteristicName(characteristic: WithUUID<{
39
61
  name?: string | null;
40
62
  displayName?: string | null;
41
63
  }>): string | undefined;
64
+ registerPlatformAccessory(accessory: PlatformAccessory<TTLockAccessCodeAccessoryContext>): void;
65
+ configureAccessory(accessory: PlatformAccessory<TTLockAccessCodeAccessoryContext>): void;
66
+ private foundDevice;
67
+ private createHomeKitDevice;
42
68
  }