homey-api 1.5.14 → 1.5.17
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.
|
@@ -113,64 +113,105 @@ class Device extends Item {
|
|
|
113
113
|
async connect() {
|
|
114
114
|
this.__debug('connect');
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
this.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
116
|
+
// If disconnecting, await that first
|
|
117
|
+
try {
|
|
118
|
+
await this.__disconnectPromise;
|
|
119
|
+
} catch (err) { }
|
|
120
|
+
|
|
121
|
+
this.__connectPromise = Promise.resolve().then(async () => {
|
|
122
|
+
if (!this.io) {
|
|
123
|
+
this.io = this.homey.subscribe(this.uri, {
|
|
124
|
+
onConnect: () => {
|
|
125
|
+
this.__debug('onConnect');
|
|
126
|
+
this.__connected = true;
|
|
127
|
+
},
|
|
128
|
+
onDisconnect: () => {
|
|
129
|
+
this.__debug('onDisconnect');
|
|
130
|
+
this.__connected = false;
|
|
131
|
+
},
|
|
132
|
+
onReconnect: () => {
|
|
133
|
+
this.__debug('onDisconnect');
|
|
134
|
+
|
|
135
|
+
const capabilityInstances = this.__capabilityInstances;
|
|
136
|
+
if (Object.keys(capabilityInstances).length > 0) {
|
|
137
|
+
// Get the device's latest values
|
|
138
|
+
// TODO: Optimize this with `getDevices()` when >1 device has >0 capability instances.
|
|
139
|
+
this.manager.getDevice({
|
|
140
|
+
id: this.id,
|
|
141
|
+
}).then(async device => {
|
|
142
|
+
Object.entries(capabilityInstances).forEach(([capabilityId, capabilityInstance]) => {
|
|
143
|
+
const value = device.capabilitiesObj
|
|
144
|
+
? typeof device.capabilitiesObj[capabilityId] !== 'undefined'
|
|
145
|
+
? device.capabilitiesObj[capabilityId].value
|
|
146
|
+
: null
|
|
147
|
+
: null;
|
|
148
|
+
|
|
149
|
+
capabilityInstance.__onCapabilityValue({
|
|
150
|
+
capabilityId,
|
|
151
|
+
value,
|
|
152
|
+
transactionId: Util.uuid(),
|
|
153
|
+
});
|
|
147
154
|
});
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
}
|
|
155
|
+
})
|
|
156
|
+
// eslint-disable-next-line no-console
|
|
157
|
+
.catch(err => console.error(`Device[${this.id}].onReconnectError:`, err));
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
onEvent: (event, data) => {
|
|
161
|
+
// // Fire event listeners
|
|
162
|
+
if (Array.isArray(this.__listeners[event])) {
|
|
163
|
+
this.__listeners[event].forEach(listener => listener(data));
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
await this.io;
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Delete the connecting Promise
|
|
173
|
+
this.__connectPromise
|
|
174
|
+
.catch(() => { })
|
|
175
|
+
.finally(() => {
|
|
176
|
+
delete this.__connectPromise;
|
|
160
177
|
});
|
|
161
|
-
}
|
|
162
178
|
|
|
163
|
-
await this.
|
|
179
|
+
await this.__connectPromise;
|
|
164
180
|
}
|
|
165
181
|
|
|
166
182
|
async disconnect() {
|
|
167
183
|
this.__debug('disconnect');
|
|
168
184
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
185
|
+
// If connecting, await that first
|
|
186
|
+
try {
|
|
187
|
+
await this.__connectPromise;
|
|
188
|
+
} catch (err) { }
|
|
189
|
+
|
|
190
|
+
this.__disconnectPromise = Promise.resolve().then(async () => {
|
|
191
|
+
this.__connected = false;
|
|
192
|
+
|
|
193
|
+
if (this.io) {
|
|
194
|
+
this.io
|
|
195
|
+
.then(io => io.unsubscribe())
|
|
196
|
+
.catch(err => this.__debug('Error Disconnecting:', err));
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Delete the disconnecting Promise
|
|
201
|
+
this.__disconnectPromise
|
|
202
|
+
.catch(() => { })
|
|
203
|
+
.finally(() => {
|
|
204
|
+
delete this.__disconnectPromise;
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
await this.__disconnectPromise;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
destroy() {
|
|
211
|
+
super.destroy();
|
|
212
|
+
|
|
213
|
+
// Disconnect from Socket.io
|
|
214
|
+
this.disconnect().catch(() => { });
|
|
174
215
|
}
|
|
175
216
|
|
|
176
217
|
}
|
|
@@ -167,10 +167,7 @@ class Manager extends EventEmitter {
|
|
|
167
167
|
}
|
|
168
168
|
case 'body': {
|
|
169
169
|
if (parameter.root) {
|
|
170
|
-
body =
|
|
171
|
-
...body,
|
|
172
|
-
...value,
|
|
173
|
-
};
|
|
170
|
+
body = value;
|
|
174
171
|
} else {
|
|
175
172
|
body[parameterId] = value;
|
|
176
173
|
}
|
|
@@ -253,6 +250,7 @@ class Manager extends EventEmitter {
|
|
|
253
250
|
} else {
|
|
254
251
|
// Get from HTTP
|
|
255
252
|
result = await this.homey.call({
|
|
253
|
+
$timeout,
|
|
256
254
|
headers,
|
|
257
255
|
body,
|
|
258
256
|
path: `/api/manager/${this.id}${path}`,
|
|
@@ -383,82 +381,102 @@ class Manager extends EventEmitter {
|
|
|
383
381
|
async connect() {
|
|
384
382
|
this.__debug('connect');
|
|
385
383
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
this.
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
384
|
+
// If disconnecting, await that first
|
|
385
|
+
try {
|
|
386
|
+
await this.__disconnectPromise;
|
|
387
|
+
} catch (err) { }
|
|
388
|
+
|
|
389
|
+
this.__connectPromise = Promise.resolve().then(async () => {
|
|
390
|
+
if (!this.io) {
|
|
391
|
+
this.io = this.homey.subscribe(this.uri, {
|
|
392
|
+
onConnect: () => {
|
|
393
|
+
this.__debug('onConnect');
|
|
394
|
+
this.__connected = true;
|
|
395
|
+
},
|
|
396
|
+
onDisconnect: () => {
|
|
397
|
+
this.__debug('onDisconnect');
|
|
398
|
+
this.__connected = false;
|
|
399
|
+
|
|
400
|
+
// Clear CRUD Item cache
|
|
401
|
+
for (const itemId of Object.keys(this.__cache)) {
|
|
402
|
+
this.__cache[itemId] = {};
|
|
403
|
+
this.__cacheAllComplete[itemId] = false;
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
onEvent: (event, data) => {
|
|
407
|
+
this.__debug('onEvent', event);
|
|
408
|
+
|
|
409
|
+
// Transform & add to cache if this is a CRUD event
|
|
410
|
+
if (event.endsWith('.create')
|
|
411
|
+
|| event.endsWith('.update')
|
|
412
|
+
|| event.endsWith('.delete')) {
|
|
413
|
+
const [itemId, operation] = event.split('.');
|
|
414
|
+
const ItemClass = this.constructor.ITEMS[itemId] || Item;
|
|
415
|
+
const itemType = this.__itemsById[itemId].type;
|
|
416
|
+
const key = itemType === 'filter'
|
|
417
|
+
? `${data.uri}:${data.id}`
|
|
418
|
+
: `${data.id}`;
|
|
419
|
+
|
|
420
|
+
switch (operation) {
|
|
421
|
+
case 'create': {
|
|
422
|
+
this.__cache[itemId][key] = new ItemClass({
|
|
423
|
+
key,
|
|
424
|
+
manager: this,
|
|
425
|
+
properties: { ...data },
|
|
426
|
+
});
|
|
427
|
+
this.__cache[itemId][key].emit('create', data);
|
|
424
428
|
|
|
425
|
-
|
|
429
|
+
data = this.__cache[itemId][key];
|
|
426
430
|
|
|
427
|
-
|
|
428
|
-
}
|
|
429
|
-
case 'update': {
|
|
430
|
-
if (this.__cache[itemId][key]) {
|
|
431
|
-
this.__cache[itemId][key].__update(data);
|
|
432
|
-
this.__cache[itemId][key].emit('update', data);
|
|
431
|
+
break;
|
|
433
432
|
}
|
|
433
|
+
case 'update': {
|
|
434
|
+
if (this.__cache[itemId][key]) {
|
|
435
|
+
this.__cache[itemId][key].__update(data);
|
|
436
|
+
this.__cache[itemId][key].emit('update', data);
|
|
437
|
+
} else {
|
|
438
|
+
this.__cache[itemId][key] = new ItemClass({
|
|
439
|
+
key,
|
|
440
|
+
manager: this,
|
|
441
|
+
properties: { ...data },
|
|
442
|
+
});
|
|
443
|
+
}
|
|
434
444
|
|
|
435
|
-
|
|
445
|
+
data = this.__cache[itemId][key];
|
|
436
446
|
|
|
437
|
-
|
|
438
|
-
}
|
|
439
|
-
case 'delete': {
|
|
440
|
-
if (this.__cache[itemId][key]) {
|
|
441
|
-
this.__cache[itemId][key].emit('delete');
|
|
442
|
-
this.__cache[itemId][key].destroy();
|
|
443
|
-
delete this.__cache[itemId][key];
|
|
444
|
-
data = null;
|
|
447
|
+
break;
|
|
445
448
|
}
|
|
446
|
-
|
|
449
|
+
case 'delete': {
|
|
450
|
+
if (this.__cache[itemId][key]) {
|
|
451
|
+
this.__cache[itemId][key].emit('delete');
|
|
452
|
+
this.__cache[itemId][key].destroy();
|
|
453
|
+
delete this.__cache[itemId][key];
|
|
454
|
+
data = null;
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
default:
|
|
459
|
+
break;
|
|
447
460
|
}
|
|
448
|
-
default:
|
|
449
|
-
break;
|
|
450
461
|
}
|
|
451
|
-
}
|
|
452
462
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
463
|
+
// Fire event listeners
|
|
464
|
+
this.emit(event, data);
|
|
465
|
+
},
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
await this.io;
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
// Delete the connecting Promise
|
|
473
|
+
this.__connectPromise
|
|
474
|
+
.catch(() => { })
|
|
475
|
+
.finally(() => {
|
|
476
|
+
delete this.__connectPromise;
|
|
458
477
|
});
|
|
459
|
-
}
|
|
460
478
|
|
|
461
|
-
await this.
|
|
479
|
+
await this.__connectPromise;
|
|
462
480
|
}
|
|
463
481
|
|
|
464
482
|
/**
|
|
@@ -468,11 +486,31 @@ class Manager extends EventEmitter {
|
|
|
468
486
|
async disconnect() {
|
|
469
487
|
this.__debug('disconnect');
|
|
470
488
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
489
|
+
// If connecting, await that first
|
|
490
|
+
try {
|
|
491
|
+
await this.__connectPromise;
|
|
492
|
+
} catch (err) { }
|
|
493
|
+
|
|
494
|
+
this.__disconnectPromise = Promise.resolve().then(async () => {
|
|
495
|
+
this.__connected = false;
|
|
496
|
+
|
|
497
|
+
if (this.io) {
|
|
498
|
+
await this.io
|
|
499
|
+
.then(io => io.unsubscribe())
|
|
500
|
+
.catch(err => this.__debug('Error Disconnecting:', err));
|
|
501
|
+
|
|
502
|
+
delete this.io;
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
// Delete the disconnecting Promise
|
|
507
|
+
this.__disconnectPromise
|
|
508
|
+
.catch(() => { })
|
|
509
|
+
.finally(() => {
|
|
510
|
+
delete this.__disconnectPromise;
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
await this.__disconnectPromise;
|
|
476
514
|
}
|
|
477
515
|
|
|
478
516
|
destroy() {
|
|
@@ -288,8 +288,6 @@ class HomeyAPIV2 extends HomeyAPI {
|
|
|
288
288
|
promises.push(pings[HomeyAPI.DISCOVERY_STRATEGIES.MDNS]);
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
-
// TODO: Move this to the catch handler to always fallback on cloud
|
|
292
|
-
// Now mdns or local will error first and cloud won't have a chance!!
|
|
293
291
|
if (pings[HomeyAPI.DISCOVERY_STRATEGIES.CLOUD]) {
|
|
294
292
|
promises.push(pings[HomeyAPI.DISCOVERY_STRATEGIES.CLOUD]);
|
|
295
293
|
}
|
|
@@ -301,7 +299,16 @@ class HomeyAPIV2 extends HomeyAPI {
|
|
|
301
299
|
return Promise.race(promises);
|
|
302
300
|
})
|
|
303
301
|
.then(result => resolve(result))
|
|
304
|
-
.catch(
|
|
302
|
+
.catch(err => {
|
|
303
|
+
// Last resort: try cloud
|
|
304
|
+
if (pings[HomeyAPI.DISCOVERY_STRATEGIES.CLOUD]) {
|
|
305
|
+
return pings[HomeyAPI.DISCOVERY_STRATEGIES.CLOUD].catch(err => {
|
|
306
|
+
throw new HomeyOfflineError(err);
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
reject(new HomeyOfflineError(err));
|
|
311
|
+
});
|
|
305
312
|
} else if (pings[HomeyAPI.DISCOVERY_STRATEGIES.LOCAL]) {
|
|
306
313
|
pings[HomeyAPI.DISCOVERY_STRATEGIES.LOCAL]
|
|
307
314
|
.then(result => resolve(result))
|