homey-api 3.0.19 → 3.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.
|
@@ -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, {
|
|
@@ -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,
|
|
280
|
-
pings[HomeyAPI.DISCOVERY_STRATEGIES.LOCAL_SECURE].catch(err =>
|
|
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)
|
|
@@ -452,7 +462,7 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
452
462
|
method,
|
|
453
463
|
headers,
|
|
454
464
|
path,
|
|
455
|
-
originalBody,
|
|
465
|
+
body: originalBody,
|
|
456
466
|
retryAfterRefresh: true,
|
|
457
467
|
});
|
|
458
468
|
}
|
|
@@ -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
|
-
|
|
500
|
+
|
|
501
|
+
if (store && store.token && store.session) {
|
|
491
502
|
this.__debug('Got token from store');
|
|
492
|
-
|
|
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
|
-
|
|
505
|
-
|
|
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
|
-
|
|
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(
|
|
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:
|
|
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
|
-
|
|
705
|
+
|
|
706
|
+
this.__io.on('connect_error', err => {
|
|
668
707
|
this.__debug('SocketIOClient.onConnectError', err.message);
|
|
669
708
|
reject(err);
|
|
670
709
|
});
|
|
671
|
-
|
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "3.0.21",
|
|
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": "
|
|
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",
|