homey-api 3.0.0-rc.9 → 3.0.0
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/README.md +1 -1
- package/assets/specifications/AthomCloudAPI.json +16 -0
- package/assets/specifications/HomeyAPIV3Local.json +173 -7
- package/assets/types/homey-api.d.ts +418 -223
- package/assets/types/homey-api.private.d.ts +464 -223
- package/index.browser.js +1 -0
- package/index.js +39 -20
- package/lib/API.js +6 -0
- package/lib/AthomCloudAPI/StorageAdapter.js +1 -0
- package/lib/HomeyAPI/HomeyAPI.js +108 -9
- package/lib/HomeyAPI/HomeyAPIV1.js +8 -0
- package/lib/HomeyAPI/HomeyAPIV2/ManagerDevices/Device.js +2 -1
- package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/AdvancedFlow.js +3 -1
- package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/Flow.js +2 -0
- package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow.js +1 -1
- package/lib/HomeyAPI/HomeyAPIV2.js +8 -0
- package/lib/HomeyAPI/HomeyAPIV3/Manager.js +10 -4
- package/lib/HomeyAPI/HomeyAPIV3/ManagerDevices/Device.js +2 -0
- package/lib/HomeyAPI/HomeyAPIV3/ManagerDevices/DeviceCapability.js +3 -3
- package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/AdvancedFlow.js +119 -0
- package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/Flow.js +96 -1
- package/lib/HomeyAPI/HomeyAPIV3/ManagerFlowToken/FlowToken.js +8 -3
- package/lib/HomeyAPI/HomeyAPIV3.js +22 -17
- package/lib/HomeyAPI/HomeyAPIV3Cloud.js +8 -0
- package/lib/HomeyAPI/HomeyAPIV3Local/ManagerDevkit.js +32 -0
- package/lib/HomeyAPI/HomeyAPIV3Local.js +14 -0
- package/package.json +4 -3
package/index.browser.js
CHANGED
|
@@ -11,3 +11,4 @@ global.HomeyCloudAPI = require('./lib/HomeyCloudAPI');
|
|
|
11
11
|
global.HomeyAPIV2 = require('./lib/HomeyAPI/HomeyAPIV2');
|
|
12
12
|
global.HomeyAPIV3Local = require('./lib/HomeyAPI/HomeyAPIV3Local');
|
|
13
13
|
global.HomeyAPIV3Cloud = require('./lib/HomeyAPI/HomeyAPIV3Cloud');
|
|
14
|
+
global.HomeyAPI = require('./lib/HomeyAPI/HomeyAPI');
|
package/index.js
CHANGED
|
@@ -2,23 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
-
module.exports = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
5
|
+
module.exports = {};
|
|
6
|
+
|
|
7
|
+
// Athom Cloud
|
|
8
|
+
module.exports.AthomAppsAPI = require('./lib/AthomAppsAPI');
|
|
9
|
+
module.exports.AthomBackupAPI = require('./lib/AthomBackupAPI');
|
|
10
|
+
module.exports.AthomCallbackAPI = require('./lib/AthomCallbackAPI');
|
|
11
|
+
module.exports.AthomCloudAPI = require('./lib/AthomCloudAPI');
|
|
12
|
+
module.exports.AthomConnectAPI = require('./lib/AthomConnectAPI');
|
|
13
|
+
module.exports.AthomDNSAPI = require('./lib/AthomDNSAPI');
|
|
14
|
+
module.exports.AthomFirmwareAPI = require('./lib/AthomFirmwareAPI');
|
|
15
|
+
module.exports.AthomFlowAPI = require('./lib/AthomFlowAPI');
|
|
16
|
+
module.exports.AthomGeolocateAPI = require('./lib/AthomGeolocateAPI');
|
|
17
|
+
module.exports.AthomIconsAPI = require('./lib/AthomIconsAPI');
|
|
18
|
+
module.exports.AthomInfraredAPI = require('./lib/AthomInfraredAPI');
|
|
19
|
+
module.exports.AthomNotificationsAPI = require('./lib/AthomNotificationsAPI');
|
|
20
|
+
module.exports.AthomSetupAPI = require('./lib/AthomSetupAPI');
|
|
21
|
+
module.exports.AthomStoreAPI = require('./lib/AthomStoreAPI');
|
|
22
|
+
module.exports.AthomWeatherAPI = require('./lib/AthomWeatherAPI');
|
|
23
|
+
module.exports.AthomWebhooksAPI = require('./lib/AthomWebhooksAPI');
|
|
24
|
+
|
|
25
|
+
// Homey Cloud
|
|
26
|
+
module.exports.HomeyCloudAPI = require('./lib/HomeyCloudAPI');
|
|
27
|
+
|
|
28
|
+
// Homey API
|
|
29
|
+
module.exports.HomeyAPI = require('./lib/HomeyAPI/HomeyAPI');
|
|
30
|
+
module.exports.HomeyAPIV1 = require('./lib/HomeyAPI/HomeyAPIV1');
|
|
31
|
+
module.exports.HomeyAPIV2 = require('./lib/HomeyAPI/HomeyAPIV2');
|
|
32
|
+
module.exports.HomeyAPIV3 = require('./lib/HomeyAPI/HomeyAPIV3');
|
|
33
|
+
module.exports.HomeyAPIV3Local = require('./lib/HomeyAPI/HomeyAPIV3Local');
|
|
34
|
+
module.exports.HomeyAPIV3Cloud = require('./lib/HomeyAPI/HomeyAPIV3Cloud');
|
|
35
|
+
|
|
36
|
+
// APIError
|
|
37
|
+
module.exports.APIError = require('./lib/APIError');
|
|
38
|
+
module.exports.APIErrorHomeyOffline = require('./lib/APIErrorHomeyOffline');
|
|
39
|
+
module.exports.APIErrorNotFound = require('./lib/APIErrorNotFound');
|
|
40
|
+
module.exports.APIErrorTimeout = require('./lib/APIErrorTimeout');
|
|
41
|
+
|
|
42
|
+
// Util
|
|
43
|
+
module.exports.Util = require('./lib/Util');
|
package/lib/API.js
CHANGED
|
@@ -73,6 +73,7 @@ class API {
|
|
|
73
73
|
$body = {},
|
|
74
74
|
$query = {},
|
|
75
75
|
$headers = {},
|
|
76
|
+
$token = null,
|
|
76
77
|
...args
|
|
77
78
|
} = {}) => {
|
|
78
79
|
let pathWithParameters = operation.path;
|
|
@@ -89,6 +90,11 @@ class API {
|
|
|
89
90
|
value = this.__secret;
|
|
90
91
|
}
|
|
91
92
|
|
|
93
|
+
// Set Authorization header if $token is provided
|
|
94
|
+
if (typeof $token === 'string') {
|
|
95
|
+
headers.Authorization = `Bearer ${$token}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
92
98
|
// Validate the parameter
|
|
93
99
|
if ($validate) {
|
|
94
100
|
if (parameter.required === true && typeof value === 'undefined') {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Abstract storage adapter. To be extended by your own, or {@link AthomCloudAPI.StorageAdapterBrowser} or {@link AthomCloudAPI.StorageAdapterMemory}.
|
|
5
|
+
* When creating your own, make sure to overload the `get` and `set` methods.
|
|
5
6
|
* @class
|
|
6
7
|
* @memberof AthomCloudAPI
|
|
7
8
|
*/
|
package/lib/HomeyAPI/HomeyAPI.js
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const Util = require('../Util');
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
6
|
+
* An authenticated Homey API. Do not construct this class manually.
|
|
7
|
+
* @class
|
|
5
8
|
* @hideconstructor
|
|
6
9
|
*/
|
|
7
10
|
class HomeyAPI {
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
|
-
*
|
|
13
|
+
* Platforms
|
|
14
|
+
* @static
|
|
15
|
+
* @property {object} PLATFORMS
|
|
16
|
+
* @property {string} PLATFORMS.LOCAL - Homey (2016 — 2019) & Homey Pro (2019 — 2023)
|
|
17
|
+
* @property {string} PLATFORMS.CLOUD - Homey Cloud
|
|
18
|
+
*/
|
|
19
|
+
static PLATFORMS = {
|
|
20
|
+
LOCAL: 'local',
|
|
21
|
+
CLOUD: 'cloud',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Discovery Strategies
|
|
11
26
|
* @static
|
|
12
27
|
* @property {object} DISCOVERY_STRATEGIES
|
|
13
28
|
* @property {string} DISCOVERY_STRATEGIES.CLOUD - Cloud HTTPS, e.g. `https://abcdef.connect.athom.com`.
|
|
@@ -25,8 +40,8 @@ class HomeyAPI {
|
|
|
25
40
|
};
|
|
26
41
|
|
|
27
42
|
constructor({
|
|
28
|
-
api,
|
|
29
|
-
properties,
|
|
43
|
+
api = null,
|
|
44
|
+
properties = {},
|
|
30
45
|
debug = () => { },
|
|
31
46
|
}) {
|
|
32
47
|
// Set Debug Enabled
|
|
@@ -45,14 +60,28 @@ class HomeyAPI {
|
|
|
45
60
|
|
|
46
61
|
// Set ID
|
|
47
62
|
Object.defineProperty(this, 'id', {
|
|
48
|
-
value: properties.id
|
|
63
|
+
value: properties.id ?? properties._id ?? null,
|
|
49
64
|
enumerable: true,
|
|
50
65
|
writable: true,
|
|
51
66
|
});
|
|
52
67
|
|
|
53
68
|
// Set Version
|
|
54
69
|
Object.defineProperty(this, 'version', {
|
|
55
|
-
value: properties.softwareVersion
|
|
70
|
+
value: properties.softwareVersion ?? null,
|
|
71
|
+
enumerable: true,
|
|
72
|
+
writable: true,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Set Name
|
|
76
|
+
Object.defineProperty(this, 'name', {
|
|
77
|
+
value: properties.name ?? null,
|
|
78
|
+
enumerable: true,
|
|
79
|
+
writable: true,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Set Language
|
|
83
|
+
Object.defineProperty(this, 'Language', {
|
|
84
|
+
value: properties.Language ?? null,
|
|
56
85
|
enumerable: true,
|
|
57
86
|
writable: true,
|
|
58
87
|
});
|
|
@@ -65,6 +94,10 @@ class HomeyAPI {
|
|
|
65
94
|
});
|
|
66
95
|
}
|
|
67
96
|
|
|
97
|
+
get _id() {
|
|
98
|
+
throw new Error('HomeyAPI._id is not supported, please use HomeyAPI.id');
|
|
99
|
+
}
|
|
100
|
+
|
|
68
101
|
__debug(...props) {
|
|
69
102
|
if (!this.__debugFunction) return;
|
|
70
103
|
this.__debugFunction(...props);
|
|
@@ -126,10 +159,29 @@ class HomeyAPI {
|
|
|
126
159
|
}
|
|
127
160
|
|
|
128
161
|
/**
|
|
129
|
-
*
|
|
162
|
+
* Creates a {@link HomeyAPIV3Local} or {@link HomeyAPIV2} instance for use in the Apps SDK.
|
|
130
163
|
* @param {Object} opts
|
|
131
|
-
* @param {Homey} opts.homey — Homey instance
|
|
132
|
-
* @param {Function|null} opts.debug — Debug function, defaults to `null
|
|
164
|
+
* @param {Homey} opts.homey — Homey (Apps SDK) instance.
|
|
165
|
+
* @param {Function|null} opts.debug — Debug function, defaults to `null`.
|
|
166
|
+
* @example
|
|
167
|
+
* const { HomeyAPI } = require('homey-api');
|
|
168
|
+
*
|
|
169
|
+
* module.exports = class MyApp extends Homey.App {
|
|
170
|
+
*
|
|
171
|
+
* async onInit() {
|
|
172
|
+
* // Create a HomeyAPI instance. Ensure your app has the `homey:manager:api` permission.
|
|
173
|
+
* this.homeyApi = await HomeyAPI.createAppAPI({
|
|
174
|
+
* homey: this.homey,
|
|
175
|
+
* });
|
|
176
|
+
*
|
|
177
|
+
* // Get all the devices, and log their names.
|
|
178
|
+
* const devices = await this.{@link HomeyAPIV3Local homeyApi}.{@link HomeyAPIV3Local.ManagerDevices devices}.{@link HomeyAPIV3Local.ManagerDevices#getDevices getDevices}();
|
|
179
|
+
* for(const device of Object.values(devices)) {
|
|
180
|
+
* this.log(device.name);
|
|
181
|
+
* }
|
|
182
|
+
* }
|
|
183
|
+
*
|
|
184
|
+
* }
|
|
133
185
|
*/
|
|
134
186
|
static async createAppAPI({
|
|
135
187
|
homey,
|
|
@@ -172,6 +224,53 @@ class HomeyAPI {
|
|
|
172
224
|
throw new Error(`Invalid Homey Platform Version: ${homey.platformVersion}`);
|
|
173
225
|
}
|
|
174
226
|
|
|
227
|
+
/**
|
|
228
|
+
* Creates a {@link HomeyAPIV3Local} instance for use in a project.
|
|
229
|
+
* @param {Object} opts
|
|
230
|
+
* @param {String} opts.address — The address of the Homey, e.g. `http://192.168.1.123:80`.
|
|
231
|
+
* @param {String} opts.token — A Personal Access Token created in the Homey Web App.
|
|
232
|
+
* @param {Function|null} opts.debug — Debug function, defaults to `null`.
|
|
233
|
+
* @example
|
|
234
|
+
* import { HomeyAPI } from 'homey-api';
|
|
235
|
+
* const homeyApi = await HomeyAPI.createLocalAPI({
|
|
236
|
+
* address: 'http://192.169.1.123',
|
|
237
|
+
* token: '<my_personal_access_token>',
|
|
238
|
+
* });
|
|
239
|
+
* const devices = await homeyApi.devices.getDevices();
|
|
240
|
+
*/
|
|
241
|
+
static async createLocalAPI({
|
|
242
|
+
address,
|
|
243
|
+
token,
|
|
244
|
+
debug = null,
|
|
245
|
+
}) {
|
|
246
|
+
if (!address) {
|
|
247
|
+
throw new Error('Invalid Address');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (!token) {
|
|
251
|
+
throw new Error('Invalid Token');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const res = await Util.fetch(`${address}/api/manager/system/ping`);
|
|
255
|
+
if (!res.headers.has('X-Homey-ID')) {
|
|
256
|
+
throw new Error(`No Homey Found At Address: ${address}`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const props = {
|
|
260
|
+
token,
|
|
261
|
+
debug: debug ?? function debug() { },
|
|
262
|
+
baseUrl: address,
|
|
263
|
+
strategy: [],
|
|
264
|
+
properties: {
|
|
265
|
+
id: res.headers.get('X-Homey-ID'),
|
|
266
|
+
softwareVersion: res.headers.get('X-Homey-Version'),
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const HomeyAPIV3Local = require('./HomeyAPIV3Local');
|
|
271
|
+
return new HomeyAPIV3Local(props);
|
|
272
|
+
}
|
|
273
|
+
|
|
175
274
|
}
|
|
176
275
|
|
|
177
276
|
module.exports = HomeyAPI;
|
|
@@ -5,9 +5,10 @@ const DeviceV3 = require('../../HomeyAPIV3/ManagerDevices/Device');
|
|
|
5
5
|
class Device extends DeviceV3 {
|
|
6
6
|
|
|
7
7
|
static transformGet(item) {
|
|
8
|
+
item.driverId = `${item.driverUri}:${item.driverId}`;
|
|
9
|
+
|
|
8
10
|
item = super.transformGet(item);
|
|
9
11
|
|
|
10
|
-
item.driverId = `${item.driverUri}:${item.driverId}`;
|
|
11
12
|
delete item.driverUri;
|
|
12
13
|
delete item.zoneName;
|
|
13
14
|
return item;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const AdvancedFlowV3 = require('../../HomeyAPIV3/ManagerFlow/
|
|
3
|
+
const AdvancedFlowV3 = require('../../HomeyAPIV3/ManagerFlow/AdvancedFlow');
|
|
4
4
|
|
|
5
5
|
class AdvancedFlow extends AdvancedFlowV3 {
|
|
6
6
|
|
|
@@ -11,6 +11,8 @@ class AdvancedFlow extends AdvancedFlowV3 {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
delete item.broken;
|
|
15
|
+
|
|
14
16
|
return item;
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -66,7 +66,7 @@ class ManagerFlow extends Manager {
|
|
|
66
66
|
return this.__cache['flowcardtrigger'][id];
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
return this.
|
|
69
|
+
return this.__super__getFlowCardTrigger({
|
|
70
70
|
id: id.split(':').reverse()[0],
|
|
71
71
|
uri: id.split(':', 3).join(':'),
|
|
72
72
|
});
|
|
@@ -213,6 +213,7 @@ class Manager extends EventEmitter {
|
|
|
213
213
|
// This is about ~2x faster than HTTP
|
|
214
214
|
if (this.homey.isConnected() && $socket === true) {
|
|
215
215
|
result = await Util.timeout(new Promise((resolve, reject) => {
|
|
216
|
+
this.__debug(`IO ${operationId}`);
|
|
216
217
|
this.homey.__ioNamespace.emit('api', {
|
|
217
218
|
args,
|
|
218
219
|
operation: operationId,
|
|
@@ -278,7 +279,8 @@ class Manager extends EventEmitter {
|
|
|
278
279
|
// Add all to cache
|
|
279
280
|
for (let item of Object.values(result)) {
|
|
280
281
|
item = Item.transformGet(item);
|
|
281
|
-
|
|
282
|
+
|
|
283
|
+
if (this.isConnected() && this.__cache[itemId][item.id]) {
|
|
282
284
|
items[item.id] = this.__cache[itemId][item.id];
|
|
283
285
|
items[item.id].__update(item);
|
|
284
286
|
} else {
|
|
@@ -316,7 +318,7 @@ class Manager extends EventEmitter {
|
|
|
316
318
|
let item = { ...result };
|
|
317
319
|
item = Item.transformGet(item);
|
|
318
320
|
|
|
319
|
-
if (this.__cache[itemId][item.id]) {
|
|
321
|
+
if (this.isConnected() && this.__cache[itemId][item.id]) {
|
|
320
322
|
item = this.__cache[itemId][item.id];
|
|
321
323
|
item.__update(item);
|
|
322
324
|
} else {
|
|
@@ -336,7 +338,7 @@ class Manager extends EventEmitter {
|
|
|
336
338
|
return item;
|
|
337
339
|
}
|
|
338
340
|
case 'deleteOne': {
|
|
339
|
-
if (this.__cache[itemId][args.id]) {
|
|
341
|
+
if (this.isConnected() && this.__cache[itemId][args.id]) {
|
|
340
342
|
this.__cache[itemId][args.id].destroy();
|
|
341
343
|
delete this.__cache[itemId][args.id];
|
|
342
344
|
}
|
|
@@ -422,7 +424,7 @@ class Manager extends EventEmitter {
|
|
|
422
424
|
});
|
|
423
425
|
this.__cache[itemId][data.id] = item;
|
|
424
426
|
|
|
425
|
-
|
|
427
|
+
return this.emit(event, item);
|
|
426
428
|
}
|
|
427
429
|
case 'update': {
|
|
428
430
|
data = Item.transformGet(data);
|
|
@@ -430,6 +432,7 @@ class Manager extends EventEmitter {
|
|
|
430
432
|
if (this.__cache[itemId][data.id]) {
|
|
431
433
|
const item = this.__cache[itemId][data.id];
|
|
432
434
|
item.__update(data);
|
|
435
|
+
return this.emit(event, item);
|
|
433
436
|
}
|
|
434
437
|
|
|
435
438
|
break;
|
|
@@ -441,6 +444,9 @@ class Manager extends EventEmitter {
|
|
|
441
444
|
const item = this.__cache[itemId][data.id];
|
|
442
445
|
item.__delete();
|
|
443
446
|
delete this.__cache[itemId][item.id];
|
|
447
|
+
return this.emit(event, {
|
|
448
|
+
id: item.id,
|
|
449
|
+
});
|
|
444
450
|
}
|
|
445
451
|
|
|
446
452
|
break;
|
|
@@ -198,6 +198,8 @@ class Device extends Item {
|
|
|
198
198
|
static transformGet(item) {
|
|
199
199
|
item = super.transformGet(item);
|
|
200
200
|
|
|
201
|
+
delete item.driverUri;
|
|
202
|
+
|
|
201
203
|
if (item.capabilitiesObj) {
|
|
202
204
|
for (const capabilityObj of Object.values(item.capabilitiesObj)) {
|
|
203
205
|
if (capabilityObj.lastUpdated) {
|
|
@@ -6,7 +6,7 @@ const EventEmitter = require('../../../EventEmitter');
|
|
|
6
6
|
/**
|
|
7
7
|
* @class
|
|
8
8
|
* @hideconstructor
|
|
9
|
-
* @memberof
|
|
9
|
+
* @memberof HomeyAPIV3.ManagerDevices.Device
|
|
10
10
|
*/
|
|
11
11
|
class DeviceCapability extends EventEmitter {
|
|
12
12
|
|
|
@@ -79,7 +79,7 @@ class DeviceCapability extends EventEmitter {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
* Destroy
|
|
82
|
+
* Destroy this capability listener, and if it's the last one, unsubscribe from the device's realtime events.
|
|
83
83
|
*/
|
|
84
84
|
destroy() {
|
|
85
85
|
this.emit('destroy');
|
|
@@ -139,7 +139,7 @@ class DeviceCapability extends EventEmitter {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
|
-
*
|
|
142
|
+
* Sets a new capability value.
|
|
143
143
|
* @param {boolean|number|string} value - The new capability value
|
|
144
144
|
* @param {object} opts
|
|
145
145
|
*/
|
|
@@ -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,3 +1,5 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
2
|
+
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
5
|
const Item = require('../Item');
|
|
@@ -9,7 +11,100 @@ class Flow extends Item {
|
|
|
9
11
|
* @returns Promise<Boolean>
|
|
10
12
|
*/
|
|
11
13
|
async isBroken() {
|
|
12
|
-
|
|
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;
|
|
13
108
|
}
|
|
14
109
|
|
|
15
110
|
}
|