homey-api 3.0.0-rc.2 → 3.0.0-rc.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.
Files changed (37) hide show
  1. package/assets/specifications/AthomCloudAPI.json +16 -0
  2. package/assets/specifications/HomeyAPIV3Local.json +365 -7
  3. package/assets/types/homey-api.d.ts +382 -59
  4. package/assets/types/homey-api.private.d.ts +428 -59
  5. package/index.browser.js +1 -0
  6. package/index.js +19 -20
  7. package/lib/HomeyAPI/HomeyAPI.js +58 -5
  8. package/lib/HomeyAPI/HomeyAPIV2/ManagerDevices/Capability.js +2 -2
  9. package/lib/HomeyAPI/HomeyAPIV2/ManagerDevices/Device.js +4 -3
  10. package/lib/HomeyAPI/HomeyAPIV2/ManagerDevices.js +0 -14
  11. package/lib/HomeyAPI/HomeyAPIV2/ManagerDrivers/Driver.js +2 -2
  12. package/lib/HomeyAPI/HomeyAPIV2/ManagerDrivers/PairSession.js +20 -0
  13. package/lib/HomeyAPI/HomeyAPIV2/ManagerDrivers.js +17 -0
  14. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/AdvancedFlow.js +19 -4
  15. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/Flow.js +27 -2
  16. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardAction.js +2 -2
  17. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardCondition.js +2 -2
  18. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardTrigger.js +2 -2
  19. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow.js +37 -14
  20. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlowToken/FlowToken.js +3 -3
  21. package/lib/HomeyAPI/HomeyAPIV2/ManagerInsights/Log.js +2 -3
  22. package/lib/HomeyAPI/HomeyAPIV2/ManagerInsights.js +17 -0
  23. package/lib/HomeyAPI/HomeyAPIV3/Item.js +14 -1
  24. package/lib/HomeyAPI/HomeyAPIV3/Manager.js +34 -46
  25. package/lib/HomeyAPI/HomeyAPIV3/ManagerDevices/Device.js +14 -12
  26. package/lib/HomeyAPI/HomeyAPIV3/ManagerDevices/DeviceCapability.js +1 -1
  27. package/lib/HomeyAPI/HomeyAPIV3/ManagerDrivers/PairSession.js +9 -0
  28. package/lib/HomeyAPI/HomeyAPIV3/ManagerDrivers.js +2 -0
  29. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/AdvancedFlow.js +119 -0
  30. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/Flow.js +103 -0
  31. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/FlowCard.js +8 -0
  32. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlowToken/FlowToken.js +12 -4
  33. package/lib/HomeyAPI/HomeyAPIV3/ManagerInsights/Log.js +14 -0
  34. package/lib/HomeyAPI/HomeyAPIV3.js +8 -8
  35. package/lib/HomeyAPI/HomeyAPIV3Local/ManagerDevkit.js +32 -0
  36. package/lib/HomeyAPI/HomeyAPIV3Local.js +6 -0
  37. package/package.json +2 -1
