@uboness/homebridge-tedee 0.1.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 (50) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +17 -0
  3. package/README.md +41 -0
  4. package/config.schema.json +146 -0
  5. package/dist/common.d.ts +25 -0
  6. package/dist/common.d.ts.map +1 -0
  7. package/dist/common.js +51 -0
  8. package/dist/common.js.map +1 -0
  9. package/dist/device/device.d.ts +26 -0
  10. package/dist/device/device.d.ts.map +1 -0
  11. package/dist/device/device.js +46 -0
  12. package/dist/device/device.js.map +1 -0
  13. package/dist/device/index.d.ts +5 -0
  14. package/dist/device/index.d.ts.map +1 -0
  15. package/dist/device/index.js +5 -0
  16. package/dist/device/index.js.map +1 -0
  17. package/dist/device/lock.d.ts +28 -0
  18. package/dist/device/lock.d.ts.map +1 -0
  19. package/dist/device/lock.js +175 -0
  20. package/dist/device/lock.js.map +1 -0
  21. package/dist/index.d.ts +4 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +6 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/logger.d.ts +16 -0
  26. package/dist/logger.d.ts.map +1 -0
  27. package/dist/logger.js +26 -0
  28. package/dist/logger.js.map +1 -0
  29. package/dist/settings.d.ts +9 -0
  30. package/dist/settings.d.ts.map +1 -0
  31. package/dist/settings.js +10 -0
  32. package/dist/settings.js.map +1 -0
  33. package/dist/tedee-client.d.ts +51 -0
  34. package/dist/tedee-client.d.ts.map +1 -0
  35. package/dist/tedee-client.js +442 -0
  36. package/dist/tedee-client.js.map +1 -0
  37. package/dist/tedee-event-server.d.ts +25 -0
  38. package/dist/tedee-event-server.d.ts.map +1 -0
  39. package/dist/tedee-event-server.js +109 -0
  40. package/dist/tedee-event-server.js.map +1 -0
  41. package/dist/tedee-platform.d.ts +51 -0
  42. package/dist/tedee-platform.d.ts.map +1 -0
  43. package/dist/tedee-platform.js +186 -0
  44. package/dist/tedee-platform.js.map +1 -0
  45. package/dist/tedee.d.ts +99 -0
  46. package/dist/tedee.d.ts.map +1 -0
  47. package/dist/tedee.js +30 -0
  48. package/dist/tedee.js.map +1 -0
  49. package/package.json +66 -0
  50. package/tsconfig.json +31 -0
