homey-api 1.5.14 → 1.5.15

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
- if (!this.io) {
117
- this.io = this.homey.subscribe(this.uri, {
118
- onConnect: () => {
119
- this.__debug('onConnect');
120
- this.__connected = true;
121
- },
122
- onDisconnect: () => {
123
- this.__debug('onDisconnect');
124
- this.__connected = false;
125
- },
126
- onReconnect: () => {
127
- this.__debug('onDisconnect');
128
-
129
- const capabilityInstances = this.__capabilityInstances;
130
- if (Object.keys(capabilityInstances).length > 0) {
131
- // Get the device's latest values
132
- // TODO: Optimize this with `getDevices()` when >1 device has >0 capability instances.
133
- this.manager.getDevice({
134
- id: this.id,
135
- }).then(async device => {
136
- Object.entries(capabilityInstances).forEach(([capabilityId, capabilityInstance]) => {
137
- const value = device.capabilitiesObj
138
- ? typeof device.capabilitiesObj[capabilityId] !== 'undefined'
139
- ? device.capabilitiesObj[capabilityId].value
140
- : null
141
- : null;
142
-
143
- capabilityInstance.__onCapabilityValue({
144
- capabilityId,
145
- value,
146
- transactionId: Util.uuid(),
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
- // eslint-disable-next-line no-console
151
- .catch(err => console.error(`Device[${this.id}].onReconnectError:`, err));
152
- }
153
- },
154
- onEvent: (event, data) => {
155
- // // Fire event listeners
156
- if (Array.isArray(this.__listeners[event])) {
157
- this.__listeners[event].forEach(listener => listener(data));
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.io;
179
+ await this.__connectPromise;
164
180
  }
165
181
 
166
182
  async disconnect() {
167
183
  this.__debug('disconnect');
168
184
 
169
- if (this.io) {
170
- this.io
171
- .then(io => io.unsubscribe())
172
- .catch(err => this.__debug('Error Disconnecting:', err));
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
  }
@@ -55,7 +55,8 @@ class Item extends EventEmitter {
55
55
  }
56
56
 
57
57
  destroy() {
58
- // TODO
58
+ // Remove all event listeners
59
+ this.removeAllListeners();
59
60
  }
60
61
 
61
62
  }
@@ -383,82 +383,102 @@ class Manager extends EventEmitter {
383
383
  async connect() {
384
384
  this.__debug('connect');
385
385
 
386
- if (!this.io) {
387
- this.io = this.homey.subscribe(this.uri, {
388
- onConnect: () => {
389
- this.__debug('onConnect');
390
- this.__connected = true;
391
- },
392
- onDisconnect: () => {
393
- this.__debug('onDisconnect');
394
- this.__connected = false;
395
-
396
- // Clear CRUD Item cache
397
- for (const itemId of Object.keys(this.__cache)) {
398
- this.__cache[itemId] = {};
399
- this.__cacheAllComplete[itemId] = false;
400
- }
401
- },
402
- onEvent: (event, data) => {
403
- this.__debug('onEvent', event);
404
-
405
- // Transform & add to cache if this is a CRUD event
406
- if (event.endsWith('.create')
407
- || event.endsWith('.update')
408
- || event.endsWith('.delete')) {
409
- const [itemId, operation] = event.split('.');
410
- const ItemClass = this.constructor.ITEMS[itemId] || Item;
411
- const itemType = this.__itemsById[itemId].type;
412
- const key = itemType === 'filter'
413
- ? `${data.uri}:${data.id}`
414
- : `${data.id}`;
415
-
416
- switch (operation) {
417
- case 'create': {
418
- this.__cache[itemId][key] = new ItemClass({
419
- key,
420
- manager: this,
421
- properties: { ...data },
422
- });
423
- this.__cache[itemId][key].emit('create', data);
386
+ // If disconnecting, await that first
387
+ try {
388
+ await this.__disconnectPromise;
389
+ } catch (err) { }
390
+
391
+ this.__connectPromise = Promise.resolve().then(async () => {
392
+ if (!this.io) {
393
+ this.io = this.homey.subscribe(this.uri, {
394
+ onConnect: () => {
395
+ this.__debug('onConnect');
396
+ this.__connected = true;
397
+ },
398
+ onDisconnect: () => {
399
+ this.__debug('onDisconnect');
400
+ this.__connected = false;
401
+
402
+ // Clear CRUD Item cache
403
+ for (const itemId of Object.keys(this.__cache)) {
404
+ this.__cache[itemId] = {};
405
+ this.__cacheAllComplete[itemId] = false;
406
+ }
407
+ },
408
+ onEvent: (event, data) => {
409
+ this.__debug('onEvent', event);
410
+
411
+ // Transform & add to cache if this is a CRUD event
412
+ if (event.endsWith('.create')
413
+ || event.endsWith('.update')
414
+ || event.endsWith('.delete')) {
415
+ const [itemId, operation] = event.split('.');
416
+ const ItemClass = this.constructor.ITEMS[itemId] || Item;
417
+ const itemType = this.__itemsById[itemId].type;
418
+ const key = itemType === 'filter'
419
+ ? `${data.uri}:${data.id}`
420
+ : `${data.id}`;
421
+
422
+ switch (operation) {
423
+ case 'create': {
424
+ this.__cache[itemId][key] = new ItemClass({
425
+ key,
426
+ manager: this,
427
+ properties: { ...data },
428
+ });
429
+ this.__cache[itemId][key].emit('create', data);
424
430
 
425
- data = this.__cache[itemId][key];
431
+ data = this.__cache[itemId][key];
426
432
 
427
- break;
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);
433
+ break;
433
434
  }
435
+ case 'update': {
436
+ if (this.__cache[itemId][key]) {
437
+ this.__cache[itemId][key].__update(data);
438
+ this.__cache[itemId][key].emit('update', data);
439
+ } else {
440
+ this.__cache[itemId][key] = new ItemClass({
441
+ key,
442
+ manager: this,
443
+ properties: { ...data },
444
+ });
445
+ }
434
446
 
435
- data = this.__cache[itemId][key];
447
+ data = this.__cache[itemId][key];
436
448
 
437
- break;
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;
449
+ break;
445
450
  }
446
- break;
451
+ case 'delete': {
452
+ if (this.__cache[itemId][key]) {
453
+ this.__cache[itemId][key].emit('delete');
454
+ this.__cache[itemId][key].destroy();
455
+ delete this.__cache[itemId][key];
456
+ data = null;
457
+ }
458
+ break;
459
+ }
460
+ default:
461
+ break;
447
462
  }
448
- default:
449
- break;
450
463
  }
451
- }
452
464
 
453
- // Fire event listeners
454
- if (Array.isArray(this.__listeners[event])) {
455
- this.__listeners[event].forEach(listener => listener(data));
456
- }
457
- },
465
+ // Fire event listeners
466
+ this.emit(event, data);
467
+ },
468
+ });
469
+ }
470
+
471
+ await this.io;
472
+ });
473
+
474
+ // Delete the connecting Promise
475
+ this.__connectPromise
476
+ .catch(() => { })
477
+ .finally(() => {
478
+ delete this.__connectPromise;
458
479
  });
459
- }
460
480
 
461
- await this.io;
481
+ await this.__connectPromise;
462
482
  }
463
483
 
464
484
  /**
@@ -468,11 +488,31 @@ class Manager extends EventEmitter {
468
488
  async disconnect() {
469
489
  this.__debug('disconnect');
470
490
 
471
- if (this.io) {
472
- this.io
473
- .then(io => io.unsubscribe())
474
- .catch(err => this.__debug('Error Disconnecting:', err));
475
- }
491
+ // If connecting, await that first
492
+ try {
493
+ await this.__connectPromise;
494
+ } catch (err) { }
495
+
496
+ this.__disconnectPromise = Promise.resolve().then(async () => {
497
+ this.__connected = false;
498
+
499
+ if (this.io) {
500
+ await this.io
501
+ .then(io => io.unsubscribe())
502
+ .catch(err => this.__debug('Error Disconnecting:', err));
503
+
504
+ delete this.io;
505
+ }
506
+ });
507
+
508
+ // Delete the disconnecting Promise
509
+ this.__disconnectPromise
510
+ .catch(() => { })
511
+ .finally(() => {
512
+ delete this.__disconnectPromise;
513
+ });
514
+
515
+ await this.__disconnectPromise;
476
516
  }
477
517
 
478
518
  destroy() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homey-api",
3
- "version": "1.5.14",
3
+ "version": "1.5.15",
4
4
  "description": "Homey API",
5
5
  "main": "src/index.js",
6
6
  "types": "assets/types/homey-api.d.ts",