homey-api 3.0.22 → 3.0.24
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.
- package/lib/HomeyAPI/HomeyAPI.js +4 -1
- package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardAction.js +5 -4
- package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardCondition.js +5 -4
- package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardTrigger.js +5 -4
- package/lib/HomeyAPI/HomeyAPIV3/Manager.js +12 -6
- package/lib/HomeyAPI/HomeyAPIV3.js +64 -92
- package/lib/Util.js +12 -4
- package/package.json +1 -1
package/lib/HomeyAPI/HomeyAPI.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const Util = require('../Util');
|
|
4
|
+
const EventEmitter = require('../EventEmitter');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* An authenticated Homey API. Do not construct this class manually.
|
|
7
8
|
* @class
|
|
8
9
|
* @hideconstructor
|
|
9
10
|
*/
|
|
10
|
-
class HomeyAPI {
|
|
11
|
+
class HomeyAPI extends EventEmitter {
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Platforms
|
|
@@ -46,6 +47,8 @@ class HomeyAPI {
|
|
|
46
47
|
properties = {},
|
|
47
48
|
debug = () => { },
|
|
48
49
|
}) {
|
|
50
|
+
super();
|
|
51
|
+
|
|
49
52
|
// Set Debug Enabled
|
|
50
53
|
Object.defineProperty(this, '__debugFunction', {
|
|
51
54
|
value: debug,
|
|
@@ -9,10 +9,11 @@ class FlowCardAction extends FlowCardActionV3 {
|
|
|
9
9
|
|
|
10
10
|
item.id = `${item.uri}:${item.id}`;
|
|
11
11
|
item.ownerUri = item.uri;
|
|
12
|
-
|
|
13
|
-
item.
|
|
14
|
-
item.
|
|
15
|
-
item.
|
|
12
|
+
// I dont know how uriObj can be null but it is possible.
|
|
13
|
+
item.ownerId = item.uriObj != null ? item.uriObj.id : null;
|
|
14
|
+
item.ownerName = item.uriObj != null ? item.uriObj.name : null;
|
|
15
|
+
item.color = item.uriObj != null ? item.uriObj.color : null;
|
|
16
|
+
item.iconObj = item.uriObj != null ? item.uriObj.iconObj : null;
|
|
16
17
|
|
|
17
18
|
delete item.uri;
|
|
18
19
|
delete item.uriObj;
|
|
@@ -9,10 +9,11 @@ class FlowCardCondition extends FlowCardConditionV3 {
|
|
|
9
9
|
|
|
10
10
|
item.id = `${item.uri}:${item.id}`;
|
|
11
11
|
item.ownerUri = item.uri;
|
|
12
|
-
|
|
13
|
-
item.
|
|
14
|
-
item.
|
|
15
|
-
item.
|
|
12
|
+
// I dont know how uriObj can be null but it is possible.
|
|
13
|
+
item.ownerId = item.uriObj != null ? item.uriObj.id : null;
|
|
14
|
+
item.ownerName = item.uriObj != null ? item.uriObj.name : null;
|
|
15
|
+
item.color = item.uriObj != null ? item.uriObj.color : null;
|
|
16
|
+
item.iconObj = item.uriObj != null ? item.uriObj.iconObj : null;
|
|
16
17
|
|
|
17
18
|
delete item.uri;
|
|
18
19
|
delete item.uriObj;
|
|
@@ -9,10 +9,11 @@ class FlowCardTrigger extends FlowCardTriggerV3 {
|
|
|
9
9
|
|
|
10
10
|
item.id = `${item.uri}:${item.id}`;
|
|
11
11
|
item.ownerUri = item.uri;
|
|
12
|
-
|
|
13
|
-
item.
|
|
14
|
-
item.
|
|
15
|
-
item.
|
|
12
|
+
// I dont know how uriObj can be null but it is possible.
|
|
13
|
+
item.ownerId = item.uriObj != null ? item.uriObj.id : null;
|
|
14
|
+
item.ownerName = item.uriObj != null ? item.uriObj.name : null;
|
|
15
|
+
item.color = item.uriObj != null ? item.uriObj.color : null;
|
|
16
|
+
item.iconObj = item.uriObj != null ? item.uriObj.iconObj : null;
|
|
16
17
|
|
|
17
18
|
delete item.uri;
|
|
18
19
|
delete item.uriObj;
|
|
@@ -275,7 +275,7 @@ class Manager extends EventEmitter {
|
|
|
275
275
|
if (this.homey.isConnected() && $socket === true) {
|
|
276
276
|
result = await Util.timeout(new Promise((resolve, reject) => {
|
|
277
277
|
this.__debug(`IO ${operationId}`);
|
|
278
|
-
this.homey.
|
|
278
|
+
this.homey.__homeySocket.emit('api', {
|
|
279
279
|
args,
|
|
280
280
|
operation: operationId,
|
|
281
281
|
uri: this.uri,
|
|
@@ -480,11 +480,17 @@ class Manager extends EventEmitter {
|
|
|
480
480
|
this.__debug(`onDisconnect Reason:${reason}`);
|
|
481
481
|
this.__connected = false;
|
|
482
482
|
|
|
483
|
+
// Disable for now. We should probably only set the cache to invalid.
|
|
484
|
+
|
|
483
485
|
// Clear CRUD Item cache
|
|
484
|
-
for (const itemId of Object.keys(this.__cache)) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
}
|
|
486
|
+
// for (const itemId of Object.keys(this.__cache)) {
|
|
487
|
+
// this.__cache[itemId] = {};
|
|
488
|
+
// this.__cacheAllComplete[itemId] = false;
|
|
489
|
+
// }
|
|
490
|
+
},
|
|
491
|
+
onReconnect: () => {
|
|
492
|
+
this.__debug(`onReconnect`);
|
|
493
|
+
this.__connected = true;
|
|
488
494
|
},
|
|
489
495
|
onEvent: (event, data) => {
|
|
490
496
|
this.__debug('onEvent', event);
|
|
@@ -561,7 +567,7 @@ class Manager extends EventEmitter {
|
|
|
561
567
|
}
|
|
562
568
|
|
|
563
569
|
/**
|
|
564
|
-
*
|
|
570
|
+
* Disconnect from this manager's Socket.io namespace.
|
|
565
571
|
* @returns {Promise<void>}
|
|
566
572
|
*/
|
|
567
573
|
async disconnect() {
|
|
@@ -102,12 +102,6 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
102
102
|
writable: true,
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
Object.defineProperty(this, '__connected', {
|
|
106
|
-
value: false,
|
|
107
|
-
enumerable: false,
|
|
108
|
-
writable: true,
|
|
109
|
-
});
|
|
110
|
-
|
|
111
105
|
this.generateManagersFromSpecification();
|
|
112
106
|
}
|
|
113
107
|
|
|
@@ -559,7 +553,7 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
559
553
|
* @returns {Boolean}
|
|
560
554
|
*/
|
|
561
555
|
isConnected() {
|
|
562
|
-
return this.
|
|
556
|
+
return this.__homeySocket && this.__homeySocket.connected;
|
|
563
557
|
}
|
|
564
558
|
|
|
565
559
|
async subscribe(uri, {
|
|
@@ -572,12 +566,12 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
572
566
|
this.__debug('subscribe', uri);
|
|
573
567
|
|
|
574
568
|
await this.connect();
|
|
575
|
-
await new Promise((resolve, reject) => {
|
|
576
|
-
this.
|
|
569
|
+
await Util.timeout(new Promise((resolve, reject) => {
|
|
570
|
+
this.__homeySocket.once('disconnect', (reason) => {
|
|
577
571
|
reject(new Error(reason));
|
|
578
572
|
});
|
|
579
573
|
this.__debug('subscribing', uri);
|
|
580
|
-
this.
|
|
574
|
+
this.__homeySocket.emit('subscribe', uri, err => {
|
|
581
575
|
if (err) {
|
|
582
576
|
this.__debug('Failed to subscribe', uri, err);
|
|
583
577
|
return reject(err)
|
|
@@ -586,13 +580,13 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
586
580
|
this.__debug('subscribed', uri);
|
|
587
581
|
return resolve();
|
|
588
582
|
});
|
|
589
|
-
});
|
|
583
|
+
}), 5000, `Failed to subscribe to ${uri} (Timeout after 5000ms).`);
|
|
590
584
|
|
|
591
585
|
// On Connect
|
|
592
586
|
const __onEvent = (event, data) => {
|
|
593
587
|
onEvent(event, data);
|
|
594
588
|
};
|
|
595
|
-
this.
|
|
589
|
+
this.__homeySocket.on(uri, __onEvent);
|
|
596
590
|
|
|
597
591
|
onConnect();
|
|
598
592
|
|
|
@@ -600,43 +594,48 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
600
594
|
const __onDisconnect = reason => {
|
|
601
595
|
onDisconnect(reason);
|
|
602
596
|
};
|
|
603
|
-
this.
|
|
597
|
+
this.__socket.on('disconnect', __onDisconnect);
|
|
604
598
|
|
|
605
599
|
// On Reconnect
|
|
606
600
|
const __onReconnect = () => {
|
|
607
601
|
Promise.resolve().then(async () => {
|
|
608
602
|
await this.connect();
|
|
609
|
-
await new Promise((resolve, reject) => {
|
|
610
|
-
this.
|
|
603
|
+
await Util.timeout(new Promise((resolve, reject) => {
|
|
604
|
+
this.__homeySocket.once('disconnect', (reason) => {
|
|
605
|
+
reject(new Error(reason));
|
|
606
|
+
});
|
|
607
|
+
this.__debug('subscribing', uri);
|
|
608
|
+
this.__homeySocket.emit('subscribe', uri, err => {
|
|
611
609
|
if (err) {
|
|
612
610
|
this.__debug('Failed to subscribe', uri, err);
|
|
613
611
|
return reject(err)
|
|
614
612
|
}
|
|
615
|
-
|
|
613
|
+
|
|
614
|
+
this.__debug('subscribed', uri);
|
|
616
615
|
return resolve();
|
|
617
616
|
});
|
|
618
|
-
});
|
|
617
|
+
}), 5000, `Failed to subscribe to ${uri} (Timeout after 5000ms).`);
|
|
619
618
|
|
|
620
|
-
this.
|
|
619
|
+
this.__homeySocket.on(uri, __onEvent);
|
|
621
620
|
|
|
622
621
|
onReconnect();
|
|
623
622
|
}).catch(err => onReconnectError(err));
|
|
624
623
|
};
|
|
625
|
-
this.
|
|
624
|
+
this.__socket.on('reconnect', __onReconnect);
|
|
626
625
|
|
|
627
626
|
return {
|
|
628
627
|
unsubscribe: () => {
|
|
629
|
-
this.
|
|
630
|
-
this.
|
|
631
|
-
this.
|
|
632
|
-
this.
|
|
628
|
+
this.__homeySocket.emit('unsubscribe', uri);
|
|
629
|
+
this.__homeySocket.removeListener(uri, __onEvent);
|
|
630
|
+
this.__socket.removeListener('disconnect', __onDisconnect);
|
|
631
|
+
this.__socket.removeListener('reconnect', __onReconnect);
|
|
633
632
|
},
|
|
634
633
|
};
|
|
635
634
|
}
|
|
636
635
|
|
|
637
636
|
async connect() {
|
|
638
|
-
if (!this.
|
|
639
|
-
this.
|
|
637
|
+
if (!this.__connectPromise) {
|
|
638
|
+
this.__connectPromise = Promise.resolve().then(async () => {
|
|
640
639
|
// Ensure Base URL
|
|
641
640
|
const baseUrl = await this.baseUrl;
|
|
642
641
|
|
|
@@ -645,8 +644,9 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
645
644
|
|
|
646
645
|
return new Promise((resolve, reject) => {
|
|
647
646
|
this.__debug(`SocketIOClient ${baseUrl}`);
|
|
648
|
-
|
|
649
|
-
|
|
647
|
+
|
|
648
|
+
this.__socket = SocketIOClient(baseUrl, {
|
|
649
|
+
autoConnect: false,
|
|
650
650
|
transports: ['websocket'],
|
|
651
651
|
transportOptions: {
|
|
652
652
|
pingTimeout: 8000,
|
|
@@ -655,65 +655,40 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
655
655
|
reconnection: true,
|
|
656
656
|
});
|
|
657
657
|
|
|
658
|
-
this.
|
|
658
|
+
this.__socket.on('disconnect', reason => {
|
|
659
659
|
this.__debug('SocketIOClient.onDisconnect', reason);
|
|
660
|
-
this.__connected = false;
|
|
661
|
-
|
|
662
|
-
if (this.__ioNamespace) {
|
|
663
|
-
this.__ioNamespace.disconnect();
|
|
664
|
-
this.__ioNamespace.destroy();
|
|
665
|
-
this.__ioNamespace.removeAllListeners();
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
if (reason === 'io server disconnect') {
|
|
669
|
-
// The disconnect was initiated by the server.
|
|
670
|
-
this.__io.connect();
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
reject(new Error('Disconnected'));
|
|
674
660
|
});
|
|
675
661
|
|
|
676
|
-
this.
|
|
662
|
+
this.__socket.on('error', err => {
|
|
677
663
|
this.__debug('SocketIOClient.onError', err.message);
|
|
678
664
|
});
|
|
679
665
|
|
|
680
|
-
this.
|
|
666
|
+
this.__socket.on('reconnect', () => {
|
|
681
667
|
this.__debug('SocketIOClient.onReconnect');
|
|
682
|
-
this.__handshakeClient()
|
|
683
|
-
.then(() => {
|
|
684
|
-
this.__debug('SocketIOClient.onReconnect.onHandshakeClientSuccess');
|
|
685
|
-
this.__connected = true;
|
|
686
|
-
resolve();
|
|
687
|
-
})
|
|
688
|
-
.catch(err => {
|
|
689
|
-
this.__debug('SocketIOClient.onReconnect.onHandshakeClientError', err.message);
|
|
690
|
-
reject(err);
|
|
691
|
-
});
|
|
692
668
|
});
|
|
693
669
|
|
|
694
|
-
this.
|
|
670
|
+
this.__socket.on('reconnect_attempt', () => {
|
|
695
671
|
this.__debug(`SocketIOClient.onReconnectAttempt`);
|
|
696
672
|
});
|
|
697
673
|
|
|
698
|
-
this.
|
|
674
|
+
this.__socket.on('reconnecting', attempt => {
|
|
699
675
|
this.__debug(`SocketIOClient.onReconnecting (Attempt #${attempt})`);
|
|
700
676
|
});
|
|
701
677
|
|
|
702
|
-
this.
|
|
678
|
+
this.__socket.on('reconnect_error', err => {
|
|
703
679
|
this.__debug('SocketIOClient.onReconnectError', err.message);
|
|
704
680
|
});
|
|
705
681
|
|
|
706
|
-
this.
|
|
682
|
+
this.__socket.on('connect_error', err => {
|
|
707
683
|
this.__debug('SocketIOClient.onConnectError', err.message);
|
|
708
684
|
reject(err);
|
|
709
685
|
});
|
|
710
686
|
|
|
711
|
-
this.
|
|
687
|
+
this.__socket.on('connect', () => {
|
|
712
688
|
this.__debug('SocketIOClient.onConnect');
|
|
713
689
|
this.__handshakeClient()
|
|
714
690
|
.then(() => {
|
|
715
691
|
this.__debug('SocketIOClient.onConnect.onHandshakeClientSuccess');
|
|
716
|
-
this.__connected = true;
|
|
717
692
|
resolve();
|
|
718
693
|
})
|
|
719
694
|
.catch(err => {
|
|
@@ -721,34 +696,39 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
721
696
|
reject(err);
|
|
722
697
|
});
|
|
723
698
|
});
|
|
724
|
-
|
|
699
|
+
|
|
700
|
+
this.__socket.open();
|
|
725
701
|
});
|
|
726
702
|
});
|
|
727
703
|
|
|
728
|
-
this.
|
|
704
|
+
this.__connectPromise.catch(err => {
|
|
729
705
|
this.__debug('SocketIOClient Error', err.message);
|
|
706
|
+
delete this.__connectPromise;
|
|
730
707
|
});
|
|
731
708
|
}
|
|
732
709
|
|
|
733
|
-
return this.
|
|
710
|
+
return this.__connectPromise;
|
|
734
711
|
}
|
|
735
712
|
|
|
736
713
|
async disconnect() {
|
|
737
|
-
|
|
714
|
+
// Should we wait for connect here?
|
|
715
|
+
|
|
716
|
+
if (this.__socket) {
|
|
738
717
|
await new Promise(resolve => {
|
|
739
|
-
this.
|
|
740
|
-
this.
|
|
741
|
-
this.
|
|
742
|
-
this.
|
|
718
|
+
this.__socket.once('disconnect', resolve());
|
|
719
|
+
this.__socket.disconnect();
|
|
720
|
+
this.__socket.removeAllListeners();
|
|
721
|
+
this.__socket = null;
|
|
743
722
|
});
|
|
744
723
|
}
|
|
724
|
+
|
|
745
725
|
// TODO todo what?
|
|
746
726
|
}
|
|
747
727
|
|
|
748
728
|
destroy() {
|
|
749
|
-
if (this.
|
|
750
|
-
this.
|
|
751
|
-
this.
|
|
729
|
+
if (this.__socket) {
|
|
730
|
+
this.__socket.removeAllListeners();
|
|
731
|
+
this.__socket.close();
|
|
752
732
|
}
|
|
753
733
|
}
|
|
754
734
|
|
|
@@ -756,7 +736,7 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
756
736
|
this.__debug('__handshakeClient');
|
|
757
737
|
|
|
758
738
|
return new Promise((resolve, reject) => {
|
|
759
|
-
this.
|
|
739
|
+
this.__socket.emit('handshakeClient', {
|
|
760
740
|
token: this.__token,
|
|
761
741
|
homeyId: this.id,
|
|
762
742
|
}, (err, result) => {
|
|
@@ -772,7 +752,7 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
772
752
|
await this.login();
|
|
773
753
|
|
|
774
754
|
return new Promise((resolve, reject) => {
|
|
775
|
-
this.
|
|
755
|
+
this.__socket.emit('handshakeClient', {
|
|
776
756
|
token: this.__token,
|
|
777
757
|
homeyId: this.id,
|
|
778
758
|
}, (err, result) => {
|
|
@@ -788,43 +768,35 @@ class HomeyAPIV3 extends HomeyAPI {
|
|
|
788
768
|
this.__debug('SocketIOClient.onHandshakeClientSuccess', `Namespace: ${namespace}`);
|
|
789
769
|
|
|
790
770
|
return new Promise((resolve, reject) => {
|
|
791
|
-
this.
|
|
792
|
-
|
|
793
|
-
this.__debug(this.__ioNamespace);
|
|
771
|
+
this.__homeySocket = this.__socket.io.socket(namespace);
|
|
794
772
|
|
|
795
|
-
|
|
796
|
-
if (this.__ioNamespace.connected) {
|
|
797
|
-
this.__debug(`SocketIOClient.Namespace[${namespace}].connected`);
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
this.__ioNamespace.once('connect', () => {
|
|
773
|
+
this.__homeySocket.once('connect', () => {
|
|
801
774
|
this.__debug(`SocketIOClient.Namespace[${namespace}].onConnect`);
|
|
802
775
|
resolve();
|
|
803
776
|
});
|
|
804
777
|
|
|
805
|
-
this.
|
|
778
|
+
this.__homeySocket.once('connect_error', err => {
|
|
806
779
|
this.__debug(`SocketIOClient.Namespace[${namespace}].onConnectError`, err.message);
|
|
807
780
|
reject(err);
|
|
808
781
|
});
|
|
809
782
|
|
|
810
|
-
this.
|
|
783
|
+
this.__homeySocket.on('disconnect', reason => {
|
|
784
|
+
this.__debug(`SocketIOClient.Namespace[${namespace}].onDisconnect`, reason);
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
this.__homeySocket.on('reconnecting', attempt => {
|
|
811
788
|
this.__debug(`SocketIOClient.Namespace[${namespace}].onReconnecting (Attempt #${attempt})`);
|
|
812
789
|
});
|
|
813
790
|
|
|
814
|
-
this.
|
|
791
|
+
this.__homeySocket.on('reconnect', () => {
|
|
815
792
|
this.__debug(`SocketIOClient.Namespace[${namespace}].onReconnect`);
|
|
816
793
|
});
|
|
817
794
|
|
|
818
|
-
this.
|
|
795
|
+
this.__homeySocket.on('reconnect_error', err => {
|
|
819
796
|
this.__debug(`SocketIOClient.Namespace[${namespace}].onReconnectError`, err.message);
|
|
820
797
|
});
|
|
821
798
|
|
|
822
|
-
this.
|
|
823
|
-
this.__debug(`SocketIOClient.Namespace[${namespace}].onDisconnect`, reason);
|
|
824
|
-
});
|
|
825
|
-
|
|
826
|
-
this.__debug(`SocketIOClient.Namespace[${namespace}].disconnected`, this.__ioNamespace.disconnected);
|
|
827
|
-
this.__debug(`SocketIOClient.Namespace[${namespace}].connected`, this.__ioNamespace.connected);
|
|
799
|
+
this.__homeySocket.open();
|
|
828
800
|
});
|
|
829
801
|
});
|
|
830
802
|
}
|
package/lib/Util.js
CHANGED
|
@@ -56,16 +56,24 @@ class Util {
|
|
|
56
56
|
static async timeout(promise, timeoutMillis = 5000, message = `Timeout after ${timeoutMillis}ms`) {
|
|
57
57
|
const timeoutError = new APIErrorTimeout(message);
|
|
58
58
|
let timeoutRef;
|
|
59
|
-
|
|
59
|
+
|
|
60
|
+
const returnPromise = Promise.race([
|
|
60
61
|
promise,
|
|
61
62
|
new Promise((_, reject) => {
|
|
62
63
|
timeoutRef = setTimeout(() => {
|
|
63
64
|
reject(timeoutError);
|
|
64
65
|
}, timeoutMillis);
|
|
65
66
|
}),
|
|
66
|
-
])
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
returnPromise
|
|
70
|
+
// eslint-disable-next-line no-unused-vars
|
|
71
|
+
.catch(err => { })
|
|
72
|
+
.finally(() => {
|
|
73
|
+
clearTimeout(timeoutRef);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return returnPromise;
|
|
69
77
|
}
|
|
70
78
|
|
|
71
79
|
/**
|