homebridge-orro 1.0.19 → 1.0.21

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.
@@ -0,0 +1,111 @@
1
+ import { Logger } from 'homebridge';
2
+ export declare type OrroCommand = {
3
+ command: 'on' | 'off';
4
+ } | {
5
+ command: 'dimmer_set';
6
+ value: number;
7
+ };
8
+ export interface LightingChange {
9
+ onOff: boolean;
10
+ dimmerLevel: number;
11
+ /** False when the switch changed on its own, for example adapting to its surroundings. */
12
+ wasUserInitiated?: boolean;
13
+ }
14
+ export interface OrroTiming {
15
+ handshakeTimeoutMs: number;
16
+ heartbeatIntervalMs: number;
17
+ /** With a switch known to answer pings, silence this long means the socket is dead. */
18
+ heartbeatStaleMs: number;
19
+ /** A heartbeat count with no pong after which we stop expecting pongs and say so. */
20
+ pongGraceBeats: number;
21
+ reconnectMinMs: number;
22
+ reconnectMaxMs: number;
23
+ /** Retry delay ceiling while a command is waiting on the connection. */
24
+ commandReconnectMs: number;
25
+ /** A connection that stayed up this long resets the retry backoff. */
26
+ stableAfterMs: number;
27
+ confirmationTimeoutMs: number;
28
+ /** How long to keep waiting for the exact level after a non-matching event arrives. */
29
+ confirmationSettleMs: number;
30
+ /** Total time a command may take. Homebridge gives up on a handler at 10 seconds. */
31
+ commandDeadlineMs: number;
32
+ }
33
+ export declare const DEFAULT_TIMING: OrroTiming;
34
+ export interface OrroConnectionOptions {
35
+ name: string;
36
+ ipAddress: string;
37
+ port?: number;
38
+ homeId: string;
39
+ switchId: string;
40
+ accessToken: string;
41
+ log: Pick<Logger, 'debug' | 'info' | 'warn' | 'error'>;
42
+ onLightingChange: (change: LightingChange) => void;
43
+ timing?: Partial<OrroTiming>;
44
+ }
45
+ export declare class OrroCommandError extends Error {
46
+ }
47
+ /**
48
+ * One long-lived WebSocket to one switch, per the Orro LAN WebSocket API.
49
+ *
50
+ * The API has no command acknowledgement and does not define a keepalive, so delivery
51
+ * is verified with what it does provide: every state change produces an
52
+ * OrroLightingChange event. A command that should change the light and produces no
53
+ * event is treated as lost, and is resent once on a fresh socket.
54
+ */
55
+ export declare class OrroConnection {
56
+ private readonly options;
57
+ private readonly timing;
58
+ private readonly clientId;
59
+ private socket?;
60
+ private stopped;
61
+ private reconnectTimer?;
62
+ private heartbeatTimer?;
63
+ private reconnectAttempts;
64
+ private reconnectImmediately;
65
+ private openedAt;
66
+ private lastActivityAt;
67
+ private beatsWithoutPong;
68
+ private readonly openWaiters;
69
+ private pending?;
70
+ private queue;
71
+ private pongSeen;
72
+ private confirmationSeen;
73
+ constructor(options: OrroConnectionOptions);
74
+ start(): void;
75
+ stop(): void;
76
+ /**
77
+ * Sends a command, one at a time per switch so that a resend cannot reorder commands.
78
+ * Resolves once delivered. Rejects with OrroCommandError if it could not be delivered.
79
+ *
80
+ * @param expectChange whether the command should alter the light. Commands that
81
+ * would not change anything produce no event, so they cannot be confirmed.
82
+ */
83
+ execute(command: OrroCommand, expectChange: boolean): Promise<void>;
84
+ private deliver;
85
+ private write;
86
+ private expectConfirmation;
87
+ /**
88
+ * A late event from an earlier command must not confirm this one, so a non-matching
89
+ * event only starts a short wait for the exact value. If that value never comes
90
+ * (mid-fade levels, or a switch that rounds), the event still proves the socket works.
91
+ * The switch's own adaptive changes say nothing about a command, so they are ignored here.
92
+ */
93
+ private observeForConfirmation;
94
+ private settlePending;
95
+ private waitUntilOpen;
96
+ private settleOpenWaiters;
97
+ private isOpen;
98
+ private connect;
99
+ private handleOpen;
100
+ private heartbeat;
101
+ private handlePong;
102
+ private handleMessage;
103
+ private handleErrorFrame;
104
+ private handleClose;
105
+ private scheduleReconnect;
106
+ private reconnectNow;
107
+ private clearReconnectTimer;
108
+ private clearHeartbeat;
109
+ private log;
110
+ }
111
+ //# sourceMappingURL=orroConnection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orroConnection.d.ts","sourceRoot":"","sources":["../src/orroConnection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,381 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.OrroConnection = exports.OrroCommandError = exports.DEFAULT_TIMING = void 0;
7
+ const crypto_1 = require("crypto");
8
+ const ws_1 = __importDefault(require("ws"));
9
+ exports.DEFAULT_TIMING = {
10
+ handshakeTimeoutMs: 5000,
11
+ heartbeatIntervalMs: 15000,
12
+ heartbeatStaleMs: 40000,
13
+ pongGraceBeats: 3,
14
+ reconnectMinMs: 1000,
15
+ reconnectMaxMs: 30000,
16
+ commandReconnectMs: 500,
17
+ stableAfterMs: 60000,
18
+ confirmationTimeoutMs: 3000,
19
+ confirmationSettleMs: 300,
20
+ commandDeadlineMs: 8000,
21
+ };
22
+ class OrroCommandError extends Error {
23
+ }
24
+ exports.OrroCommandError = OrroCommandError;
25
+ function matcherFor(command) {
26
+ switch (command.command) {
27
+ case 'on':
28
+ return change => change.onOff;
29
+ case 'off':
30
+ return change => !change.onOff;
31
+ case 'dimmer_set':
32
+ return change => change.dimmerLevel === command.value;
33
+ }
34
+ }
35
+ const MAX_SEND_ATTEMPTS = 2;
36
+ /**
37
+ * One long-lived WebSocket to one switch, per the Orro LAN WebSocket API.
38
+ *
39
+ * The API has no command acknowledgement and does not define a keepalive, so delivery
40
+ * is verified with what it does provide: every state change produces an
41
+ * OrroLightingChange event. A command that should change the light and produces no
42
+ * event is treated as lost, and is resent once on a fresh socket.
43
+ */
44
+ class OrroConnection {
45
+ constructor(options) {
46
+ this.options = options;
47
+ // the docs ask for a unique id per client; Error frames echo it back
48
+ this.clientId = `homebridge-orro-${crypto_1.randomBytes(4).toString('hex')}`;
49
+ this.stopped = false;
50
+ this.reconnectAttempts = 0;
51
+ this.reconnectImmediately = false;
52
+ this.openedAt = 0;
53
+ this.lastActivityAt = 0;
54
+ this.beatsWithoutPong = 0;
55
+ this.openWaiters = new Set();
56
+ this.queue = Promise.resolve();
57
+ // Neither of these is documented behaviour, so both are learned from the switch
58
+ // rather than assumed. Until seen, their absence is never treated as a failure.
59
+ this.pongSeen = false;
60
+ this.confirmationSeen = false;
61
+ this.timing = { ...exports.DEFAULT_TIMING, ...options.timing };
62
+ }
63
+ start() {
64
+ this.stopped = false;
65
+ this.connect();
66
+ }
67
+ stop() {
68
+ this.stopped = true;
69
+ this.clearReconnectTimer();
70
+ this.clearHeartbeat();
71
+ this.settlePending({ kind: 'closed' });
72
+ this.settleOpenWaiters(false);
73
+ if (this.socket) {
74
+ this.socket.terminate();
75
+ this.socket = undefined;
76
+ }
77
+ }
78
+ /**
79
+ * Sends a command, one at a time per switch so that a resend cannot reorder commands.
80
+ * Resolves once delivered. Rejects with OrroCommandError if it could not be delivered.
81
+ *
82
+ * @param expectChange whether the command should alter the light. Commands that
83
+ * would not change anything produce no event, so they cannot be confirmed.
84
+ */
85
+ execute(command, expectChange) {
86
+ const result = this.queue.then(() => this.deliver(command, expectChange));
87
+ this.queue = result.catch(() => undefined);
88
+ return result;
89
+ }
90
+ async deliver(command, expectChange) {
91
+ const { name } = this.options;
92
+ const deadline = Date.now() + this.timing.commandDeadlineMs;
93
+ let failure = 'no connection';
94
+ let wentUnconfirmed = false;
95
+ for (let attempt = 1; attempt <= MAX_SEND_ATTEMPTS; attempt++) {
96
+ if (!await this.waitUntilOpen(deadline - Date.now())) {
97
+ failure = 'no connection';
98
+ wentUnconfirmed = false;
99
+ break;
100
+ }
101
+ const timestamp = Date.now();
102
+ const confirmation = expectChange
103
+ ? this.expectConfirmation(timestamp, Math.min(this.timing.confirmationTimeoutMs, deadline - timestamp), matcherFor(command))
104
+ : undefined;
105
+ try {
106
+ await this.write(command, timestamp);
107
+ }
108
+ catch (e) {
109
+ this.settlePending({ kind: 'closed' });
110
+ failure = `send failed: ${e.message}`;
111
+ wentUnconfirmed = false;
112
+ this.log('warn', `${name}: ${failure} (attempt ${attempt})`);
113
+ this.reconnectNow();
114
+ continue;
115
+ }
116
+ if (!confirmation) {
117
+ return;
118
+ }
119
+ const outcome = await confirmation;
120
+ if (outcome.kind === 'confirmed') {
121
+ this.confirmationSeen = true;
122
+ return;
123
+ }
124
+ if (outcome.kind === 'rejected') {
125
+ throw new OrroCommandError(`${name} rejected "${command.command}": ${outcome.error}`);
126
+ }
127
+ if (outcome.kind === 'unconfirmed') {
128
+ failure = 'no confirmation from switch';
129
+ wentUnconfirmed = true;
130
+ this.log('warn', `${name}: no confirmation for "${command.command}" (attempt ${attempt}), reconnecting`);
131
+ this.reconnectNow();
132
+ }
133
+ else {
134
+ failure = 'connection closed before confirmation';
135
+ wentUnconfirmed = false;
136
+ }
137
+ }
138
+ // Guards against a firmware that doesn't echo events to the sending client,
139
+ // where treating silence as failure would break every command.
140
+ if (wentUnconfirmed && !this.confirmationSeen) {
141
+ this.log('warn', `${name}: "${command.command}" was sent but this switch has not confirmed any command yet`);
142
+ return;
143
+ }
144
+ throw new OrroCommandError(`${name}: "${command.command}" not delivered (${failure})`);
145
+ }
146
+ write(command, timestamp) {
147
+ const payload = JSON.stringify({
148
+ targetId: this.options.switchId,
149
+ clientId: this.clientId,
150
+ type: 'RemoteCommand',
151
+ timestamp,
152
+ data: command,
153
+ });
154
+ return new Promise((resolve, reject) => {
155
+ if (!this.socket) {
156
+ reject(new Error('socket gone'));
157
+ return;
158
+ }
159
+ // ws drops sends on a closing socket silently unless a callback is given
160
+ this.socket.send(payload, (error) => error ? reject(error) : resolve());
161
+ });
162
+ }
163
+ expectConfirmation(timestamp, timeoutMs, matches) {
164
+ return new Promise(resolve => {
165
+ const timer = setTimeout(() => this.settlePending({ kind: 'unconfirmed' }), timeoutMs);
166
+ this.pending = { timestamp, timer, settle: resolve, matches, settling: false };
167
+ });
168
+ }
169
+ /**
170
+ * A late event from an earlier command must not confirm this one, so a non-matching
171
+ * event only starts a short wait for the exact value. If that value never comes
172
+ * (mid-fade levels, or a switch that rounds), the event still proves the socket works.
173
+ * The switch's own adaptive changes say nothing about a command, so they are ignored here.
174
+ */
175
+ observeForConfirmation(change) {
176
+ const pending = this.pending;
177
+ if (!pending) {
178
+ return;
179
+ }
180
+ if (pending.matches(change)) {
181
+ this.settlePending({ kind: 'confirmed' });
182
+ }
183
+ else if (!pending.settling && change.wasUserInitiated !== false) {
184
+ pending.settling = true;
185
+ clearTimeout(pending.timer);
186
+ pending.timer = setTimeout(() => this.settlePending({ kind: 'confirmed' }), this.timing.confirmationSettleMs);
187
+ }
188
+ }
189
+ settlePending(outcome) {
190
+ if (this.pending) {
191
+ const { timer, settle } = this.pending;
192
+ clearTimeout(timer);
193
+ this.pending = undefined;
194
+ settle(outcome);
195
+ }
196
+ }
197
+ waitUntilOpen(timeoutMs) {
198
+ if (this.isOpen()) {
199
+ return Promise.resolve(true);
200
+ }
201
+ if (this.stopped || timeoutMs <= 0) {
202
+ return Promise.resolve(false);
203
+ }
204
+ // someone is waiting, so don't sit out the rest of a long backoff
205
+ if (this.reconnectTimer) {
206
+ this.clearReconnectTimer();
207
+ this.connect();
208
+ }
209
+ return new Promise(resolve => {
210
+ const waiter = {
211
+ timer: setTimeout(() => {
212
+ this.openWaiters.delete(waiter);
213
+ resolve(false);
214
+ }, timeoutMs),
215
+ settle: resolve,
216
+ };
217
+ this.openWaiters.add(waiter);
218
+ });
219
+ }
220
+ settleOpenWaiters(open) {
221
+ for (const waiter of this.openWaiters) {
222
+ clearTimeout(waiter.timer);
223
+ waiter.settle(open);
224
+ }
225
+ this.openWaiters.clear();
226
+ }
227
+ isOpen() {
228
+ return this.socket !== undefined && this.socket.readyState === ws_1.default.OPEN;
229
+ }
230
+ connect() {
231
+ if (this.stopped || this.socket) {
232
+ return;
233
+ }
234
+ const { ipAddress, port = 8080, homeId, accessToken } = this.options;
235
+ const socket = new ws_1.default(`ws://${ipAddress}:${port}/edison/${homeId}`, {
236
+ headers: { 'offline-access-token': accessToken },
237
+ handshakeTimeout: this.timing.handshakeTimeoutMs,
238
+ });
239
+ this.socket = socket;
240
+ socket.on('open', () => this.handleOpen());
241
+ socket.on('message', (data) => this.handleMessage(data));
242
+ socket.on('pong', () => this.handlePong());
243
+ socket.on('close', (code, reason) => this.handleClose(socket, code, reason));
244
+ socket.on('error', (error) => {
245
+ // a retry loop against an offline switch shouldn't flood the log
246
+ this.log(this.reconnectAttempts === 0 ? 'warn' : 'debug', `${this.options.name}: ${error.message}`);
247
+ });
248
+ }
249
+ handleOpen() {
250
+ this.openedAt = Date.now();
251
+ this.lastActivityAt = this.openedAt;
252
+ this.beatsWithoutPong = 0;
253
+ this.log('info', `Connected to ${this.options.name}`);
254
+ this.settleOpenWaiters(true);
255
+ this.clearHeartbeat();
256
+ this.heartbeatTimer = setInterval(() => this.heartbeat(), this.timing.heartbeatIntervalMs);
257
+ }
258
+ heartbeat() {
259
+ if (!this.socket || !this.isOpen()) {
260
+ return;
261
+ }
262
+ const silentFor = Date.now() - this.lastActivityAt;
263
+ if (this.pongSeen && silentFor >= this.timing.heartbeatStaleMs) {
264
+ this.log('warn', `${this.options.name}: no response for ${Math.round(silentFor / 1000)}s, reconnecting`);
265
+ this.reconnectNow();
266
+ return;
267
+ }
268
+ if (!this.pongSeen && ++this.beatsWithoutPong === this.timing.pongGraceBeats) {
269
+ this.log('info', `${this.options.name} does not answer pings, relying on command confirmation`);
270
+ }
271
+ // Writing also surfaces a switch that rebooted: its TCP reset closes this socket.
272
+ this.socket.ping(undefined, undefined, () => undefined);
273
+ }
274
+ handlePong() {
275
+ this.lastActivityAt = Date.now();
276
+ if (!this.pongSeen) {
277
+ this.pongSeen = true;
278
+ this.log('debug', `${this.options.name} answers pings`);
279
+ }
280
+ }
281
+ handleMessage(raw) {
282
+ var _a;
283
+ this.lastActivityAt = Date.now();
284
+ let message;
285
+ try {
286
+ message = JSON.parse(raw.toString());
287
+ }
288
+ catch (e) {
289
+ this.log('debug', `${this.options.name}: unparseable message: ${e.message}`);
290
+ return;
291
+ }
292
+ const { type, targetId, clientId, data } = message || {};
293
+ if (type === 'Error') {
294
+ this.handleErrorFrame(clientId, data);
295
+ return;
296
+ }
297
+ // Identified by shape rather than `type`, so a firmware that names the event
298
+ // differently from the 2021 docs can't make every command look unconfirmed.
299
+ if (!data || typeof data.onOff !== 'boolean' || typeof data.dimmerLevel !== 'number') {
300
+ return;
301
+ }
302
+ // Events are home-wide, and targetId may name a group or room. The docs
303
+ // guarantee switchTargetId is the switch that actually changed.
304
+ if (((_a = data.switchTargetId) !== null && _a !== void 0 ? _a : targetId) !== this.options.switchId) {
305
+ return;
306
+ }
307
+ const change = { onOff: data.onOff, dimmerLevel: data.dimmerLevel, wasUserInitiated: data.wasUserInitiated };
308
+ this.observeForConfirmation(change);
309
+ this.options.onLightingChange(change);
310
+ }
311
+ handleErrorFrame(clientId, data) {
312
+ var _a;
313
+ if (clientId && clientId !== this.clientId) {
314
+ return;
315
+ }
316
+ const error = (_a = data === null || data === void 0 ? void 0 : data.error) !== null && _a !== void 0 ? _a : 'unknown error';
317
+ this.log('error', `${this.options.name} reported an error: ${error}`);
318
+ if (this.pending && ((data === null || data === void 0 ? void 0 : data.messageTimestamp) === undefined || data.messageTimestamp === this.pending.timestamp)) {
319
+ this.settlePending({ kind: 'rejected', error });
320
+ }
321
+ }
322
+ handleClose(socket, code, reason) {
323
+ if (socket !== this.socket) {
324
+ return;
325
+ }
326
+ this.socket = undefined;
327
+ this.clearHeartbeat();
328
+ this.settlePending({ kind: 'closed' });
329
+ if (this.stopped) {
330
+ return;
331
+ }
332
+ if (this.openedAt && Date.now() - this.openedAt >= this.timing.stableAfterMs) {
333
+ this.reconnectAttempts = 0;
334
+ }
335
+ const detail = reason && reason.length ? `, ${reason.toString()}` : '';
336
+ this.log(this.reconnectAttempts === 0 ? 'warn' : 'debug', `Disconnected from ${this.options.name} (code ${code}${detail})`);
337
+ this.openedAt = 0;
338
+ this.scheduleReconnect();
339
+ }
340
+ scheduleReconnect() {
341
+ const { reconnectMinMs, reconnectMaxMs, commandReconnectMs } = this.timing;
342
+ const backoff = Math.min(reconnectMaxMs, reconnectMinMs * 2 ** this.reconnectAttempts);
343
+ // jitter keeps every switch from retrying in lockstep after a network blip
344
+ let delay = backoff / 2 + Math.random() * (backoff / 2);
345
+ if (this.openWaiters.size > 0) {
346
+ delay = Math.min(delay, commandReconnectMs);
347
+ }
348
+ if (this.reconnectImmediately) {
349
+ delay = 0;
350
+ this.reconnectImmediately = false;
351
+ }
352
+ this.reconnectAttempts++;
353
+ this.reconnectTimer = setTimeout(() => {
354
+ this.reconnectTimer = undefined;
355
+ this.connect();
356
+ }, delay);
357
+ }
358
+ reconnectNow() {
359
+ if (this.socket) {
360
+ this.reconnectImmediately = true;
361
+ this.socket.terminate();
362
+ }
363
+ }
364
+ clearReconnectTimer() {
365
+ if (this.reconnectTimer) {
366
+ clearTimeout(this.reconnectTimer);
367
+ this.reconnectTimer = undefined;
368
+ }
369
+ }
370
+ clearHeartbeat() {
371
+ if (this.heartbeatTimer) {
372
+ clearInterval(this.heartbeatTimer);
373
+ this.heartbeatTimer = undefined;
374
+ }
375
+ }
376
+ log(level, message) {
377
+ this.options.log[level](message);
378
+ }
379
+ }
380
+ exports.OrroConnection = OrroConnection;
381
+ //# sourceMappingURL=orroConnection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orroConnection.js","sourceRoot":"","sources":["../src/orroConnection.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAK5H;;;;EAIE;AACF,qBAAa,YAAa,YAAW,qBAAqB;aAQlC,GAAG,EAAE,MAAM;aACX,MAAM,EAAE,cAAc;aACtB,GAAG,EAAE,GAAG;IAT5B,SAAgB,OAAO,EAAE,OAAO,OAAO,CAAwB;IAC/D,SAAgB,cAAc,EAAE,OAAO,cAAc,CAA+B;IAGpF,SAAgB,WAAW,EAAE,iBAAiB,EAAE,CAAM;gBAGlC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,GAAG;IAe5B;;;MAGE;IACF,kBAAkB,CAAC,SAAS,EAAE,iBAAiB;IAO/C;;;;MAIE;IACF,eAAe;CAiDlB"}
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAK5H;;;;EAIE;AACF,qBAAa,YAAa,YAAW,qBAAqB;aAQlC,GAAG,EAAE,MAAM;aACX,MAAM,EAAE,cAAc;aACtB,GAAG,EAAE,GAAG;IAT5B,SAAgB,OAAO,EAAE,OAAO,OAAO,CAAwB;IAC/D,SAAgB,cAAc,EAAE,OAAO,cAAc,CAA+B;IAGpF,SAAgB,WAAW,EAAE,iBAAiB,EAAE,CAAM;gBAGlC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,GAAG;IAe5B;;;MAGE;IACF,kBAAkB,CAAC,SAAS,EAAE,iBAAiB;IAO/C;;;;MAIE;IACF,eAAe;CAsDlB"}
package/dist/platform.js CHANGED
@@ -43,6 +43,10 @@ class OrroPlatform {
43
43
  * must not be registered again to prevent "duplicate UUID" errors.
44
44
  */
45
45
  discoverDevices() {
46
+ if (!Array.isArray(this.config.switches) || !this.config.homeID || !this.config.accessToken) {
47
+ this.log.error('Config needs homeID, accessToken and a switches list. Not loading any switches.');
48
+ return;
49
+ }
46
50
  // loop over the discovered devices and register each one if it has not already been registered
47
51
  for (const device of this.config.switches) {
48
52
  // generate a unique id for the accessory this should be generated from
@@ -55,9 +59,9 @@ class OrroPlatform {
55
59
  if (existingAccessory) {
56
60
  // the accessory already exists
57
61
  this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName);
58
- // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
59
- // existingAccessory.context.device = device;
60
- // this.api.updatePlatformAccessories([existingAccessory]);
62
+ // always use the current config, otherwise an edited IP address is ignored
63
+ existingAccessory.context.device = device;
64
+ this.api.updatePlatformAccessories([existingAccessory]);
61
65
  // create the accessory handler for the restored accessory
62
66
  // this is imported from `platformAccessory.ts`
63
67
  new platformAccessory_1.Switch(this, existingAccessory);
@@ -1 +1 @@
1
- {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":";;;AAEA,yCAAwD;AACxD,2DAA6C;AAE7C;;;;EAIE;AACF,MAAa,YAAY;IAOrB,YACoB,GAAW,EACX,MAAsB,EACtB,GAAQ;QAFR,QAAG,GAAH,GAAG,CAAQ;QACX,WAAM,GAAN,MAAM,CAAgB;QACtB,QAAG,GAAH,GAAG,CAAK;QATZ,YAAO,GAAmB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;QAC/C,mBAAc,GAA0B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;QAEpF,oDAAoD;QACpC,gBAAW,GAAwB,EAAE,CAAC;QAOlD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iCAAiC,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAExE,8FAA8F;QAC9F,4FAA4F;QAC5F,2FAA2F;QAC3F,yCAAyC;QACzC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;YACnC,GAAG,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAClD,oEAAoE;YACpE,IAAI,CAAC,eAAe,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;;MAGE;IACF,kBAAkB,CAAC,SAA4B;QAC3C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,+BAA+B,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;QAEtE,wGAAwG;QACxG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAED;;;;MAIE;IACF,eAAe;QAEX,+FAA+F;QAC/F,KAAI,MAAM,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;YAEtC,uEAAuE;YACvE,0EAA0E;YAC1E,wBAAwB;YACxB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAE7D,uFAAuF;YACvF,wEAAwE;YACxE,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YACtF,IAAG,iBAAiB,EAAE;gBAClB,+BAA+B;gBAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,0CAA0C,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;gBAEzF,wGAAwG;gBACxG,6CAA6C;gBAC7C,2DAA2D;gBAE3D,0DAA0D;gBAC1D,+CAA+C;gBAC/C,IAAI,0BAAM,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;gBAEpC,4GAA4G;gBAC5G,qDAAqD;gBACrD,2FAA2F;gBAC3F,2FAA2F;aAC9F;iBAAM;gBACH,4DAA4D;gBAC5D,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;gBAEpD,yBAAyB;gBACzB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAEpE,+DAA+D;gBAC/D,wFAAwF;gBACxF,SAAS,CAAC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;gBAElC,8DAA8D;gBAC9D,+CAA+C;gBAC/C,IAAI,0BAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBAE5B,sCAAsC;gBACtC,IAAI,CAAC,GAAG,CAAC,2BAA2B,CAAC,sBAAW,EAAE,wBAAa,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;aACjF;SACJ;IACL,CAAC;CACJ;AA1FD,oCA0FC"}
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
@@ -1,45 +1,30 @@
1
1
  import { CharacteristicValue, PlatformAccessory } from 'homebridge';
2
2
  import { OrroPlatform } from './platform';
3
- /**
4
- * Platform Accessory
5
- * An instance of this class is created for each accessory your platform registers
6
- * Each accessory may expose multiple services of different service types.
7
- */
8
3
  export declare class Switch {
9
4
  private readonly platform;
10
5
  private readonly accessory;
11
- private service;
12
- /**
13
- * These are just used to create a working example
14
- * You should implement your own code to track the state of your accessory
15
- */
16
- private state;
17
- private connection;
6
+ private readonly service;
7
+ private readonly connection;
8
+ private readonly state;
9
+ private pendingBrightness;
10
+ private brightnessTimer?;
11
+ private brightnessWaiters;
12
+ private brightnessSending;
13
+ private holdTimer?;
14
+ private heldChange?;
18
15
  constructor(platform: OrroPlatform, accessory: PlatformAccessory);
19
- connect: () => Promise<void>;
20
- /**
21
- * Handle "SET" requests from HomeKit
22
- * These are sent when the user changes the state of an accessory, for example, turning on a Light bulb.
23
- */
16
+ private handleLightingChange;
24
17
  setOn(value: CharacteristicValue): Promise<void>;
25
- /**
26
- * Handle the "GET" requests from HomeKit
27
- * These are sent when HomeKit wants to know the current state of the accessory, for example, checking if a Light bulb is on.
28
- *
29
- * GET requests should return as fast as possbile. A long delay here will result in
30
- * HomeKit being unresponsive and a bad user experience in general.
31
- *
32
- * If your device takes time to respond you should update the status of your device
33
- * asynchronously instead using the `updateCharacteristic` method instead.
34
-
35
- * @example
36
- * this.service.updateCharacteristic(this.platform.Characteristic.On, true)
37
- */
38
- getOn(): Promise<CharacteristicValue>;
39
- /**
40
- * Handle "SET" requests from HomeKit
41
- * These are sent when the user changes the state of an accessory, for example, changing the Brightness
42
- */
43
18
  setBrightness(value: CharacteristicValue): Promise<void>;
19
+ /**
20
+ * Only one brightness command is ever outstanding. Values that arrive meanwhile
21
+ * replace each other, so the switch goes straight to the newest one.
22
+ */
23
+ private flushBrightness;
24
+ /** Holds back switch reports, then applies the most recent one so the real level wins. */
25
+ private holdSwitchReports;
26
+ /** Throws a HomeKit error on failure, so a lost command is never reported as a success. */
27
+ private send;
28
+ private saveState;
44
29
  }
45
30
  //# sourceMappingURL=platformAccessory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"platformAccessory.d.ts","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAW,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1C;;;;EAIE;AACF,qBAAa,MAAM;IAeX,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAf9B,OAAO,CAAC,OAAO,CAAU;IAEzB;;;MAGE;IACF,OAAO,CAAC,KAAK,CAGX;IAEF,OAAO,CAAC,UAAU,CAAY;gBAGT,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,iBAAiB;IAgCjD,OAAO,sBA+DN;IAED;;;MAGE;IACI,KAAK,CAAC,KAAK,EAAE,mBAAmB;IA6BtC;;;;;;;;;;;;MAYE;IACI,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAM3C;;;MAGE;IACI,aAAa,CAAC,KAAK,EAAE,mBAAmB;CA4CjD"}
1
+ {"version":3,"file":"platformAccessory.d.ts","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAW,MAAM,YAAY,CAAC;AAE7E,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAc1C,qBAAa,MAAM;IAaX,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAb9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;IAC5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsC;IAE5D,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,eAAe,CAAC,CAAiB;IACzC,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,SAAS,CAAC,CAAiB;IACnC,OAAO,CAAC,UAAU,CAAC,CAAiB;gBAGf,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,iBAAiB;IA2CjD,OAAO,CAAC,oBAAoB;IA2BtB,KAAK,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOtD,aAAa,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAaxD;;;OAGG;YACW,eAAe;IA0B7B,0FAA0F;IAC1F,OAAO,CAAC,iBAAiB;IAezB,2FAA2F;YAC7E,IAAI;IAWlB,OAAO,CAAC,SAAS;CAGpB"}
@@ -1,199 +1,147 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.Switch = void 0;
7
- const ws_1 = __importDefault(require("ws"));
8
- /**
9
- * Platform Accessory
10
- * An instance of this class is created for each accessory your platform registers
11
- * Each accessory may expose multiple services of different service types.
12
- */
4
+ const orroConnection_1 = require("./orroConnection");
5
+ // HomeKit sends a stream of values while a slider is dragged; only the last one matters
6
+ const BRIGHTNESS_DEBOUNCE_MS = 120;
7
+ // How long after a brightness request the switch's own reports are held back, since
8
+ // events from earlier values and fades keep arriving after the newest value is sent
9
+ const BRIGHTNESS_HOLD_MS = 2000;
13
10
  class Switch {
14
11
  constructor(platform, accessory) {
15
12
  this.platform = platform;
16
13
  this.accessory = accessory;
17
- /**
18
- * These are just used to create a working example
19
- * You should implement your own code to track the state of your accessory
20
- */
14
+ this.pendingBrightness = 0;
15
+ this.brightnessWaiters = [];
16
+ this.brightnessSending = false;
17
+ const { device, lastState } = accessory.context;
18
+ // The API has no way to read a switch's light state, so the last known
19
+ // state is kept across restarts instead of reporting everything as off.
21
20
  this.state = {
22
- On: false,
23
- Brightness: 0
21
+ On: (lastState === null || lastState === void 0 ? void 0 : lastState.On) === true,
22
+ Brightness: typeof (lastState === null || lastState === void 0 ? void 0 : lastState.Brightness) === 'number' ? lastState.Brightness : 0,
24
23
  };
25
- this.connect = async () => {
26
- const url = `ws://${this.accessory.context.device.ipAddress}:8080/edison/${this.platform.config.homeID}`;
27
- this.platform.log.info('Connecting to:', url);
28
- const connection = new ws_1.default(url, { headers: { 'offline-access-token': this.platform.config.accessToken } });
29
- connection.on('open', () => {
30
- this.platform.log.info(`Connected to ${this.accessory.context.device.name}`);
31
- // listen for system events
32
- this.connection.on('message', response => {
33
- try {
34
- // prevent moving forward if event is not for this switch
35
- const { data, targetId } = JSON.parse(response.toString());
36
- if (targetId !== this.accessory.context.device.switchID) {
37
- return;
38
- }
39
- // update on/off state if changed externally
40
- const { dimmerLevel, onOff } = data || {};
41
- if (typeof (onOff) === 'boolean' && onOff !== this.state.On) {
42
- this.platform.log.info(`Updated "on" to ${onOff ? 'true' : 'false'} from system event`);
43
- this.state.On = onOff;
44
- this.service.updateCharacteristic(this.platform.Characteristic.On, onOff);
45
- }
46
- // turn light off if dimmer level is zero
47
- if (dimmerLevel === 0 && this.state.On !== false) {
48
- this.platform.log.info(`Updated "on" to false to match zero dimmer level from system event`);
49
- this.state.On = false;
50
- this.service.updateCharacteristic(this.platform.Characteristic.On, false);
51
- }
52
- // prevent moving forward if a manuanl hange triggered this event
53
- if (this.accessory.context.device.action) {
54
- const { type, value } = this.accessory.context.device.action;
55
- if (type === 'brightness' && value === dimmerLevel) {
56
- this.accessory.context.device.action = null;
57
- this.platform.log.info(`Brightness system event blocked by manual value change`);
58
- return;
59
- }
60
- }
61
- // update dimmer level if changed externally
62
- if (dimmerLevel >= 0 && dimmerLevel !== this.state.Brightness) {
63
- this.platform.log.info(`Updated "brightness" to ${dimmerLevel} from system event`);
64
- this.state.Brightness = dimmerLevel;
65
- this.service.updateCharacteristic(this.platform.Characteristic.Brightness, dimmerLevel);
66
- }
67
- }
68
- catch (e) {
69
- this.platform.log.error('Websocket api response error:', e.message);
70
- }
71
- });
72
- });
73
- connection.on('close', () => {
74
- this.platform.log.error(`Disconnected from ${this.accessory.context.device.name}, attempting reconnection in 30 seconds...`);
75
- setTimeout(this.connect, 30000);
76
- });
77
- connection.on('error', error => {
78
- this.platform.log.error(`${this.accessory.context.device.name} error: ${error.message}`);
79
- });
80
- this.connection = connection;
81
- };
82
- // set accessory information
83
24
  this.accessory.getService(this.platform.Service.AccessoryInformation)
84
25
  .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Orro')
85
26
  .setCharacteristic(this.platform.Characteristic.Model, 'Switch')
86
- .setCharacteristic(this.platform.Characteristic.SerialNumber, accessory.context.device.serialNumber);
87
- // get the LightBulb service if it exists, otherwise create a new LightBulb service
88
- // you can create multiple services for each accessory
89
- this.service = this.accessory.getService(this.platform.Service.Lightbulb) || this.accessory.addService(this.platform.Service.Lightbulb);
90
- // set the service name, this is what is displayed as the default name on the Home app
91
- // in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method.
92
- this.service.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name);
93
- // each service must implement at-minimum the "required characteristics" for the given service type
94
- // see https://developers.homebridge.io/#/service/Lightbulb
95
- // register handlers for the On/Off Characteristic
27
+ .setCharacteristic(this.platform.Characteristic.SerialNumber, device.serialNumber);
28
+ this.service = this.accessory.getService(this.platform.Service.Lightbulb)
29
+ || this.accessory.addService(this.platform.Service.Lightbulb);
30
+ this.service.setCharacteristic(this.platform.Characteristic.Name, device.name);
96
31
  this.service.getCharacteristic(this.platform.Characteristic.On)
97
- .onSet(this.setOn.bind(this)) // SET - bind to the `setOn` method below
98
- .onGet(this.getOn.bind(this)); // GET - bind to the `getOn` method below
99
- // register handlers for the Brightness Characteristic
32
+ .onSet(this.setOn.bind(this))
33
+ .onGet(() => this.state.On);
100
34
  this.service.getCharacteristic(this.platform.Characteristic.Brightness)
101
- .onSet(this.setBrightness.bind(this)); // SET - bind to the 'setBrightness` method below
102
- this.connect();
35
+ .onSet(this.setBrightness.bind(this))
36
+ .onGet(() => this.state.Brightness);
37
+ this.connection = new orroConnection_1.OrroConnection({
38
+ name: device.name,
39
+ ipAddress: device.ipAddress,
40
+ homeId: this.platform.config.homeID,
41
+ switchId: device.switchID,
42
+ accessToken: this.platform.config.accessToken,
43
+ log: this.platform.log,
44
+ onLightingChange: change => this.handleLightingChange(change),
45
+ });
46
+ this.connection.start();
47
+ this.platform.api.on('shutdown', () => this.connection.stop());
103
48
  }
104
- /**
105
- * Handle "SET" requests from HomeKit
106
- * These are sent when the user changes the state of an accessory, for example, turning on a Light bulb.
107
- */
108
- async setOn(value) {
109
- try {
110
- this.platform.log.info('Set On');
111
- const payload = JSON.stringify({
112
- targetId: this.accessory.context.device.switchID,
113
- clientId: 'homebridge-orro',
114
- type: 'RemoteCommand',
115
- timestamp: Date.now(),
116
- data: {
117
- command: value ? 'on' : 'off'
118
- }
119
- });
120
- this.connection.send(payload);
121
- this.state.On = value;
122
- this.platform.log.info('Set Characteristic On ->', {
123
- targetId: this.accessory.context.device.switchID,
124
- clientId: 'homebridge-orro',
125
- type: 'RemoteCommand',
126
- timestamp: Date.now(),
127
- data: {
128
- command: value ? 'on' : 'off'
129
- }
130
- });
49
+ handleLightingChange(change) {
50
+ if (this.holdTimer) {
51
+ this.heldChange = change;
52
+ return;
131
53
  }
132
- catch (e) {
133
- this.platform.log.error('Set Characteristic On Error -> ', e.message);
54
+ const { onOff, dimmerLevel, wasUserInitiated } = change;
55
+ const source = wasUserInitiated === false ? 'adaptive' : 'from switch';
56
+ // HomeKit has no "on at zero" state, so level 0 is shown as off
57
+ const on = onOff && dimmerLevel !== 0;
58
+ if (on !== this.state.On) {
59
+ this.platform.log.info(`${this.accessory.displayName}: on -> ${on} (${source})`);
60
+ this.state.On = on;
61
+ this.service.updateCharacteristic(this.platform.Characteristic.On, on);
62
+ }
63
+ // level 0 is skipped so turning back on restores the previous brightness
64
+ if (dimmerLevel > 0 && dimmerLevel !== this.state.Brightness) {
65
+ this.platform.log.info(`${this.accessory.displayName}: brightness -> ${dimmerLevel} (${source})`);
66
+ this.state.Brightness = dimmerLevel;
67
+ this.service.updateCharacteristic(this.platform.Characteristic.Brightness, dimmerLevel);
134
68
  }
69
+ this.saveState();
135
70
  }
136
- /**
137
- * Handle the "GET" requests from HomeKit
138
- * These are sent when HomeKit wants to know the current state of the accessory, for example, checking if a Light bulb is on.
139
- *
140
- * GET requests should return as fast as possbile. A long delay here will result in
141
- * HomeKit being unresponsive and a bad user experience in general.
142
- *
143
- * If your device takes time to respond you should update the status of your device
144
- * asynchronously instead using the `updateCharacteristic` method instead.
145
-
146
- * @example
147
- * this.service.updateCharacteristic(this.platform.Characteristic.On, true)
148
- */
149
- async getOn() {
150
- const isOn = this.state.On;
151
- this.platform.log.info('Get Characteristic On ->', isOn);
152
- return isOn;
71
+ async setOn(value) {
72
+ const on = value;
73
+ await this.send({ command: on ? 'on' : 'off' }, on !== this.state.On);
74
+ this.state.On = on;
75
+ this.saveState();
76
+ }
77
+ setBrightness(value) {
78
+ this.pendingBrightness = value;
79
+ this.holdSwitchReports();
80
+ return new Promise((resolve, reject) => {
81
+ this.brightnessWaiters.push({ resolve, reject });
82
+ if (this.brightnessTimer) {
83
+ clearTimeout(this.brightnessTimer);
84
+ }
85
+ this.brightnessTimer = setTimeout(() => this.flushBrightness(), BRIGHTNESS_DEBOUNCE_MS);
86
+ });
153
87
  }
154
88
  /**
155
- * Handle "SET" requests from HomeKit
156
- * These are sent when the user changes the state of an accessory, for example, changing the Brightness
157
- */
158
- async setBrightness(value) {
89
+ * Only one brightness command is ever outstanding. Values that arrive meanwhile
90
+ * replace each other, so the switch goes straight to the newest one.
91
+ */
92
+ async flushBrightness() {
93
+ this.brightnessTimer = undefined;
94
+ if (this.brightnessSending) {
95
+ return; // the loop below picks up the newest value when its send finishes
96
+ }
97
+ this.brightnessSending = true;
98
+ // a running debounce timer means the user is still dragging, and it will flush again
99
+ while (this.brightnessWaiters.length > 0 && !this.brightnessTimer) {
100
+ const waiters = this.brightnessWaiters;
101
+ this.brightnessWaiters = [];
102
+ const value = this.pendingBrightness;
103
+ try {
104
+ await this.send({ command: 'dimmer_set', value }, value !== this.state.Brightness);
105
+ this.state.Brightness = value;
106
+ this.saveState();
107
+ waiters.forEach(waiter => waiter.resolve());
108
+ }
109
+ catch (e) {
110
+ waiters.forEach(waiter => waiter.reject(e));
111
+ }
112
+ this.holdSwitchReports();
113
+ }
114
+ this.brightnessSending = false;
115
+ }
116
+ /** Holds back switch reports, then applies the most recent one so the real level wins. */
117
+ holdSwitchReports() {
118
+ if (this.holdTimer) {
119
+ clearTimeout(this.holdTimer);
120
+ }
121
+ this.holdTimer = setTimeout(() => {
122
+ this.holdTimer = undefined;
123
+ const change = this.heldChange;
124
+ this.heldChange = undefined;
125
+ if (change) {
126
+ this.handleLightingChange(change);
127
+ }
128
+ }, BRIGHTNESS_HOLD_MS);
129
+ }
130
+ /** Throws a HomeKit error on failure, so a lost command is never reported as a success. */
131
+ async send(command, expectChange) {
159
132
  try {
160
- // prepare payload for api request
161
- const payload = JSON.stringify({
162
- targetId: this.accessory.context.device.switchID,
163
- clientId: 'homebridge-orro',
164
- type: 'RemoteCommand',
165
- timestamp: Date.now(),
166
- data: {
167
- command: 'dimmer_set',
168
- value: value
169
- }
170
- });
171
- // submit api request
172
- this.connection.send(payload);
173
- // update local state for brightness
174
- this.state.Brightness = value;
175
- this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.state.Brightness);
176
- // set object for manual change
177
- this.accessory.context.device.action = {
178
- type: 'brightness',
179
- value: this.state.Brightness
180
- };
181
- // log payload to console
182
- this.platform.log.info('Set Characteristic Brightness -> ', {
183
- targetId: this.accessory.context.device.switchID,
184
- clientId: 'homebridge-orro',
185
- type: 'RemoteCommand',
186
- timestamp: Date.now(),
187
- data: {
188
- command: 'dimmer_set',
189
- value: value
190
- }
191
- });
133
+ await this.connection.execute(command, expectChange);
134
+ this.platform.log.debug(`${this.accessory.displayName}: delivered`, command);
192
135
  }
193
136
  catch (e) {
194
- this.platform.log.error('Set Characteristic Brightness Error -> ', e.message);
137
+ this.platform.log.error(e.message);
138
+ const { HapStatusError, HAPStatus } = this.platform.api.hap;
139
+ throw new HapStatusError(-70402 /* SERVICE_COMMUNICATION_FAILURE */);
195
140
  }
196
141
  }
142
+ saveState() {
143
+ this.accessory.context.lastState = { ...this.state };
144
+ }
197
145
  }
198
146
  exports.Switch = Switch;
199
147
  //# sourceMappingURL=platformAccessory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"platformAccessory.js","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platformAccessory.js","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "Homebridge Orro",
3
3
  "name": "homebridge-orro",
4
- "version": "1.0.19",
4
+ "version": "1.0.21",
5
5
  "description": "Homebridge support for Orro lan switches.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -16,7 +16,13 @@
16
16
  "homebridge": ">=1.3.0"
17
17
  },
18
18
  "main": "dist/index.js",
19
+ "files": [
20
+ "dist",
21
+ "config.schema.json",
22
+ "LICENSE"
23
+ ],
19
24
  "scripts": {
25
+ "test": "npm run build && node --test \"test/*.test.js\"",
20
26
  "lint": "eslint src/**.ts --max-warnings=0",
21
27
  "watch": "npm run build && npm link && nodemon",
22
28
  "build": "rimraf ./dist && tsc",
@@ -37,8 +43,6 @@
37
43
  "typescript": "^4.2.2"
38
44
  },
39
45
  "dependencies": {
40
- "moment": "^2.30.1",
41
- "websocket": "^1.0.34",
42
- "ws": "^8.4.0"
46
+ "ws": "^8.22.2"
43
47
  }
44
48
  }
package/orro-lan/index.js DELETED
@@ -1,41 +0,0 @@
1
- const net = require('net');
2
- const WebSocketClient = require('websocket').client;
3
-
4
- let switch_ip = '192.168.7.125';
5
- let switch_id = 'de1bc286-51f7-480e-b702-7957b9952618';
6
- let home_id = '3debeb6b-023d-4dba-8e70-92663b6d2610';
7
-
8
- const setOn = (connection, val) => {
9
- let payload = JSON.stringify({
10
- targetId: switch_id,
11
- clientId: 'homebridge-orro',
12
- type: 'RemoteCommand',
13
- timestamp: Date.now(),
14
- data: {
15
- command: val ? 'on' : 'off'
16
- }
17
- });
18
- connection.sendUTF(payload);
19
- }
20
-
21
- let client = new WebSocketClient();
22
- client.connect(`ws://${switch_ip}:8080/edison/${home_id}`, null, null, [{ 'offline-access-token': 'YxqRX78eQU_gyzdftPmOG_7n261njz2NFF3hgckXEyQjZGi7qS1RBGdeGhjIb0gYKRKA_wMqeu8RdG9Aybaz1Q' }]);
23
- client.on('connect', connection => {
24
-
25
- // post on/off change
26
- setOn(connection, true);
27
- setTimeout(setOn.bind(this, connection, false), 5000);
28
-
29
- // listen for system events
30
- connection.on('message', data => {
31
- try {
32
- let json = JSON.parse(data.utf8Data);
33
- console.log(json);
34
- } catch(e) {
35
- console.log(e.message);
36
- }
37
- })
38
- })
39
- client.on('error', error => {
40
- console.log(error.message);
41
- })