homey-api 1.10.17 → 3.0.0-rc.2

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 (53) hide show
  1. package/README.md +1 -1
  2. package/assets/types/homey-api.d.ts +47 -588
  3. package/assets/types/homey-api.private.d.ts +47 -648
  4. package/index.js +1 -1
  5. package/lib/APIErrorNotFound.js +20 -0
  6. package/lib/AthomCloudAPI/Homey.js +3 -1
  7. package/lib/EventEmitter.js +0 -6
  8. package/lib/HomeyAPI/HomeyAPI.js +49 -5
  9. package/lib/HomeyAPI/HomeyAPIErrorNotFound.js +21 -0
  10. package/lib/HomeyAPI/HomeyAPIV2/Manager.js +2 -575
  11. package/lib/HomeyAPI/HomeyAPIV2/ManagerDevices/Capability.js +20 -0
  12. package/lib/HomeyAPI/HomeyAPIV2/ManagerDevices/Device.js +18 -0
  13. package/lib/HomeyAPI/HomeyAPIV2/ManagerDevices.js +20 -3
  14. package/lib/HomeyAPI/HomeyAPIV2/ManagerDrivers/Driver.js +25 -0
  15. package/lib/HomeyAPI/HomeyAPIV2/ManagerDrivers.js +29 -0
  16. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/AdvancedFlow.js +17 -0
  17. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/Flow.js +34 -0
  18. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardAction.js +25 -0
  19. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardCondition.js +25 -0
  20. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardTrigger.js +25 -0
  21. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow.js +104 -0
  22. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlowToken/FlowToken.js +24 -0
  23. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlowToken.js +29 -0
  24. package/lib/HomeyAPI/HomeyAPIV2/ManagerInsights/Log.js +23 -0
  25. package/lib/HomeyAPI/HomeyAPIV2/ManagerInsights.js +29 -0
  26. package/lib/HomeyAPI/HomeyAPIV2.js +12 -716
  27. package/lib/HomeyAPI/HomeyAPIV3/Item.js +173 -2
  28. package/lib/HomeyAPI/HomeyAPIV3/Manager.js +531 -3
  29. package/lib/HomeyAPI/{HomeyAPIV2 → HomeyAPIV3/ManagerApps}/App.js +1 -1
  30. package/lib/HomeyAPI/{HomeyAPIV2 → HomeyAPIV3}/ManagerApps.js +4 -3
  31. package/lib/HomeyAPI/HomeyAPIV3/ManagerDevices/Capability.js +9 -0
  32. package/lib/HomeyAPI/{HomeyAPIV2 → HomeyAPIV3/ManagerDevices}/Device.js +78 -3
  33. package/lib/HomeyAPI/{HomeyAPIV2 → HomeyAPIV3/ManagerDevices}/DeviceCapability.js +3 -3
  34. package/lib/HomeyAPI/HomeyAPIV3/ManagerDevices.js +17 -0
  35. package/lib/HomeyAPI/HomeyAPIV3/ManagerDrivers/Driver.js +9 -0
  36. package/lib/HomeyAPI/HomeyAPIV3/ManagerDrivers.js +15 -0
  37. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/AdvancedFlow.js +9 -0
  38. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/Flow.js +9 -0
  39. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/FlowCard.js +9 -0
  40. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/FlowCardAction.js +9 -0
  41. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/FlowCardCondition.js +9 -0
  42. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/FlowCardTrigger.js +9 -0
  43. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow.js +12 -23
  44. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlowToken/FlowToken.js +16 -0
  45. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlowToken.js +15 -0
  46. package/lib/HomeyAPI/HomeyAPIV3/ManagerInsights/Log.js +9 -0
  47. package/lib/HomeyAPI/HomeyAPIV3/ManagerInsights.js +15 -0
  48. package/lib/HomeyAPI/HomeyAPIV3.js +728 -4
  49. package/lib/HomeyAPI/HomeyAPIV3Cloud.js +1 -1
  50. package/lib/HomeyAPI/HomeyAPIV3Local.js +1 -1
  51. package/package.json +1 -1
  52. package/lib/HomeyAPI/HomeyAPIApp.js +0 -127
  53. package/lib/HomeyAPI/HomeyAPIV2/Item.js +0 -177
@@ -1,14 +1,542 @@
1
+ /* eslint-disable no-multi-assign */
2
+
1
3
  'use strict';
