homey-api 3.0.20 → 3.0.22

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.
@@ -572,6 +572,8 @@ for(const {@link HomeyAPIV2.ManagerDevices.Device device} of Object.values(devic
572
572
  .finally(() => {
573
573
  this.__refreshTokenPromise = null;
574
574
  });
575
+ } else {
576
+ this.__debug('Already refreshing token reusing promise.');
575
577
  }
576
578
 
577
579
  return this.__refreshTokenPromise;
@@ -11,6 +11,7 @@ class Device extends DeviceV3 {
11
11
 
12
12
  delete item.driverUri;
13
13
  delete item.zoneName;
14
+
14
15
  return item;
15
16
  }
16
17
  }
@@ -459,6 +459,16 @@ class Manager extends EventEmitter {
459
459
 
460
460
  }
461
461
 
462
+ if (this.__connectPromise) {
463
+ await this.__connectPromise
464
+ return;
465
+ }
466
+
467
+ if (this.io) {
468
+ await this.io;
469
+ return
470
+ }
471
+
462
472
  this.__connectPromise = Promise.resolve().then(async () => {
463
473
  if (!this.io) {
464
474
  this.io = this.homey.subscribe(this.uri, {
@@ -229,6 +229,7 @@ class Device extends Item {
229
229
  item = super.transformGet(item);
230
230
 
231
231
  delete item.driverUri;
232
+ delete item.insights;
232
233
 
233
234
  if (item.capabilitiesObj) {
234
235
  for (const capabilityObj of Object.values(item.capabilitiesObj)) {
@@ -10,6 +10,15 @@ class ManagerInsights extends Manager {
10
10
  Log,
11
11
  };
12
12
 
13
+ async getLogEntries({ id, resolution, ...rest }) {
14
+ return this.__super__getLogEntries({
15
+ ...rest,
16
+ id: id,
17
+ uri: id.split(':', 3).join(':'),
18
+ resolution,
19
+ });
20
+ }
21
+
13
22
  }
14
23
 
15
24
  module.exports = ManagerInsights;
@@ -45,6 +45,7 @@ class HomeyAPIV3 extends HomeyAPI {
45
45
  ],
46
46
  baseUrl = null,
47
47
  token = null,
48
+ session = null,
48
49
  ...props
49
50
  }) {
50
51
  super({ properties, ...props });
@@ -67,6 +68,12 @@ class HomeyAPIV3 extends HomeyAPI {
67
68
  writable: true,
68
69
  });
69
70
 
71
+ Object.defineProperty(this, '__session', {
72
+ value: session,
73
+ enumerable: false,
74
+ writable: true,
75
+ });
76
+
70
77
  Object.defineProperty(this, '__strategies', {
71
78
  value: Array.isArray(strategy)
72
79
  ? strategy
@@ -276,8 +283,11 @@ class HomeyAPIV3 extends HomeyAPI {
276
283
 
277
284
  // Ping localSecure (https://xxx-xxx-xxx-xx.homey.homeylocal.com)
278
285
  if (urls[HomeyAPI.DISCOVERY_STRATEGIES.LOCAL_SECURE]) {
279
- pings[HomeyAPI.DISCOVERY_STRATEGIES.LOCAL_SECURE] = ping(HomeyAPI.DISCOVERY_STRATEGIES.LOCAL_SECURE, 1200);
280
- pings[HomeyAPI.DISCOVERY_STRATEGIES.LOCAL_SECURE].catch(err => this.__debug(`Ping ${HomeyAPI.DISCOVERY_STRATEGIES.LOCAL_SECURE} Error:`, err && err.message));
286
+ pings[HomeyAPI.DISCOVERY_STRATEGIES.LOCAL_SECURE] = ping(HomeyAPI.DISCOVERY_STRATEGIES.LOCAL_SECURE, 3000);
287
+ pings[HomeyAPI.DISCOVERY_STRATEGIES.LOCAL_SECURE].catch(err => {
288
+ this.__debug(`Ping ${HomeyAPI.DISCOVERY_STRATEGIES.LOCAL_SECURE} Error:`, err && err.message)
289
+ this.__debug(urls[HomeyAPI.DISCOVERY_STRATEGIES.LOCAL_SECURE]);
290
+ });
281
291
  }
282
292
 
283
293
  // Ping local (http://xxx-xxx-xxx-xxx)
@@ -487,9 +497,13 @@ class HomeyAPIV3 extends HomeyAPI {
487
497
  this.__loginPromise = Promise.resolve().then(async () => {
488
498
  // Check store for a valid Homey.Session
489
499
  const store = await this.__getStore();
490
- if (store && store.token) {
500
+
501
+ if (store && store.token && store.session) {
491
502
  this.__debug('Got token from store');
492
- return store.token;
503
+ this.__token = store.token;
504
+ this.__session = store.session;
505
+
506
+ return;
493
507
  }
494
508
 
495
509
  // Create a Session by generating a JWT token on AthomCloudAPI,
@@ -501,21 +515,28 @@ class HomeyAPIV3 extends HomeyAPI {
501
515
  $socket: false,
502
516
  token: jwtToken,
503
517
  });
504
- await this.__setStore({ token });
505
- this.__debug('Got token');
518
+ this.__token = token;
519
+
520
+ const session = await this.sessions.getSessionMe({
521
+ $socket: false,
522
+ });
523
+ this.__session = session;
524
+
525
+ await this.__setStore({ token, session });
506
526
 
507
- return token;
527
+ this.__debug('Got token');
528
+ return;
508
529
  }
509
530
 
510
531
  throw new Error('Cannot Sign In: Missing AthomCloudAPI');
511
532
  });
512
533
 
513
534
  this.__loginPromise
514
- .then(token => {
515
- this.__token = token;
516
- })
535
+ .then(() => { })
517
536
  .catch(err => {
518
537
  this.__debug('Error Logging In:', err);
538
+ this.__token = null;
539
+ this.__session = null;
519
540
  })
520
541
  .finally(() => {
521
542
  this.__loginPromise = null;
@@ -553,14 +574,16 @@ class HomeyAPIV3 extends HomeyAPI {
553
574
  await this.connect();
554
575
  await new Promise((resolve, reject) => {
555
576
  this.__ioNamespace.once('disconnect', (reason) => {
556
- reject(reason);
577
+ reject(new Error(reason));
557
578
  });
579
+ this.__debug('subscribing', uri);
558
580
  this.__ioNamespace.emit('subscribe', uri, err => {
559
581
  if (err) {
560
582
  this.__debug('Failed to subscribe', uri, err);
561
583
  return reject(err)
562
584
  }
563
585
 
586
+ this.__debug('subscribed', uri);
564
587
  return resolve();
565
588
  });
566
589
  });
@@ -623,13 +646,15 @@ class HomeyAPIV3 extends HomeyAPI {
623
646
  return new Promise((resolve, reject) => {
624
647
  this.__debug(`SocketIOClient ${baseUrl}`);
625
648
  this.__io = SocketIOClient(baseUrl, {
626
- autoConnect: false,
649
+ autoConnect: true,
627
650
  transports: ['websocket'],
628
651
  transportOptions: {
629
652
  pingTimeout: 8000,
630
653
  pingInterval: 5000,
631
654
  },
655
+ reconnection: true,
632
656
  });
657
+
633
658
  this.__io.on('disconnect', reason => {
634
659
  this.__debug('SocketIOClient.onDisconnect', reason);
635
660
  this.__connected = false;
@@ -640,11 +665,18 @@ class HomeyAPIV3 extends HomeyAPI {
640
665
  this.__ioNamespace.removeAllListeners();
641
666
  }
642
667
 
668
+ if (reason === 'io server disconnect') {
669
+ // The disconnect was initiated by the server.
670
+ this.__io.connect();
671
+ }
672
+
643
673
  reject(new Error('Disconnected'));
644
674
  });
675
+
645
676
  this.__io.on('error', err => {
646
677
  this.__debug('SocketIOClient.onError', err.message);
647
678
  });
679
+
648
680
  this.__io.on('reconnect', () => {
649
681
  this.__debug('SocketIOClient.onReconnect');
650
682
  this.__handshakeClient()
@@ -658,17 +690,25 @@ class HomeyAPIV3 extends HomeyAPI {
658
690
  reject(err);
659
691
  });
660
692
  });
693
+
694
+ this.__io.on('reconnect_attempt', () => {
695
+ this.__debug(`SocketIOClient.onReconnectAttempt`);
696
+ });
697
+
661
698
  this.__io.on('reconnecting', attempt => {
662
699
  this.__debug(`SocketIOClient.onReconnecting (Attempt #${attempt})`);
663
700
  });
701
+
664
702
  this.__io.on('reconnect_error', err => {
665
703
  this.__debug('SocketIOClient.onReconnectError', err.message);
666
704
  });
667
- this.__io.once('connect_error', err => {
705
+
706
+ this.__io.on('connect_error', err => {
668
707
  this.__debug('SocketIOClient.onConnectError', err.message);
669
708
  reject(err);
670
709
  });
671
- this.__io.once('connect', () => {
710
+
711
+ this.__io.on('connect', () => {
672
712
  this.__debug('SocketIOClient.onConnect');
673
713
  this.__handshakeClient()
674
714
  .then(() => {
@@ -681,9 +721,10 @@ class HomeyAPIV3 extends HomeyAPI {
681
721
  reject(err);
682
722
  });
683
723
  });
684
- this.__io.connect();
724
+ // this.__io.connect();
685
725
  });
686
726
  });
727
+
687
728
  this.io.catch(err => {
688
729
  this.__debug('SocketIOClient Error', err.message);
689
730
  });
@@ -712,6 +753,8 @@ class HomeyAPIV3 extends HomeyAPI {
712
753
  }
713
754
 
714
755
  async __handshakeClient() {
756
+ this.__debug('__handshakeClient');
757
+
715
758
  return new Promise((resolve, reject) => {
716
759
  this.__io.emit('handshakeClient', {
717
760
  token: this.__token,
@@ -746,31 +789,70 @@ class HomeyAPIV3 extends HomeyAPI {
746
789
 
747
790
  return new Promise((resolve, reject) => {
748
791
  this.__ioNamespace = this.__io.io.socket(namespace);
792
+
793
+ this.__debug(this.__ioNamespace);
794
+
795
+ // Assuming this.__ioNamespace is your namespace object
796
+ if (this.__ioNamespace.connected) {
797
+ this.__debug(`SocketIOClient.Namespace[${namespace}].connected`);
798
+ }
799
+
749
800
  this.__ioNamespace.once('connect', () => {
750
801
  this.__debug(`SocketIOClient.Namespace[${namespace}].onConnect`);
751
802
  resolve();
752
803
  });
804
+
753
805
  this.__ioNamespace.once('connect_error', err => {
754
806
  this.__debug(`SocketIOClient.Namespace[${namespace}].onConnectError`, err.message);
755
807
  reject(err);
756
808
  });
809
+
757
810
  this.__ioNamespace.on('reconnecting', attempt => {
758
811
  this.__debug(`SocketIOClient.Namespace[${namespace}].onReconnecting (Attempt #${attempt})`);
759
812
  });
813
+
760
814
  this.__ioNamespace.on('reconnect', () => {
761
815
  this.__debug(`SocketIOClient.Namespace[${namespace}].onReconnect`);
762
816
  });
817
+
763
818
  this.__ioNamespace.on('reconnect_error', err => {
764
819
  this.__debug(`SocketIOClient.Namespace[${namespace}].onReconnectError`, err.message);
765
820
  });
821
+
766
822
  this.__ioNamespace.on('disconnect', reason => {
767
823
  this.__debug(`SocketIOClient.Namespace[${namespace}].onDisconnect`, reason);
768
824
  });
769
- this.__ioNamespace.connect();
825
+
826
+ this.__debug(`SocketIOClient.Namespace[${namespace}].disconnected`, this.__ioNamespace.disconnected);
827
+ this.__debug(`SocketIOClient.Namespace[${namespace}].connected`, this.__ioNamespace.connected);
770
828
  });
771
829
  });
772
830
  }
773
831
 
832
+ hasScope(scope) {
833
+ if (this.__session == null) {
834
+ this.__debug('Tried to call hasScope without a session present.');
835
+ return true;
836
+ }
837
+
838
+ return this.__session.intersectedScopes.some((availableScope) => {
839
+ return this.constructor.instanceOfScope(scope, availableScope);
840
+ });
841
+ }
842
+
843
+ static instanceOfScope(scopeOne, scopeTwo) {
844
+ const partsOne = scopeOne.split(':');
845
+ const partsTwo = scopeTwo.split(':');
846
+
847
+ let suffixIsEqual = true;
848
+
849
+ if (partsOne[1]) {
850
+ suffixIsEqual = partsOne[1] === partsTwo[1];
851
+ }
852
+
853
+ return scopeOne.indexOf(partsTwo[0]) === 0 && suffixIsEqual;
854
+ }
855
+
774
856
  }
775
857
 
776
858
  module.exports = HomeyAPIV3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homey-api",
3
- "version": "3.0.20",
3
+ "version": "3.0.22",
4
4
  "description": "Homey API",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -12,7 +12,7 @@
12
12
  ],
13
13
  "types": "assets/types/homey-api.d.ts",
14
14
  "scripts": {
15
- "test": "echo \"Error: no test specified\" && exit 1",
15
+ "test": "jest",
16
16
  "lint": "eslint .",
17
17
  "serve": "concurrently \"serve jsdoc/\" \"npm run jsdoc:watch\"",
18
18
  "build": "npm run build:specs; npm run build:jsdoc; npm run build:types; npm run build:webpack;",
@@ -65,9 +65,11 @@
65
65
  "ejs": "^3.1.6",
66
66
  "eslint": "^7.32.0",
67
67
  "eslint-config-athom": "^2.1.1",
68
+ "eslint-plugin-jest": "^27.4.0",
68
69
  "fs-extra": "^10.0.0",
69
70
  "homey-api": "^3.0.8",
70
71
  "http-server": "^0.12.3",
72
+ "jest": "^29.7.0",
71
73
  "jsdoc": "^4.0.2",
72
74
  "jsdoc-to-markdown": "^8.0.0",
73
75
  "jsdoc-ts-utils": "^4.0.0",