@@ -0,0 +1,109 @@
1
+ import EventEmitter from 'node:events';
2
+ import { createServer } from 'node:http';
3
+ import { WEBHOOK_DEFAULT_PORT, WEBHOOK_INSTANCE_HEADER, WEBHOOK_PATH } from "./settings.js";
4
+ export class TedeeEventServer {
5
+ config;
6
+ logger;
7
+ emitter = new EventEmitter();
8
+ server;
9
+ actualPort;
10
+ constructor(config, logger) {
11
+ this.config = config;
12
+ this.logger = logger.getLogger('webhook-server');
13
+ this.emitter.setMaxListeners(1000);
14
+ }
15
+ callbackUrl(host) {
16
+ if (!this.actualPort) {
17
+ throw new Error('Webhook server has not started yet');
18
+ }
19
+ return `http://${host}:${this.actualPort}${WEBHOOK_PATH}`;
20
+ }
21
+ on(event, handler) {
22
+ this.emitter.on(event, handler);
23
+ return { detach: () => this.emitter.off(event, handler) };
24
+ }
25
+ async start() {
26
+ if (this.server) {
27
+ return;
28
+ }
29
+ this.server = createServer((request, response) => {
30
+ this.handle(request, response).catch(error => {
31
+ this.logger.error(`failed to process webhook request`, error);
32
+ if (!response.headersSent) {
33
+ response.writeHead(500);
34
+ }
35
+ response.end();
36
+ });
37
+ });
38
+ try {
39
+ await new Promise((resolve, reject) => {
40
+ this.server.once('error', reject);
41
+ this.server.listen(this.config.port ?? WEBHOOK_DEFAULT_PORT, '0.0.0.0', () => {
42
+ this.server.off('error', reject);
43
+ const address = this.server.address();
44
+ this.actualPort = address.port;
45
+ this.logger.info(`listening on [${address.address}:${address.port}${WEBHOOK_PATH}]`);
46
+ resolve();
47
+ });
48
+ });
49
+ }
50
+ catch (error) {
51
+ this.server = undefined;
52
+ throw error;
53
+ }
54
+ }
55
+ async close() {
56
+ if (!this.server) {
57
+ return;
58
+ }
59
+ const server = this.server;
60
+ this.server = undefined;
61
+ await new Promise((resolve, reject) => {
62
+ server.close(error => error ? reject(error) : resolve());
63
+ });
64
+ }
65
+ async handle(request, response) {
66
+ const requestUrl = new URL(request.url ?? '/', 'http://localhost');
67
+ if (requestUrl.pathname !== WEBHOOK_PATH) {
68
+ response.writeHead(404);
69
+ response.end();
70
+ return;
71
+ }
72
+ if (!this.validateSecret(request)) {
73
+ response.writeHead(401);
74
+ response.end();
75
+ return;
76
+ }
77
+ let event;
78
+ if (request.method === 'POST') {
79
+ const body = await this.readBody(request);
80
+ event = global.JSON.parse(body);
81
+ }
82
+ else {
83
+ response.writeHead(405, { Allow: 'POST' });
84
+ response.end();
85
+ return;
86
+ }
87
+ response.writeHead(204);
88
+ response.end();
89
+ setImmediate(() => this.emitter.emit('event', event));
90
+ }
91
+ validateSecret(request) {
92
+ const actual = request.headers[WEBHOOK_INSTANCE_HEADER.toLowerCase()];
93
+ return Array.isArray(actual) ? actual.includes(this.config.instanceId) : actual === this.config.instanceId;
94
+ }
95
+ async readBody(request) {
96
+ const chunks = [];
97
+ let length = 0;
98
+ for await (const chunk of request) {
99
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
100
+ length += buffer.length;
101
+ if (length > 64 * 1024) {
102
+ throw new Error('Webhook payload is too large');
103
+ }
104
+ chunks.push(buffer);
105
+ }
106
+ return Buffer.concat(chunks).toString('utf8');
107
+ }
108
+ }
109
+ //# sourceMappingURL=tedee-event-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tedee-event-server.js","sourceRoot":"","sources":["../src/tedee-event-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { API, Characteristic, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service } from 'homebridge';
2
+ import { ILogger } from './logger.ts';
3
+ import { Tedee } from './tedee.ts';
4
+ export declare class TedeePlatform implements DynamicPlatformPlugin {
5
+ readonly Service: typeof Service;
6
+ readonly Characteristic: typeof Characteristic;
7
+ readonly api: API;
8
+ readonly logger: ILogger;
9
+ readonly unlockMode: Tedee.UnlockMode;
10
+ readonly lowBatteryThreshold: number;
11
+ private readonly config;
12
+ private readonly accessories;
13
+ private readonly devices;
14
+ private readonly detachables;
15
+ private readonly loggedIgnored;
16
+ private client?;
17
+ private refreshTimer?;
18
+ constructor(log: Logger, config: PlatformConfig, api: API);
19
+ configureAccessory(accessory: PlatformAccessory): void;
20
+ init(): Promise<void>;
21
+ dispose(): Promise<void>;
22
+ private createClient;
23
+ private syncLocks;
24
+ private registerLock;
25
+ private startRefreshTimer;
26
+ private refreshLocks;
27
+ lockConfig(id: number): TedeePlatform.LockConfig | undefined;
28
+ private lockIgnored;
29
+ private callbackInstanceId;
30
+ private lockModel;
31
+ }
32
+ export declare namespace TedeePlatform {
33
+ type Config = PlatformConfig & {
34
+ host: string;
35
+ port?: number;
36
+ token: string;
37
+ tokenMode?: 'plain' | 'encrypted';
38
+ apiVersion?: string;
39
+ unlockMode?: Tedee.UnlockMode;
40
+ lowBatteryThreshold?: number;
41
+ refreshInterval?: number;
42
+ webhookPort?: number;
43
+ locks?: LockConfig[];
44
+ };
45
+ type LockConfig = {
46
+ id: number;
47
+ ignore?: boolean;
48
+ pullSpringSwitch?: boolean;
49
+ };
50
+ }
51
+ //# sourceMappingURL=tedee-platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tedee-platform.d.ts","sourceRoot":"","sources":["../src/tedee-platform.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,GAAG,EACH,cAAc,EACd,qBAAqB,EACrB,MAAM,EACN,iBAAiB,EACjB,cAAc,EACd,OAAO,EACV,MAAM,YAAY,CAAC;AAKpB,OAAO,EAAiB,OAAO,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,qBAAa,aAAc,YAAW,qBAAqB;IAEvD,SAAgB,OAAO,EAAE,OAAO,OAAO,CAAC;IACxC,SAAgB,cAAc,EAAE,OAAO,cAAc,CAAC;IACtD,SAAgB,GAAG,EAAE,GAAG,CAAC;IACzB,SAAgB,MAAM,EAAE,OAAO,CAAC;IAEhC,SAAgB,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC;IAC7C,SAAgB,mBAAmB,EAAE,MAAM,CAAC;IAE5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA2B;IACvD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,MAAM,CAAC,CAAc;IAC7B,OAAO,CAAC,YAAY,CAAC,CAAiB;gBAE1B,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG;IAazD,kBAAkB,CAAC,SAAS,EAAE,iBAAiB;IAIzC,IAAI;IAuBJ,OAAO;IAWb,OAAO,CAAC,YAAY;YAcN,SAAS;YAyCT,YAAY;IA4B1B,OAAO,CAAC,iBAAiB;YAYX,YAAY;IAa1B,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,CAAC,UAAU,GAAG,SAAS;IAI5D,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,SAAS;CAWpB;AAED,yBAAiB,aAAa,CAAC;IAE3B,KAAY,MAAM,GAAG,cAAc,GAAG;QAClC,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;QAClC,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC;QAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;KACvB,CAAA;IAED,KAAY,UAAU,GAAG;QACrB,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAC7B,CAAA;CAEJ"}
@@ -0,0 +1,186 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { Detachables } from "./common.js";
3
+ import { Lock } from "./device/lock.js";
4
+ import { ContextLogger } from "./logger.js";
5
+ import { DEFAULT_LOCK_UNLOCK_MODE, DEFAULT_LOW_BATTERY_THRESHOLD, PLATFORM_NAME, PLUGIN_NAME } from "./settings.js";
6
+ import { Tedee } from "./tedee.js";
7
+ import { TedeeClient } from "./tedee-client.js";
8
+ export class TedeePlatform {
9
+ Service;
10
+ Characteristic;
11
+ api;
12
+ logger;
13
+ unlockMode;
14
+ lowBatteryThreshold;
15
+ config;
16
+ accessories = [];
17
+ devices = [];
18
+ detachables = new Detachables();
19
+ loggedIgnored = new Set();
20
+ client;
21
+ refreshTimer;
22
+ constructor(log, config, api) {
23
+ this.logger = new ContextLogger(log);
24
+ this.config = config;
25
+ this.api = api;
26
+ this.Service = api.hap.Service;
27
+ this.Characteristic = api.hap.Characteristic;
28
+ this.unlockMode = this.config.unlockMode ?? DEFAULT_LOCK_UNLOCK_MODE;
29
+ this.lowBatteryThreshold = this.config.lowBatteryThreshold ?? DEFAULT_LOW_BATTERY_THRESHOLD;
30
+ this.api.on('didFinishLaunching', () => void this.init());
31
+ this.api.on('shutdown', () => void this.dispose());
32
+ }
33
+ configureAccessory(accessory) {
34
+ this.accessories.push(accessory);
35
+ }
36
+ async init() {
37
+ try {
38
+ const client = this.createClient();
39
+ this.client = client;
40
+ this.detachables.add(client.on('connect', () => {
41
+ this.devices.forEach(device => device.setFault(false));
42
+ }));
43
+ this.detachables.add(client.on('disconnect', () => {
44
+ this.devices.forEach(device => device.setFault(true));
45
+ }));
46
+ await client.start();
47
+ const bridge = await client.bridge();
48
+ this.logger.info(`connected to Tedee Bridge [${bridge.name}] firmware [${bridge.version}]`);
49
+ const locks = await client.listLocks();
50
+ await this.syncLocks(client, locks);
51
+ this.startRefreshTimer();
52
+ }
53
+ catch (error) {
54
+ this.logger.error(`failed to initialize Tedee platform`, error);
55
+ }
56
+ }
57
+ async dispose() {
58
+ if (this.refreshTimer) {
59
+ clearInterval(this.refreshTimer);
60
+ this.refreshTimer = undefined;
61
+ }
62
+ await this.client?.close();
63
+ this.detachables.detach();
64
+ await Promise.all(this.devices.map(device => device.close()));
65
+ }
66
+ createClient() {
67
+ return new TedeeClient({
68
+ host: this.config.host,
69
+ port: this.config.port,
70
+ token: this.config.token,
71
+ tokenMode: this.config.tokenMode,
72
+ apiVersion: this.config.apiVersion,
73
+ webhook: {
74
+ port: this.config.webhookPort,
75
+ instanceId: this.callbackInstanceId()
76
+ }
77
+ }, this.logger);
78
+ }
79
+ async syncLocks(client, locks) {
80
+ const lockById = new Map(locks.map(lock => [lock.id, lock]));
81
+ // Drop accessories whose lock has disappeared from Tedee or is now ignored.
82
+ const stale = [];
83
+ for (let i = 0; i < this.accessories.length; i++) {
84
+ const accessory = this.accessories[i];
85
+ const lock = lockById.get(accessory.context.lockId);
86
+ const reason = !lock ? 'Lock no longer available' : this.lockIgnored(lock.id) ? 'Lock is ignored' : undefined;
87
+ if (reason) {
88
+ this.accessories.splice(i--, 1);
89
+ stale.push({ accessory, reason });
90
+ }
91
+ }
92
+ for (const { reason, accessory } of stale) {
93
+ this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
94
+ this.logger.info(`unregistering cached lock accessory [${accessory.displayName}] (reason: ${reason})`);
95
+ const deviceIndex = this.devices.findIndex(device => device.id === accessory.context.lockId);
96
+ if (deviceIndex >= 0) {
97
+ const [device] = this.devices.splice(deviceIndex, 1);
98
+ await device.close();
99
+ }
100
+ }
101
+ for (const lock of locks) {
102
+ if (this.lockIgnored(lock.id)) {
103
+ if (!this.loggedIgnored.has(lock.id)) {
104
+ this.loggedIgnored.add(lock.id);
105
+ this.logger.info(`ignoring Tedee lock [${lock.name}] ID [${lock.id}]`);
106
+ }
107
+ continue;
108
+ }
109
+ const existing = this.devices.find(device => device.id === lock.id);
110
+ if (existing) {
111
+ existing.update(lock);
112
+ }
113
+ else {
114
+ await this.registerLock(client, lock);
115
+ }
116
+ }
117
+ }
118
+ async registerLock(client, lock) {
119
+ const uuid = this.api.hap.uuid.generate(`tedee:lock:${lock.serialNumber || lock.id}`);
120
+ let accessory = this.accessories.find(accessory => accessory.UUID === uuid);
121
+ if (!accessory) {
122
+ accessory = new this.api.platformAccessory(lock.name, uuid);
123
+ this.logger.info(`registering Tedee lock [${accessory.displayName}] ID [${lock.id}]`);
124
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
125
+ this.accessories.push(accessory);
126
+ }
127
+ else {
128
+ this.logger.info(`found existing Tedee lock [${accessory.displayName}] ID [${lock.id}]`);
129
+ }
130
+ accessory.context.lockId = lock.id;
131
+ accessory.context.serialNumber = lock.serialNumber;
132
+ // Written once on (re)registration — covers stale cached metadata after firmware
133
+ // updates, renames, etc. update() handles state changes during the session.
134
+ accessory.getService(this.Service.AccessoryInformation)
135
+ .setCharacteristic(this.Characteristic.Name, accessory.displayName)
136
+ .setCharacteristic(this.Characteristic.Manufacturer, 'Tedee')
137
+ .setCharacteristic(this.Characteristic.Model, this.lockModel(lock))
138
+ .setCharacteristic(this.Characteristic.FirmwareRevision, lock.version ?? '0')
139
+ .setCharacteristic(this.Characteristic.SerialNumber, lock.serialNumber ?? String(lock.id));
140
+ this.devices.push(await Lock.create(this, client, accessory, lock));
141
+ }
142
+ startRefreshTimer() {
143
+ const refreshInterval = this.config.refreshInterval ?? 600000;
144
+ if (refreshInterval <= 0) {
145
+ return;
146
+ }
147
+ this.refreshTimer = setInterval(() => {
148
+ void this.refreshLocks();
149
+ }, refreshInterval);
150
+ this.refreshTimer.unref?.();
151
+ }
152
+ async refreshLocks() {
153
+ const client = this.client;
154
+ if (!client) {
155
+ return;
156
+ }
157
+ try {
158
+ await this.syncLocks(client, await client.listLocks());
159
+ }
160
+ catch (error) {
161
+ this.logger.warn(`failed to refresh Tedee locks`, error);
162
+ this.devices.forEach(device => device.setFault(true));
163
+ }
164
+ }
165
+ lockConfig(id) {
166
+ return this.config.locks?.find(lock => lock.id === id);
167
+ }
168
+ lockIgnored(id) {
169
+ return !!this.lockConfig(id)?.ignore;
170
+ }
171
+ callbackInstanceId() {
172
+ const storagePath = this.api.user.storagePath();
173
+ return createHash('sha256').update(`${PLUGIN_NAME}:${storagePath}:${this.config.host}`).digest('hex').slice(0, 16);
174
+ }
175
+ lockModel(lock) {
176
+ switch (lock.type) {
177
+ case Tedee.DeviceType.LockPro:
178
+ return 'Tedee Lock PRO';
179
+ case Tedee.DeviceType.LockGo:
180
+ return 'Tedee Lock GO';
181
+ default:
182
+ return `Tedee Lock ${lock.type}`;
183
+ }
184
+ }
185
+ }
186
+ //# sourceMappingURL=tedee-platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tedee-platform.js","sourceRoot":"","sources":["../src/tedee-platform.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ export declare namespace Tedee {
2
+ enum DeviceType {
3
+ LockPro = 2,
4
+ LockGo = 4
5
+ }
6
+ enum LockState {
7
+ Uncalibrated = 0,
8
+ Calibrating = 1,
9
+ Unlocked = 2,
10
+ SemiLocked = 3,
11
+ Unlocking = 4,
12
+ Locking = 5,
13
+ Locked = 6,
14
+ Pulled = 7,
15
+ Pulling = 8,
16
+ Unknown = 9,
17
+ Updating = 18
18
+ }
19
+ enum UnlockMode {
20
+ Normal = 0,
21
+ Force = 2,
22
+ WithoutPull = 3,
23
+ UnlockOrPull = 4
24
+ }
25
+ type Bridge = {
26
+ name: string;
27
+ currentTime: string;
28
+ serialNumber: string;
29
+ ssid: string;
30
+ isConnected: number | boolean;
31
+ version: string;
32
+ wifiVersion: string;
33
+ };
34
+ type Lock = {
35
+ id: number;
36
+ name: string;
37
+ type: DeviceType | number;
38
+ serialNumber: string;
39
+ isConnected: number | boolean;
40
+ rssi: number;
41
+ deviceRevision: number;
42
+ version: string;
43
+ state: LockState | number;
44
+ jammed: number | boolean;
45
+ doorState?: number;
46
+ batteryLevel: number;
47
+ isCharging: number | boolean;
48
+ deviceSettings: LockSettings;
49
+ };
50
+ type LockSettings = {
51
+ autoLockEnabled: number | boolean;
52
+ autoLockDelay: number;
53
+ autoLockImplicitEnabled: number | boolean;
54
+ autoLockImplicitDelay: number;
55
+ pullSpringEnabled: number | boolean;
56
+ pullSpringDuration: number;
57
+ autoPullSpringEnabled: number | boolean;
58
+ postponedLockEnabled: number | boolean;
59
+ postponedLockDelay: number;
60
+ buttonLockEnabled: number | boolean;
61
+ buttonUnlockEnabled: number | boolean;
62
+ };
63
+ type Callback = {
64
+ id: number;
65
+ url: string;
66
+ method: CallbackMethod;
67
+ headers?: Record<string, string>[];
68
+ };
69
+ type CallbackMethod = 'POST' | 'GET' | 'GET+NO_PARAMS';
70
+ type CallbackRegistration = Omit<Callback, 'id'>;
71
+ type Event = LockStatusChangedEvent | BatteryLevelChangedEvent | BatteryStartChargingEvent | BatteryStopChargingEvent | BatteryFullyChargedEvent | DeviceConnectionChangedEvent | DeviceSettingsChangedEvent;
72
+ type BaseEvent<Name extends string, Data extends EventData> = {
73
+ event: Name;
74
+ timestamp?: string;
75
+ userIdentity?: string;
76
+ data: Data;
77
+ };
78
+ type EventData = {
79
+ deviceType?: DeviceType | number;
80
+ deviceId: number;
81
+ serialNumber?: string;
82
+ eventTime?: string;
83
+ };
84
+ type LockStatusChangedEvent = BaseEvent<'lock-status-changed', EventData & {
85
+ doorState?: number;
86
+ state: LockState | number;
87
+ }>;
88
+ type BatteryLevelChangedEvent = BaseEvent<'device-battery-level-changed', EventData & {
89
+ batteryLevel: number;
90
+ }>;
91
+ type BatteryStartChargingEvent = BaseEvent<'device-battery-start-charging', EventData>;
92
+ type BatteryStopChargingEvent = BaseEvent<'device-battery-stop-charging', EventData>;
93
+ type BatteryFullyChargedEvent = BaseEvent<'device-battery-fully-charged', EventData>;
94
+ type DeviceConnectionChangedEvent = BaseEvent<'device-connection-changed', EventData & {
95
+ isConnected: number | boolean;
96
+ }>;
97
+ type DeviceSettingsChangedEvent = BaseEvent<'device-settings-changed', EventData>;
98
+ }
99
+ //# sourceMappingURL=tedee.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tedee.d.ts","sourceRoot":"","sources":["../src/tedee.ts"],"names":[],"mappings":"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"}
package/dist/tedee.js ADDED
@@ -0,0 +1,30 @@
1
+ export var Tedee;
2
+ (function (Tedee) {
3
+ let DeviceType;
4
+ (function (DeviceType) {
5
+ DeviceType[DeviceType["LockPro"] = 2] = "LockPro";
6
+ DeviceType[DeviceType["LockGo"] = 4] = "LockGo";
7
+ })(DeviceType = Tedee.DeviceType || (Tedee.DeviceType = {}));
8
+ let LockState;
9
+ (function (LockState) {
10
+ LockState[LockState["Uncalibrated"] = 0] = "Uncalibrated";
11
+ LockState[LockState["Calibrating"] = 1] = "Calibrating";
12
+ LockState[LockState["Unlocked"] = 2] = "Unlocked";
13
+ LockState[LockState["SemiLocked"] = 3] = "SemiLocked";
14
+ LockState[LockState["Unlocking"] = 4] = "Unlocking";
15
+ LockState[LockState["Locking"] = 5] = "Locking";
16
+ LockState[LockState["Locked"] = 6] = "Locked";
17
+ LockState[LockState["Pulled"] = 7] = "Pulled";
18
+ LockState[LockState["Pulling"] = 8] = "Pulling";
19
+ LockState[LockState["Unknown"] = 9] = "Unknown";
20
+ LockState[LockState["Updating"] = 18] = "Updating";
21
+ })(LockState = Tedee.LockState || (Tedee.LockState = {}));
22
+ let UnlockMode;
23
+ (function (UnlockMode) {
24
+ UnlockMode[UnlockMode["Normal"] = 0] = "Normal";
25
+ UnlockMode[UnlockMode["Force"] = 2] = "Force";
26
+ UnlockMode[UnlockMode["WithoutPull"] = 3] = "WithoutPull";
27
+ UnlockMode[UnlockMode["UnlockOrPull"] = 4] = "UnlockOrPull";
28
+ })(UnlockMode = Tedee.UnlockMode || (Tedee.UnlockMode = {}));
29
+ })(Tedee || (Tedee = {}));
30
+ //# sourceMappingURL=tedee.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tedee.js","sourceRoot":"","sources":["../src/tedee.ts"],"names":[],"mappings":"AAAA,MAAM,KAAW,KAAK,CA4HrB;AA5HD,WAAiB,KAAK;IAElB,IAAY,UAGX;IAHD,WAAY,UAAU;QAClB,iDAAW,CAAA;QACX,+CAAU,CAAA;IACd,CAAC,EAHW,UAAU,GAAV,gBAAU,KAAV,gBAAU,QAGrB;IAED,IAAY,SAYX;IAZD,WAAY,SAAS;QACjB,yDAAgB,CAAA;QAChB,uDAAe,CAAA;QACf,iDAAY,CAAA;QACZ,qDAAc,CAAA;QACd,mDAAa,CAAA;QACb,+CAAW,CAAA;QACX,6CAAU,CAAA;QACV,6CAAU,CAAA;QACV,+CAAW,CAAA;QACX,+CAAW,CAAA;QACX,kDAAa,CAAA;IACjB,CAAC,EAZW,SAAS,GAAT,eAAS,KAAT,eAAS,QAYpB;IAED,IAAY,UAKX;IALD,WAAY,UAAU;QAClB,+CAAU,CAAA;QACV,6CAAS,CAAA;QACT,yDAAe,CAAA;QACf,2DAAgB,CAAA;IACpB,CAAC,EALW,UAAU,GAAV,gBAAU,KAAV,gBAAU,QAKrB;AAkGL,CAAC,EA5HgB,KAAK,KAAL,KAAK,QA4HrB"}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@uboness/homebridge-tedee",
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "author": "uboness",
6
+ "displayName": "Homebridge Tedee",
7
+ "description": "Homebridge plugin for Tedee locks using the local Tedee Bridge API",
8
+ "license": "Apache-2.0",
9
+ "keywords": [
10
+ "homebridge-plugin",
11
+ "tedee",
12
+ "tedee-lock",
13
+ "smart-lock"
14
+ ],
15
+ "publishConfig": {
16
+ "@uboness:registry": "https://registry.npmjs.org "
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/uboness/homebridge-tedee"
21
+ },
22
+ "engines": {
23
+ "node": "^22 || ^24",
24
+ "homebridge": "^2.0.0"
25
+ },
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "default": "./dist/index.js"
30
+ }
31
+ },
32
+ "main": "dist/index.js",
33
+ "files": [
34
+ "tsconfig.json",
35
+ "LICENSE",
36
+ "README.md",
37
+ "CHANGELOG.md",
38
+ "dist",
39
+ "config.schema.json"
40
+ ],
41
+ "scripts": {
42
+ "clean": "rimraf ./dist",
43
+ "build": "pnpm run clean && tsc",
44
+ "prepublishOnly": "pnpm run build",
45
+ "release:bump": "pnpm run build && commit-and-tag-version",
46
+ "release:bump-minor": "commit-and-tag-version --release-as minor",
47
+ "release:bump-major": "commit-and-tag-version --release-as major",
48
+ "release:postbump": "pnpm run release:push && pnpm run release:publish",
49
+ "release:push": "git push --follow-tags",
50
+ "release:publish": "npm publish --access public",
51
+ "release": "pnpm run release:bump && pnpm run release:postbump",
52
+ "release-minor": "pnpm run release:bump-minor && pnpm run release:push && pnpm run release:publish",
53
+ "release-major": "pnpm run release:bump-major && pnpm run release:push && pnpm run release:publish"
54
+ },
55
+ "dependencies": {
56
+ "undici": "^8.3.0"
57
+ },
58
+ "devDependencies": {
59
+ "@types/node": "^25.9.1",
60
+ "commit-and-tag-version": "^12.7.3",
61
+ "homebridge": "^2.0.2",
62
+ "homebridge-config-ui-x": "^5.24.0",
63
+ "rimraf": "^6.1.3",
64
+ "typescript": "^6.0.3"
65
+ }
66
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "esnext",
4
+ "module": "esnext",
5
+ "lib": [
6
+ "ES2022"
7
+ ],
8
+ "declaration": true,
9
+ "declarationMap": true,
10
+ "sourceMap": true,
11
+ "outDir": "./dist",
12
+ "rootDir": "./src",
13
+ "strict": true,
14
+ "esModuleInterop": true,
15
+ "noImplicitAny": false,
16
+ "skipLibCheck": true,
17
+ "resolveJsonModule": true,
18
+ "allowImportingTsExtensions": true,
19
+ "rewriteRelativeImportExtensions": true,
20
+ "types": [
21
+ "node"
22
+ ]
23
+ },
24
+ "include": [
25
+ "src"
26
+ ],
27
+ "exclude": [
28
+ "node_modules",
29
+ "**/*.spec.ts"
30
+ ]
31
+ }