@@ -108,7 +108,7 @@ class DeviceCapability extends EventEmitter {
108
108
  const capabilityReference = this.device.capabilitiesObj && this.device.capabilitiesObj[this.id];
109
109
  if (capabilityReference) {
110
110
  capabilityReference.value = value;
111
- capabilityReference.lastUpdated = this.__lastChanged.toISOString();
111
+ capabilityReference.lastUpdated = this.__lastChanged;
112
112
  }
113
113
 
114
114
  this.__listener(value);
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const Item = require('../Item');
4
+
5
+ class PairSession extends Item {
6
+
7
+ }
8
+
9
+ module.exports = PairSession;
@@ -2,12 +2,14 @@
2
2
 
3
3
  const Manager = require('./Manager');
4
4
  const Driver = require('./ManagerDrivers/Driver');
5
+ const PairSession = require('./ManagerDrivers/PairSession');
5
6
 
6
7
  class ManagerDrivers extends Manager {
7
8
 
8
9
  static CRUD = {
9
10
  ...super.CRUD,
10
11
  Driver,
12
+ PairSession,
11
13
  }
12
14
 
13
15
  }
@@ -1,9 +1,128 @@
1
+ /* eslint-disable no-unused-vars */
2
+
1
3
  'use strict';
2
4
 
3
5
  const Item = require('../Item');
4
6
 
5
7
  class AdvancedFlow extends Item {
6
8
 
9
+ async isBroken() {
10
+ const managerFlow = this.homey.flow;
11
+ if (!managerFlow.isConnected()) {
12
+ throw new Error('Flow.isBroken requires ManagerFlow to be connected.');
13
+ }
14
+
15
+ const managerFlowToken = this.homey.flowtoken;
16
+ if (!managerFlowToken.isConnected()) {
17
+ throw new Error('Flow.isBroken requires ManagerFlowToken to be connected.');
18
+ }
19
+
20
+ // Array of local & global Token IDs.
21
+ // For example [ 'foo', 'homey:x:y|abc' ]
22
+ const tokenIds = [];
23
+
24
+ const checkToken = async tokenId => {
25
+ // If this is a global Token, fetch all FlowTokens
26
+ if (tokenId.includes('|')) {
27
+ const flowTokens = await managerFlowToken.getFlowTokens(); // Fill the cache
28
+ for (const flowTokenId of Object.keys(flowTokens)) {
29
+ tokenIds.push(flowTokenId);
30
+ }
31
+
32
+ tokenId = tokenId.replace('|', ':');
33
+ }
34
+
35
+ if (!tokenIds.includes(tokenId)) {
36
+ throw new Error(`Missing Token: ${tokenId}`);
37
+ }
38
+ };
39
+
40
+ const checkTokens = async card => {
41
+ // Check droptoken
42
+ if (card.droptoken) {
43
+ await checkToken(card.droptoken);
44
+ }
45
+
46
+ if (typeof card.args === 'object') {
47
+ for (const arg of Object.values(card.args)) {
48
+ if (typeof arg !== 'string') continue;
49
+ for (const [tokenMatch, tokenId] of arg.matchAll(/\[\[(.*?)\]\]/g)) {
50
+ await checkToken(tokenId);
51
+ }
52
+ }
53
+ }
54
+ };
55
+
56
+ // Check if FlowCards exist, and add Tokens
57
+ for (const [cardId, card] of Object.entries(this.cards)) {
58
+ switch (card.type) {
59
+ case 'trigger': {
60
+ try {
61
+ await managerFlow.getFlowCardTriggers(); // Fill the cache
62
+ const triggerCard = await this.manager.getFlowCardTrigger({ id: card.id });
63
+
64
+ // Add FlowCardTrigger.tokens to internal tokens cache
65
+ if (Array.isArray(triggerCard.tokens)) {
66
+ for (const token of Object.values(triggerCard.tokens)) {
67
+ tokenIds.push(`trigger::${cardId}::${token.id}`);
68
+ }
69
+ }
70
+
71
+ break;
72
+ } catch (err) {
73
+ this.__debug(err);
74
+ return true;
75
+ }
76
+ }
77
+ case 'condition': {
78
+ try {
79
+ await managerFlow.getFlowCardConditions(); // Fill the cache
80
+ const conditionCard = await this.manager.getFlowCardCondition({ id: card.id });
81
+
82
+ // Add Error Token
83
+ tokenIds.push(`card::${cardId}::error`);
84
+
85
+ break;
86
+ } catch (err) {
87
+ this.__debug(err);
88
+ return true;
89
+ }
90
+ }
91
+ case 'action': {
92
+ try {
93
+ await managerFlow.getFlowCardActions(); // Fill the cache
94
+ const actionCard = await this.manager.getFlowCardAction({ id: card.id });
95
+
96
+ // Add Error Token
97
+ tokenIds.push(`card::${cardId}::error`);
98
+
99
+ // Add FlowCardAction.tokens to internal tokens cache
100
+ if (Array.isArray(actionCard.tokens)) {
101
+ for (const token of Object.values(actionCard.tokens)) {
102
+ tokenIds.push(`action::${cardId}::${token.id}`);
103
+ }
104
+ }
105
+
106
+ break;
107
+ } catch (err) {
108
+ this.__debug(err);
109
+ return true;
110
+ }
111
+ }
112
+ default: {
113
+ // Do nothing
114
+ }
115
+ }
116
+ }
117
+
118
+ // Check Tokens
119
+ for (const card of Object.values(this.cards)) {
120
+ await checkTokens(card);
121
+ }
122
+
123
+ return false;
124
+ }
125
+
7
126
  }
8
127
 
9
128
  module.exports = AdvancedFlow;
@@ -1,9 +1,112 @@
1
+ /* eslint-disable no-unused-vars */
2
+
1
3
  'use strict';
2
4
 
3
5
  const Item = require('../Item');
4
6
 
5
7
  class Flow extends Item {
6
8
 
9
+ /**
10
+ * Check whether this Flow misses one or more {@link FlowCard} or {@link FlowToken}.
11
+ * @returns Promise<Boolean>
12
+ */
13
+ async isBroken() {
14
+ const managerFlow = this.homey.flow;
15
+ if (!managerFlow.isConnected()) {
16
+ throw new Error('Flow.isBroken requires ManagerFlow to be connected.');
17
+ }
18
+
19
+ const managerFlowToken = this.homey.flowtoken;
20
+ if (!managerFlowToken.isConnected()) {
21
+ throw new Error('Flow.isBroken requires ManagerFlowToken to be connected.');
22
+ }
23
+
24
+ // Array of local & global Token IDs.
25
+ // For example [ 'foo', 'homey:x:y|abc' ]
26
+ const tokenIds = [];
27
+
28
+ const checkToken = async tokenId => {
29
+ // If this is a global Token, fetch all FlowTokens
30
+ if (tokenId.includes('|')) {
31
+ const flowTokens = await managerFlowToken.getFlowTokens(); // Fill the cache
32
+ for (const flowTokenId of Object.keys(flowTokens)) {
33
+ tokenIds.push(flowTokenId);
34
+ }
35
+
36
+ tokenId = tokenId.replace('|', ':');
37
+ }
38
+
39
+ if (!tokenIds.includes(tokenId)) {
40
+ throw new Error(`Missing Token: ${tokenId}`);
41
+ }
42
+ };
43
+
44
+ const checkTokens = async card => {
45
+ // Check droptoken
46
+ if (card.droptoken) {
47
+ await checkToken(card.droptoken);
48
+ }
49
+
50
+ if (typeof card.args === 'object') {
51
+ for (const arg of Object.values(card.args)) {
52
+ if (typeof arg !== 'string') continue;
53
+ for (const [tokenMatch, tokenId] of arg.matchAll(/\[\[(.*?)\]\]/g)) {
54
+ await checkToken(tokenId);
55
+ }
56
+ }
57
+ }
58
+ };
59
+
60
+ // Check Trigger
61
+ if (this.trigger) {
62
+ try {
63
+ await managerFlow.getFlowCardTriggers(); // Fill the cache
64
+ const triggerCard = await this.manager.getFlowCardTrigger({ id: this.trigger.id });
65
+ await checkTokens(this.trigger);
66
+
67
+ // Add FlowCardTrigger.tokens to internal tokens cache
68
+ if (Array.isArray(triggerCard.tokens)) {
69
+ for (const tokenId of Object.keys(triggerCard.tokens)) {
70
+ tokenIds.push(tokenId);
71
+ }
72
+ }
73
+ } catch (err) {
74
+ this.__debug(err.message);
75
+ return true;
76
+ }
77
+ }
78
+
79
+ // Check Conditions
80
+ if (Array.isArray(this.conditions)) {
81
+ for (const condition of Object.values(this.conditions)) {
82
+ try {
83
+ await managerFlow.getFlowCardConditions(); // Fill the cache
84
+ const conditionCard = await this.manager.getFlowCardCondition({ id: condition.id });
85
+ await checkTokens(condition);
86
+ } catch (err) {
87
+ this.__debug(err.message);
88
+ return true;
89
+ }
90
+ }
91
+ }
92
+
93
+ // Check Actions
94
+ if (Array.isArray(this.actions)) {
95
+ for (const action of Object.values(this.actions)) {
96
+ try {
97
+ await managerFlow.getFlowCardActions(); // Fill the cache
98
+ const actionCard = await this.manager.getFlowCardAction({ id: action.id });
99
+ await checkTokens(action);
100
+ } catch (err) {
101
+ this.__debug(err.message);
102
+ return true;
103
+ }
104
+ }
105
+ }
106
+
107
+ return false;
108
+ }
109
+
7
110
  }
8
111
 
9
112
  module.exports = Flow;
@@ -4,6 +4,14 @@ const Item = require('../Item');
4
4
 
5
5
  class FlowCard extends Item {
6
6
 
7
+ static transformGet(item) {
8
+ item = super.transformGet(item);
9
+
10
+ delete item.ownerName; // Prepare for back-end change
11
+
12
+ return item;
13
+ }
14
+
7
15
  }
8
16
 
9
17
  module.exports = FlowCard;
@@ -4,11 +4,19 @@ const Item = require('../Item');
4
4
 
5
5
  class FlowToken extends Item {
6
6
 
7
- // TODO: Remove when back-end has removed these properties.
8
- static transform(item) {
9
- delete item.uri;
10
- delete item.id;
7
+ static transformGet(item) {
8
+ item = super.transformGet(item);
9
+
10
+ if (item.uri) {
11
+ item.id = `${item.uri}:${item.id}`;
12
+ delete item.uri;
13
+ }
14
+
15
+ // TODO: Remove when back-end has removed these properties.
11
16
  delete item.uriObj;
17
+ delete item.ownerName; // Prepare for back-end change
18
+
19
+ return item;
12
20
  }
13
21
 
14
22
  }
@@ -4,6 +4,20 @@ const Item = require('../Item');
4
4
 
5
5
  class Log extends Item {
6
6
 
7
+ async getEntries() {
8
+ return this.manager.getLogEntries({
9
+ id: this.id,
10
+ });
11
+ }
12
+
13
+ static transformGet(item) {
14
+ item = super.transformGet(item);
15
+
16
+ delete item.ownerName; // Prepare for back-end change
17
+
18
+ return item;
19
+ }
20
+
7
21
  }
8
22
 
9
23
  module.exports = Log;
@@ -378,32 +378,32 @@ class HomeyAPIV3 extends HomeyAPI {
378
378
  headers,
379
379
  path,
380
380
  body,
381
+ json = true,
381
382
  retryAfterRefresh = false,
382
383
  }) {
383
384
  const baseUrl = await this.baseUrl;
384
385
 
385
- method = method.toUpperCase();
386
+ method = String(method).toUpperCase();
386
387
 
387
388
  headers = {
388
389
  ...headers,
389
390
  'X-Homey-ID': this.id,
390
391
  };
391
392
 
392
- if (body) {
393
- headers['Content-Type'] = 'application/json';
394
- }
395
-
396
393
  if (this.__token) {
397
394
  headers['Authorization'] = `Bearer ${this.__token}`;
398
395
  }
399
396
 
397
+ if (body && json === true && ['PUT', 'POST'].includes(method)) {
398
+ headers['Content-Type'] = 'application/json';
399
+ body = JSON.stringify(body);
400
+ }
401
+
400
402
  this.__debug(method, `${baseUrl}${path}`);
401
403
  const res = await Util.timeout(Util.fetch(`${baseUrl}${path}`, {
402
404
  method,
403
405
  headers,
404
- body: ['PUT', 'POST'].includes(method) && typeof body !== 'undefined'
405
- ? JSON.stringify(body)
406
- : undefined,
406
+ body,
407
407
  }), $timeout);
408
408
 
409
409
  const resStatusCode = res.status;
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ const FormData = require('form-data');
4
+
5
+ const Manager = require('./Manager');
6
+
7
+ class ManagerDevkit extends Manager {
8
+
9
+ async runApp({
10
+ app, // Readable
11
+ env = {},
12
+ debug = false,
13
+ clean = false,
14
+ }) {
15
+ const form = new FormData();
16
+ form.append('app', app);
17
+ form.append('env', JSON.stringify(env));
18
+ form.append('debug', debug ? 'true' : 'false');
19
+ form.append('purgseSettings', clean ? 'true' : 'false');
20
+
21
+ return this.homey.call({
22
+ $timeout: 1000 * 60 * 5, // 5 minutes
23
+ method: 'POST',
24
+ path: '/api/manager/devkit/',
25
+ body: form,
26
+ json: false,
27
+ });
28
+ }
29
+
30
+ }
31
+
32
+ module.exports = ManagerDevkit;
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const HomeyAPIV3 = require('./HomeyAPIV3');
4
+ const ManagerDevkit = require('./HomeyAPIV3Local/ManagerDevkit');
4
5
 
5
6
  /**
6
7
  * This class is returned by {@link AthomCloudAPI.Homey#authenticate} for a Homey with `platform: 'local'` and `platformVersion: 1`.
@@ -11,6 +12,11 @@ const HomeyAPIV3 = require('./HomeyAPIV3');
11
12
  */
12
13
  class HomeyAPIV3Local extends HomeyAPIV3 {
13
14
 
15
+ static MANAGERS = {
16
+ ...HomeyAPIV3.MANAGERS,
17
+ ManagerDevkit,
18
+ };
19
+
14
20
  getSpecification() {
15
21
  // eslint-disable-next-line global-require
16
22
  return require('../../assets/specifications/HomeyAPIV3Local.json');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homey-api",
3
- "version": "3.0.0-rc.2",
3
+ "version": "3.0.0-rc.21",
4
4
  "description": "Homey API",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -46,6 +46,7 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "core-js": "^3.19.1",
49
+ "form-data": "^4.0.0",
49
50
  "node-fetch": "^2.6.7",
50
51
  "regenerator-runtime": "^0.13.9",
51
52
  "socket.io-client": "^2.5.0"