2
4
 
3
- const HomeyAPIV2Manager = require('../HomeyAPIV2/Manager');
5
+ const EventEmitter = require('../../EventEmitter');
6
+ const Util = require('../../Util');
7
+ const HomeyAPIError = require('../HomeyAPIError');
8
+
9
+ // eslint-disable-next-line no-unused-vars
10
+ const Item = require('./Item');
4
11
 
5
12
  /**
6
13
  * @class
7
- * @extends HomeyAPIV2.Manager
8
14
  * @hideconstructor
9
15
  * @memberof HomeyAPIV3
10
16
  */
11
- class Manager extends HomeyAPIV2Manager {
17
+ class Manager extends EventEmitter {
18
+
19
+ static ID = null; // Set by HomeyAPIV3.js
20
+ static CRUD = {};
21
+
22
+ constructor({
23
+ homey,
24
+ items,
25
+ operations,
26
+ }) {
27
+ super();
28
+
29
+ // Set Homey
30
+ Object.defineProperty(this, 'homey', {
31
+ value: homey,
32
+ enumerable: false,
33
+ writable: false,
34
+ });
35
+
36
+ // Set Items
37
+ Object.defineProperty(this, 'items', {
38
+ value: Object.entries(items).reduce((obj, [itemName, item]) => {
39
+ const ItemClass = this.constructor.CRUD[itemName]
40
+ ? this.constructor.CRUD[itemName]
41
+ // eslint-disable-next-line no-eval
42
+ : eval(`(class ${itemName} extends Item {})`);
43
+ ItemClass.ID = item.id;
44
+ obj[item.id] = ItemClass;
45
+
46
+ return obj;
47
+ }, {}),
48
+ enumerable: false,
49
+ writable: false,
50
+ });
51
+
52
+ // Set Connected
53
+ Object.defineProperty(this, '__connected', {
54
+ value: false,
55
+ enumerable: false,
56
+ writable: true,
57
+ });
58
+
59
+ // Set Cache
60
+ Object.defineProperty(this, '__cache', {
61
+ value: Object.values(items).reduce((obj, item) => ({
62
+ ...obj,
63
+ [item.id]: {},
64
+ }), {}),
65
+ enumerable: false,
66
+ writable: false,
67
+ });
68
+
69
+ Object.defineProperty(this, '__cacheAllComplete', {
70
+ value: Object.values(items).reduce((obj, item) => ({
71
+ ...obj,
72
+ [item.id]: false,
73
+ }), {}),
74
+ enumerable: false,
75
+ writable: false,
76
+ });
77
+
78
+ // Create methods
79
+ for (const [operationId, operation] of Object.entries(operations)) {
80
+ Object.defineProperty(this,
81
+ // Name method __super__foo if there's an override method
82
+ this[operationId]
83
+ ? `__super__${operationId}`
84
+ : operationId,
85
+ {
86
+ value: async ({
87
+ $validate = true,
88
+ $cache = true,
89
+ $timeout = operation.timeout ?? 5000,
90
+ $socket = operation.socket ?? true,
91
+ $body = {},
92
+ $query = {},
93
+ $headers = {},
94
+ ...args
95
+ } = {}) => {
96
+ let { path } = operation;
97
+ let body = { ...$body };
98
+ const query = { ...$query };
99
+ const headers = { ...$headers };
100
+
101
+ // Verify & Transform parameters
102
+ if (operation.parameters) {
103
+ // Parse Parameters
104
+ for (const [parameterId, parameter] of Object.entries(operation.parameters)) {
105
+ const value = args[parameterId];
106
+
107
+ // Validate the parameter
108
+ if ($validate) {
109
+ if (parameter.required === true && typeof value === 'undefined') {
110
+ throw new Error(`Missing Parameter: ${parameterId}`);
111
+ }
112
+
113
+ if (typeof value !== 'undefined') {
114
+ if (parameter.type === 'string' && typeof value !== 'string') {
115
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: string`);
116
+ }
117
+
118
+ if (parameter.type === 'number' && typeof value !== 'number') {
119
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: number`);
120
+ }
121
+
122
+ if (parameter.type === 'boolean' && typeof value !== 'boolean') {
123
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: boolean`);
124
+ }
125
+
126
+ if (parameter.type === 'object' && typeof value !== 'object') {
127
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: object`);
128
+ }
129
+
130
+ if (parameter.type === 'array' && !Array.isArray(value)) {
131
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: array`);
132
+ }
133
+
134
+ if (Array.isArray(parameter.type)) {
135
+ // TODO
136
+ }
137
+ }
138
+ }
139
+
140
+ // Set the parameter
141
+ if (typeof value !== 'undefined') {
142
+ switch (parameter.in) {
143
+ case 'path': {
144
+ if (typeof value !== 'string') {
145
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: string`);
146
+ }
147
+
148
+ path = path.replace(`:${parameterId}`, value);
149
+ break;
150
+ }
151
+ case 'body': {
152
+ if (parameter.root) {
153
+ body = value;
154
+ } else {
155
+ body[parameterId] = value;
156
+ }
157
+ break;
158
+ }
159
+ case 'query': {
160
+ if (typeof value !== 'string') {
161
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: string`);
162
+ }
163
+
164
+ query[parameterId] = value;
165
+ break;
166
+ }
167
+ default: {
168
+ throw new Error(`Invalid 'in': ${parameter.in}`);
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+
175
+ // Append query to path
176
+ if (Object.keys(query).length > 0) {
177
+ const queryString = Object.entries(query).map(([key, value]) => {
178
+ return `${key}=${encodeURIComponent(value)}`;
179
+ }).join('&');
180
+ path = `${path}?${queryString}`;
181
+ }
182
+
183
+ let result;
184
+ const benchmark = Util.benchmark();
185
+
186
+ // If connected to Socket.io,
187
+ // try to get the CRUD Item from Cache.
188
+ if (this.isConnected() && operation.crud && $cache === true) {
189
+ const itemId = items[operation.crud.item].id;
190
+
191
+ switch (operation.crud.type) {
192
+ case 'getOne': {
193
+ if (this.__cache[itemId][args.id]) {
194
+ return this.__cache[itemId][args.id];
195
+ }
196
+
197
+ break;
198
+ }
199
+ case 'getAll': {
200
+ if (this.__cache[itemId]
201
+ && this.__cacheAllComplete[itemId]) {
202
+ return this.__cache[itemId];
203
+ }
204
+ break;
205
+ }
206
+ default:
207
+ break;
208
+ }
209
+ }
210
+
211
+ // If Homey is connected to Socket.io,
212
+ // send the API request to socket.io.
213
+ // This is about ~2x faster than HTTP
214
+ if (this.homey.isConnected() && $socket === true) {
215
+ result = await Util.timeout(new Promise((resolve, reject) => {
216
+ this.homey.__ioNamespace.emit('api', {
217
+ args,
218
+ operation: operationId,
219
+ uri: this.uri,
220
+ }, (err, result) => {
221
+ // String Error
222
+ if (typeof err === 'string') {
223
+ err = new HomeyAPIError({
224
+ error: err,
225
+ }, 500);
226
+ return reject(err);
227
+ }
228
+
229
+ // Object Error
230
+ if (typeof err === 'object' && err !== null) {
231
+ err = new HomeyAPIError({
232
+ stack: err.stack,
233
+ error: err.error,
234
+ error_description: err.error_description,
235
+ }, err.statusCode || 500);
236
+ return reject(err);
237
+ }
238
+
239
+ return resolve(result);
240
+ });
241
+ }), $timeout);
242
+ } else {
243
+ // Get from HTTP
244
+ result = await this.homey.call({
245
+ $timeout,
246
+ headers,
247
+ body,
248
+ path: `/api/manager/${this.constructor.ID}${path}`,
249
+ method: operation.method,
250
+ });
251
+ }
252
+
253
+ // Transform and cache output if this is a CRUD call
254
+ if (operation.crud) {
255
+ const itemId = items[operation.crud.item].id;
256
+ const Item = this.items[itemId];
257
+
258
+ switch (operation.crud.type) {
259
+ case 'getOne': {
260
+ let item = { ...result };
261
+ item = Item.transform(item);
262
+ item = new Item({
263
+ itemId,
264
+ id: item.id,
265
+ homey: this.homey,
266
+ manager: this,
267
+ properties: { ...item },
268
+ });
269
+
270
+ if (this.isConnected()) {
271
+ this.__cache[itemId][item.id] = item;
272
+ }
273
+
274
+ return item;
275
+ }
276
+ case 'getAll': {
277
+ const items = {};
278
+
279
+ // Add all to cache
280
+ for (let item of Object.values(result)) {
281
+ item = Item.transform(item);
282
+ if (this.__cache[itemId][item.id]) {
283
+ this.__cache[itemId][item.id].__update(item);
284
+ items[item.id] = this.__cache[itemId][item.id];
285
+ } else {
286
+ items[item.id] = new Item({
287
+ itemId,
288
+ id: item.id,
289
+ homey: this.homey,
290
+ manager: this,
291
+ properties: { ...item },
292
+ });
293
+
294
+ if (this.isConnected()) {
295
+ this.__cache[itemId][item.id] = items[item.id];
296
+ }
297
+ }
298
+ }
299
+
300
+ // Find and delete deleted items from cache
301
+ if (this.__cache[itemId]) {
302
+ for (const cachedItem of Object.values(this.__cache[itemId])) {
303
+ if (!items[cachedItem.id]) {
304
+ delete this.__cache[itemId][cachedItem.id];
305
+ }
306
+ }
307
+ }
308
+
309
+ // Mark cache as complete
310
+ if (this.isConnected()) {
311
+ this.__cacheAllComplete[itemId] = true;
312
+ }
313
+
314
+ return items;
315
+ }
316
+ case 'createOne':
317
+ case 'updateOne': {
318
+ let item = { ...result };
319
+ item = Item.transform(item);
320
+ if (this.__cache[itemId][item.id]) {
321
+ item = this.__cache[itemId][item.id].__update(item);
322
+ } else {
323
+ item = Item.transform(item);
324
+ item = new Item({
325
+ itemId,
326
+ id: item.id,
327
+ homey: this.homey,
328
+ manager: this,
329
+ properties: { ...item },
330
+ });
331
+
332
+ if (this.isConnected()) {
333
+ this.__cache[itemId][item.id] = item;
334
+ }
335
+ }
336
+
337
+ return item;
338
+ }
339
+ case 'deleteOne': {
340
+ if (this.__cache[itemId][args.id]) {
341
+ this.__cache[itemId][args.id].destroy();
342
+ delete this.__cache[itemId][args.id];
343
+ }
344
+
345
+ return undefined;
346
+ }
347
+ default:
348
+ break;
349
+ }
350
+ }
351
+
352
+ this.__debug(`${operationId} took ${benchmark()}ms`);
353
+ return result;
354
+ },
355
+ });
356
+ }
357
+ }
358
+
359
+ get uri() {
360
+ return `homey:manager:${this.constructor.ID}`;
361
+ }
362
+
363
+ __debug(...props) {
364
+ this.homey.__debug(`[${this.constructor.name}]`, ...props);
365
+ }
366
+
367
+ /**
368
+ * If this manager's namespace is connected to Socket.io.
369
+ * @returns {Boolean}
370
+ */
371
+ isConnected() {
372
+ return this.__connected === true;
373
+ }
374
+
375
+ /**
376
+ * Connect to the realtime namespace.
377
+ * @returns {Promise<void>}
378
+ */
379
+ async connect() {
380
+ this.__debug('connect');
381
+
382
+ // If disconnecting, await that first
383
+ try {
384
+ await this.__disconnectPromise;
385
+ } catch (err) { }
386
+
387
+ this.__connectPromise = Promise.resolve().then(async () => {
388
+ if (!this.io) {
389
+ this.io = this.homey.subscribe(this.uri, {
390
+ onConnect: () => {
391
+ this.__debug('onConnect');
392
+ this.__connected = true;
393
+ },
394
+ onDisconnect: reason => {
395
+ this.__debug(`onDisconnect Reason:${reason}`);
396
+ this.__connected = false;
397
+
398
+ // Clear CRUD Item cache
399
+ for (const itemId of Object.keys(this.__cache)) {
400
+ this.__cache[itemId] = {};
401
+ this.__cacheAllComplete[itemId] = false;
402
+ }
403
+ },
404
+ onEvent: (event, data) => {
405
+ this.__debug('onEvent', event);
406
+
407
+ // Transform & add to cache if this is a CRUD event
408
+ if (event.endsWith('.create')
409
+ || event.endsWith('.update')
410
+ || event.endsWith('.delete')) {
411
+ const [itemId, operation] = event.split('.');
412
+ const Item = this.items[itemId];
413
+
414
+ switch (operation) {
415
+ case 'create': {
416
+ let item = { ...data };
417
+ item = Item.transform(item);
418
+ item = new Item({
419
+ itemId,
420
+ id: item.id,
421
+ homey: this.homey,
422
+ manager: this,
423
+ properties: { ...item },
424
+ });
425
+
426
+ this.__cache[itemId][item.id] = item;
427
+ this.__cache[itemId][item.id].emit('create');
428
+
429
+ return this.emit(`${itemId}.create`, item);
430
+ }
431
+ case 'update': {
432
+ let item = { ...data };
433
+ item = Item.transform(item);
434
+
435
+ if (this.__cache[itemId][item.id]) {
436
+ item = this.__cache[itemId][item.id];
437
+ item.__update(item);
438
+ item.emit('update');
439
+ } else {
440
+ item = new Item({
441
+ itemId,
442
+ id: item.id,
443
+ homey: this.homey,
444
+ manager: this,
445
+ properties: { ...item },
446
+ });
447
+ this.__cache[itemId][item.id] = item;
448
+ }
449
+
450
+ return this.emit(`${itemId}.update`, item);
451
+ }
452
+ case 'delete': {
453
+ let item = Item.transform({ ...data });
454
+ item = Item.transform(item);
455
+
456
+ if (this.__cache[itemId][item.id]) {
457
+ this.__cache[itemId][item.id].emit('delete');
458
+ this.__cache[itemId][item.id].destroy();
459
+ delete this.__cache[itemId][item.id];
460
+ }
461
+
462
+ return this.emit(`${itemId}.delete`, {
463
+ id: item.id,
464
+ });
465
+ }
466
+ default:
467
+ break;
468
+ }
469
+ }
470
+
471
+ // Fire event listeners
472
+ this.emit(event, data);
473
+ },
474
+ });
475
+ }
476
+
477
+ await this.io;
478
+ });
479
+
480
+ // Delete the connecting Promise
481
+ this.__connectPromise
482
+ .catch(() => { })
483
+ .finally(() => {
484
+ delete this.__connectPromise;
485
+ });
486
+
487
+ await this.__connectPromise;
488
+ }
489
+
490
+ /**
491
+ * Disconnect from the realtime namespace.
492
+ * @returns {Promise<void>}
493
+ */
494
+ async disconnect() {
495
+ this.__debug('disconnect');
496
+
497
+ // If connecting, await that first
498
+ try {
499
+ await this.__connectPromise;
500
+ } catch (err) { }
501
+
502
+ this.__disconnectPromise = Promise.resolve().then(async () => {
503
+ this.__connected = false;
504
+
505
+ if (this.io) {
506
+ await this.io
507
+ .then(io => io.unsubscribe())
508
+ .catch(err => this.__debug('Error Disconnecting:', err));
509
+
510
+ delete this.io;
511
+ }
512
+ });
513
+
514
+ // Delete the disconnecting Promise
515
+ this.__disconnectPromise
516
+ .catch(() => { })
517
+ .finally(() => {
518
+ delete this.__disconnectPromise;
519
+ });
520
+
521
+ await this.__disconnectPromise;
522
+ }
523
+
524
+ destroy() {
525
+ // Clear cache
526
+ for (const id of Object.keys(this.__cache)) {
527
+ this.__cache[id] = {};
528
+ }
529
+
530
+ for (const id of Object.keys(this.__cacheAllComplete)) {
531
+ this.__cacheAllComplete[id] = false;
532
+ }
533
+
534
+ // Remove all event listeners
535
+ this.removeAllListeners();
536
+
537
+ // Disconnect from Socket.io
538
+ this.disconnect().catch(() => { });
539
+ }
12
540
 
13
541
  }
14
542
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const Item = require('./Item');
3
+ const Item = require('../Item');
4
4
 
5
5
  class App extends Item {
6
6
 
@@ -1,12 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  const Manager = require('./Manager');
4
- const App = require('./App');
4
+ const App = require('./ManagerApps/App');
5
5
 
6
6
  class ManagerApps extends Manager {
7
7
 
8
- static ITEMS = {
9
- app: App,
8
+ static CRUD = {
9
+ ...super.CRUD,
10
+ App,
10
11
  }
11
12
 
12
13
  }
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const Item = require('../Item');
4
+
5
+ class Capability extends Item {
6
+
7
+ }
8
+
9
+ module.exports = Capability;
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const Util = require('../../Util');
4
- const Item = require('./Item');
3
+ const Util = require('../../../Util');
4
+ const Item = require('../Item');
5
5
  const DeviceCapability = require('./DeviceCapability');
6
6
 
7
7
  class Device extends Item {
@@ -17,6 +17,10 @@ class Device extends Item {
17
17
  });
18
18
  }
19
19
 
20
+ get uri() {
21
+ return `homey:device:${this.id}`;
22
+ }
23
+
20
24
  /**
21
25
  * Creates an {@link HomeyAPIV2.DeviceCapability} for realtime capability updates.
22
26
  * @param {string} capabilityId
@@ -130,8 +134,79 @@ class Device extends Item {
130
134
  });
131
135
  })
132
136
  // eslint-disable-next-line no-console
133
- .catch(err => console.error(`Device[${this.id}].onReconnectError:`, err));
137
+ .catch(err => this.__debug(`Device[${this.id}].onReconnectError:`, err));
138
+ }
139
+ }
140
+
141
+ async getZone() {
142
+ return this.homey.zones.getZone({
143
+ id: this.zone,
144
+ });
145
+ }
146
+
147
+ async getDriver() {
148
+ return this.homey.drivers.getDriver({
149
+ id: this.driverId,
150
+ });
151
+ }
152
+
153
+ async getLogs() {
154
+ const logs = await this.homey.insights.getLogs();
155
+ return Object.values(logs)
156
+ .filter(log => log.ownerUri === this.uri)
157
+ .reduce((result, log) => ({
158
+ ...result,
159
+ [log.id]: log,
160
+ }), {});
161
+ }
162
+
163
+ async getFlows() {
164
+ const flows = await this.homey.flow.getFlows();
165
+ return Object.values(flows)
166
+ .filter(flow => {
167
+ if (flow.trigger && flow.trigger.id.startsWith(this.uri)) return true;
168
+ if (Array.isArray(flow.conditions) && flow.conditions.some(card => card.id.startsWith(this.uri))) return true;
169
+ if (Array.isArray(flow.actions) && flow.actions.some(card => card.id.startsWith(this.uri))) return true;
170
+
171
+ // TODO: Zone cards
172
+ // TODO: Subzone cards
173
+
174
+ return false;
175
+ })
176
+ .reduce((result, flow) => ({
177
+ ...result,
178
+ [flow.id]: flow,
179
+ }), {});
180
+ }
181
+
182
+ async getAdvancedFlows() {
183
+ const advancedFlows = await this.homey.flow.getAdvancedFlows();
184
+ return Object.values(advancedFlows)
185
+ .filter(advancedFlow => {
186
+ return Object.values(advancedFlow.cards)
187
+ .filter(card => ['trigger', 'condition', 'action'].includes(card.type))
188
+ .some(card => {
189
+ if (card.id.startsWith(this.uri)) return true;
190
+
191
+ // TODO: Zone cards
192
+ // TODO: Subzone cards
193
+ return false;
194
+ });
195
+ })
196
+ .reduce((result, advancedFlow) => ({
197
+ ...result,
198
+ [advancedFlow.id]: advancedFlow,
199
+ }), {});
200
+ }
201
+
202
+ static transform(item) {
203
+ for (const capabilityObj of Object.values(item.capabilitiesObj)) {
204
+ if (capabilityObj.lastUpdated) {
205
+ capabilityObj.lastUpdated = new Date(capabilityObj.lastUpdated);
206
+ }
134
207
  }
208
+
209
+ return item;
135
210
  }
136
211
 
137
212
  }
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const Util = require('../../Util');
4
- const EventEmitter = require('../../EventEmitter');
3
+ const Util = require('../../../Util');
4
+ const EventEmitter = require('../../../EventEmitter');
5
5
 
6
6
  /**
7
7
  * @class
@@ -75,7 +75,7 @@ class DeviceCapability extends EventEmitter {
75
75
  }
76
76
 
77
77
  __debug(...props) {
78
- this.device.__debug(`[Capability:${this.id}]`, ...props);
78
+ this.device.__debug(`[DeviceCapability:${this.id}]`, ...props);
79
79
  }
80
80
 
81
81
  /**