homey-api 3.4.28 → 3.4.30

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.
@@ -317,6 +317,17 @@
317
317
  }
318
318
  }
319
319
  },
320
+ "getAppIcon": {
321
+ "path": "/app/{appId}/icon",
322
+ "method": "get",
323
+ "parameters": {
324
+ "appId": {
325
+ "in": "path",
326
+ "type": "string",
327
+ "required": true
328
+ }
329
+ }
330
+ },
320
331
  "getAppInstall": {
321
332
  "path": "/app/{appId}/install",
322
333
  "method": "get",
@@ -2596,6 +2596,202 @@
2596
2596
  }
2597
2597
  }
2598
2598
  },
2599
+ "ManagerMoods": {
2600
+ "id": "moods",
2601
+ "idCamelCase": "moods",
2602
+ "private": true,
2603
+ "items": {
2604
+ "Mood": {
2605
+ "id": "mood",
2606
+ "schema": {
2607
+ "type": "object",
2608
+ "properties": {
2609
+ "id": {
2610
+ "type": "string"
2611
+ },
2612
+ "name": {
2613
+ "type": "string"
2614
+ },
2615
+ "zone": {
2616
+ "type": "string"
2617
+ },
2618
+ "devices": {
2619
+ "type": "object",
2620
+ "additionalProperties": false,
2621
+ "patternProperties": {
2622
+ "^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$": {
2623
+ "type": "object",
2624
+ "additionalProperties": false,
2625
+ "properties": {
2626
+ "state": {
2627
+ "type": "object",
2628
+ "additionalProperties": false,
2629
+ "patternProperties": {
2630
+ ".*": {
2631
+ "anyOf": [
2632
+ {
2633
+ "type": "string"
2634
+ },
2635
+ {
2636
+ "type": "boolean"
2637
+ },
2638
+ {
2639
+ "type": "number"
2640
+ }
2641
+ ]
2642
+ }
2643
+ }
2644
+ }
2645
+ }
2646
+ }
2647
+ }
2648
+ }
2649
+ },
2650
+ "additionalProperties": false
2651
+ }
2652
+ }
2653
+ },
2654
+ "operations": {
2655
+ "getState": {
2656
+ "method": "get",
2657
+ "path": "/state",
2658
+ "private": false,
2659
+ "scopes": [
2660
+ "homey.system.readonly"
2661
+ ],
2662
+ "parameters": {}
2663
+ },
2664
+ "getMoods": {
2665
+ "method": "get",
2666
+ "path": "/mood",
2667
+ "private": false,
2668
+ "scopes": [
2669
+ "homey.mood.readonly"
2670
+ ],
2671
+ "crud": {
2672
+ "type": "getAll",
2673
+ "item": "Mood"
2674
+ },
2675
+ "parameters": {}
2676
+ },
2677
+ "getMood": {
2678
+ "method": "get",
2679
+ "path": "/mood/:id",
2680
+ "private": false,
2681
+ "scopes": [
2682
+ "homey.mood.readonly"
2683
+ ],
2684
+ "crud": {
2685
+ "type": "getOne",
2686
+ "item": "Mood"
2687
+ },
2688
+ "parameters": {
2689
+ "id": {
2690
+ "in": "path",
2691
+ "type": "string",
2692
+ "required": true
2693
+ }
2694
+ }
2695
+ },
2696
+ "createMood": {
2697
+ "method": "post",
2698
+ "path": "/mood",
2699
+ "private": false,
2700
+ "scopes": [
2701
+ "homey.mood"
2702
+ ],
2703
+ "crud": {
2704
+ "type": "createOne",
2705
+ "item": "Mood"
2706
+ },
2707
+ "parameters": {
2708
+ "mood": {
2709
+ "in": "body",
2710
+ "type": "object",
2711
+ "root": true,
2712
+ "required": true,
2713
+ "properties": {
2714
+ "name": {
2715
+ "type": "string",
2716
+ "required": true
2717
+ },
2718
+ "devices": {
2719
+ "type": "object",
2720
+ "required": true
2721
+ }
2722
+ }
2723
+ }
2724
+ }
2725
+ },
2726
+ "updateMood": {
2727
+ "method": "put",
2728
+ "path": "/mood/:id",
2729
+ "private": false,
2730
+ "scopes": [
2731
+ "homey.mood"
2732
+ ],
2733
+ "crud": {
2734
+ "type": "updateOne",
2735
+ "item": "Mood"
2736
+ },
2737
+ "parameters": {
2738
+ "id": {
2739
+ "in": "path",
2740
+ "type": "string",
2741
+ "required": true
2742
+ },
2743
+ "mood": {
2744
+ "in": "body",
2745
+ "type": "object",
2746
+ "root": true,
2747
+ "required": true,
2748
+ "properties": {
2749
+ "name": {
2750
+ "type": "string"
2751
+ },
2752
+ "devices": {
2753
+ "type": "object"
2754
+ }
2755
+ }
2756
+ }
2757
+ }
2758
+ },
2759
+ "setMood": {
2760
+ "method": "post",
2761
+ "path": "/mood/:id/set",
2762
+ "private": false,
2763
+ "scopes": [
2764
+ "homey.mood.set"
2765
+ ],
2766
+ "parameters": {
2767
+ "id": {
2768
+ "in": "path",
2769
+ "type": "string",
2770
+ "required": true
2771
+ }
2772
+ }
2773
+ },
2774
+ "deleteMood": {
2775
+ "method": "delete",
2776
+ "path": "/mood/:id",
2777
+ "private": false,
2778
+ "scopes": [
2779
+ "homey.mood"
2780
+ ],
2781
+ "crud": {
2782
+ "type": "deleteOne",
2783
+ "item": "Mood"
2784
+ },
2785
+ "parameters": {
2786
+ "id": {
2787
+ "in": "path",
2788
+ "type": "string",
2789
+ "required": true
2790
+ }
2791
+ }
2792
+ }
2793
+ }
2794
+ },
2599
2795
  "ManagerNotifications": {
2600
2796
  "id": "notifications",
2601
2797
  "idCamelCase": "notifications",
@@ -935,6 +935,18 @@ export namespace HomeyAPIV3Cloud.ManagerLogic {
935
935
  }
936
936
  }
937
937
 
938
+ export namespace HomeyAPIV3Cloud.ManagerMoods {
939
+ export class Mood {
940
+ id: string;
941
+
942
+ name: string;
943
+
944
+ zone: string;
945
+
946
+ devices: object;
947
+ }
948
+ }
949
+
938
950
  export namespace HomeyAPIV3Cloud.ManagerNotifications {
939
951
  export class Notification {
940
952
  id: string;
@@ -1659,6 +1671,8 @@ export class AthomAppsAPI {
1659
1671
  userId?: string;
1660
1672
  }): Promise<any>;
1661
1673
 
1674
+ getAppIcon(opts: { appId: string }): Promise<any>;
1675
+
1662
1676
  getAppInstall(opts: {
1663
1677
  appId: string;
1664
1678
 
@@ -1947,6 +1961,8 @@ export class AthomAppsAPI {
1947
1961
  userId?: string;
1948
1962
  }): Promise<any>;
1949
1963
 
1964
+ getAppIcon(opts: { appId: string }): Promise<any>;
1965
+
1950
1966
  getAppInstall(opts: {
1951
1967
  appId: string;
1952
1968
 
@@ -4589,7 +4605,15 @@ export class HomeyCloudAPI {
4589
4605
  }
4590
4606
 
4591
4607
  export class Util {
4592
- static fetch(args: any): Promise;
4608
+ static fetch(
4609
+ args: string,
4610
+
4611
+ options?: Object,
4612
+
4613
+ timeoutDuration?: number,
4614
+
4615
+ timeoutMessage?: string,
4616
+ ): Promise<any>;
4593
4617
 
4594
4618
  static wait(ms: number): Promise<void>;
4595
4619
 
@@ -4625,7 +4649,15 @@ export class Util {
4625
4649
 
4626
4650
  static encodeUrlSearchParams(params: object): string;
4627
4651
 
4628
- static fetch(args: any): Promise;
4652
+ static fetch(
4653
+ args: string,
4654
+
4655
+ options?: Object,
4656
+
4657
+ timeoutDuration?: number,
4658
+
4659
+ timeoutMessage?: string,
4660
+ ): Promise<any>;
4629
4661
 
4630
4662
  static wait(ms: number): Promise<void>;
4631
4663
 
@@ -4835,6 +4867,8 @@ export class AthomAppsAPI {
4835
4867
  userId?: string;
4836
4868
  }): Promise<any>;
4837
4869
 
4870
+ getAppIcon(opts: { appId: string }): Promise<any>;
4871
+
4838
4872
  getAppInstall(opts: {
4839
4873
  appId: string;
4840
4874
 
@@ -5123,6 +5157,8 @@ export class AthomAppsAPI {
5123
5157
  userId?: string;
5124
5158
  }): Promise<any>;
5125
5159
 
5160
+ getAppIcon(opts: { appId: string }): Promise<any>;
5161
+
5126
5162
  getAppInstall(opts: {
5127
5163
  appId: string;
5128
5164
 
@@ -7701,7 +7737,15 @@ export class HomeyCloudAPI {
7701
7737
  }
7702
7738
 
7703
7739
  export class Util {
7704
- static fetch(args: any): Promise;
7740
+ static fetch(
7741
+ args: string,
7742
+
7743
+ options?: Object,
7744
+
7745
+ timeoutDuration?: number,
7746
+
7747
+ timeoutMessage?: string,
7748
+ ): Promise<any>;
7705
7749
 
7706
7750
  static wait(ms: number): Promise<void>;
7707
7751
 
@@ -7737,7 +7781,15 @@ export class Util {
7737
7781
 
7738
7782
  static encodeUrlSearchParams(params: object): string;
7739
7783
 
7740
- static fetch(args: any): Promise;
7784
+ static fetch(
7785
+ args: string,
7786
+
7787
+ options?: Object,
7788
+
7789
+ timeoutDuration?: number,
7790
+
7791
+ timeoutMessage?: string,
7792
+ ): Promise<any>;
7741
7793
 
7742
7794
  static wait(ms: number): Promise<void>;
7743
7795
 
@@ -8501,6 +8553,36 @@ export namespace HomeyAPIV3Cloud {
8501
8553
  }): Promise<any>;
8502
8554
  }
8503
8555
 
8556
+ export class ManagerMoods extends HomeyAPIV3.ManagerMoods {
8557
+ getState(): Promise<any>;
8558
+
8559
+ getMoods(): Promise<{ [key: string]: HomeyAPIV3Cloud.ManagerMoods.Mood }>;
8560
+
8561
+ getMood(opts: { id: string }): Promise<HomeyAPIV3Cloud.ManagerMoods.Mood>;
8562
+
8563
+ createMood(opts: {
8564
+ mood: {
8565
+ name: string;
8566
+
8567
+ devices: object;
8568
+ };
8569
+ }): Promise<HomeyAPIV3Cloud.ManagerMoods.Mood>;
8570
+
8571
+ updateMood(opts: {
8572
+ id: string;
8573
+
8574
+ mood: {
8575
+ name?: string;
8576
+
8577
+ devices?: object;
8578
+ };
8579
+ }): Promise<HomeyAPIV3Cloud.ManagerMoods.Mood>;
8580
+
8581
+ setMood(opts: { id: string }): Promise<any>;
8582
+
8583
+ deleteMood(opts: { id: string }): Promise<any>;
8584
+ }
8585
+
8504
8586
  export class ManagerNotifications extends HomeyAPIV3.ManagerNotifications {
8505
8587
  getState(): Promise<any>;
8506
8588
 
package/lib/API.js CHANGED
@@ -6,7 +6,6 @@ const Util = require('./Util');
6
6
  const APIError = require('./APIError');
7
7
 
8
8
  class API {
9
-
10
9
  static SPECIFICATION = null;
11
10
  static SPECIFICATION_URL = null;
12
11
  static DEFINITION_CLASSES = {};
@@ -16,19 +15,13 @@ class API {
16
15
  static JSDOC_PRIVATE = null;
17
16
  static JSDOC_EXAMPLE = null;
18
17
 
19
- constructor({
20
- baseUrl,
21
- debug = false,
22
- secret = null,
23
- } = {}) {
18
+ constructor({ baseUrl, debug = false, secret = null } = {}) {
24
19
  // Set Debug Enabled
25
20
  const debugEnvKey = `${Util.envKey(this.constructor.name)}_DEBUG`;
26
21
  const debugEnv = Util.env(debugEnvKey);
27
22
 
28
23
  Object.defineProperty(this, '__debugEnabled', {
29
- value: debugEnv !== null
30
- ? !!debugEnv
31
- : !!debug,
24
+ value: debugEnv !== null ? !!debugEnv : !!debug,
32
25
  enumerable: false,
33
26
  writable: true,
34
27
  });
@@ -38,9 +31,7 @@ class API {
38
31
  const secretEnv = Util.env(secretEnvKey);
39
32
 
40
33
  Object.defineProperty(this, '__secret', {
41
- value: secretEnv !== null
42
- ? secretEnv
43
- : secret,
34
+ value: secretEnv !== null ? secretEnv : secret,
44
35
  enumerable: false,
45
36
  writable: false,
46
37
  });
@@ -49,11 +40,17 @@ class API {
49
40
  const baseUrlEnvKey = `${Util.envKey(this.constructor.name)}_BASEURL`;
50
41
  const baseUrlEnv = Util.env(baseUrlEnvKey);
51
42
 
52
- this.baseUrl = baseUrlEnv || baseUrl || `https://${this.constructor.SPECIFICATION.host}${this.constructor.SPECIFICATION.basePath}`;
53
- if (this.baseUrl.endsWith('/')) this.baseUrl = this.baseUrl.substring(0, this.baseUrl.length - 1);
43
+ this.baseUrl =
44
+ baseUrlEnv ||
45
+ baseUrl ||
46
+ `https://${this.constructor.SPECIFICATION.host}${this.constructor.SPECIFICATION.basePath}`;
47
+ if (this.baseUrl.endsWith('/'))
48
+ this.baseUrl = this.baseUrl.substring(0, this.baseUrl.length - 1);
54
49
 
55
50
  // Create Operations
56
- for (const [operationId, operation] of Object.entries(this.constructor.SPECIFICATION.operations || {})) {
51
+ for (const [operationId, operation] of Object.entries(
52
+ this.constructor.SPECIFICATION.operations || {}
53
+ )) {
57
54
  this.__registerOperation(operationId, operation);
58
55
  }
59
56
  }
@@ -81,7 +78,11 @@ class API {
81
78
  let value = args[parameterId];
82
79
 
83
80
  // Set secret if not provided as parameter but in constructor
84
- if (parameterId === 'secret' && typeof value === 'undefined' && typeof this.__secret === 'string') {
81
+ if (
82
+ parameterId === 'secret' &&
83
+ typeof value === 'undefined' &&
84
+ typeof this.__secret === 'string'
85
+ ) {
85
86
  value = this.__secret;
86
87
  }
87
88
 
@@ -97,16 +98,26 @@ class API {
97
98
  }
98
99
 
99
100
  if (typeof value !== 'undefined') {
100
- if (parameter.in !== 'query' && parameter.type === 'string' && typeof value !== 'string') {
101
- throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: string`);
101
+ if (
102
+ parameter.in !== 'query' &&
103
+ parameter.type === 'string' &&
104
+ typeof value !== 'string'
105
+ ) {
106
+ throw new Error(
107
+ `Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: string`
108
+ );
102
109
  }
103
110
 
104
111
  if (parameter.type === 'number' && typeof value !== 'number') {
105
- throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: number`);
112
+ throw new Error(
113
+ `Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: number`
114
+ );
106
115
  }
107
116
 
108
117
  if (parameter.type === 'boolean' && typeof value !== 'boolean') {
109
- throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: boolean`);
118
+ throw new Error(
119
+ `Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: boolean`
120
+ );
110
121
  }
111
122
  }
112
123
  }
@@ -149,7 +160,7 @@ class API {
149
160
  context: { operation },
150
161
  timeout: $timeout,
151
162
  timeoutMessage: $timeoutMessage,
152
- }).catch(err => {
163
+ }).catch((err) => {
153
164
  if (typeof this.__secret === 'string' && err.message.includes(this.__secret)) {
154
165
  err.message = err.message.replace(this.__secret, '<redacted>');
155
166
  }
@@ -189,7 +200,7 @@ class API {
189
200
  // Headers
190
201
  request.headers = {
191
202
  ...request.headers,
192
- ...await this.onCallRequestHeaders({ request }),
203
+ ...(await this.onCallRequestHeaders({ request })),
193
204
  };
194
205
 
195
206
  // Timeout
@@ -229,11 +240,18 @@ class API {
229
240
  async onCallRequestExecute({ request }) {
230
241
  this.__debug('onCallRequestExecute', request);
231
242
 
232
- return Util.timeout(Util.fetch(request.url, {
233
- method: request.method,
234
- headers: request.headers,
235
- body: request.body,
236
- }), request.timeout, request.timeoutMessage);
243
+ const result = await Util.fetch(
244
+ request.url,
245
+ {
246
+ method: request.method,
247
+ headers: request.headers,
248
+ body: request.body,
249
+ },
250
+ request.timeout,
251
+ request.timeoutMessage
252
+ );
253
+
254
+ return result;
237
255
  }
238
256
 
239
257
  async onCallResponse({ request, response }) {
@@ -313,7 +331,6 @@ class API {
313
331
  return body.message;
314
332
  }
315
333
 
316
-
317
334
  return body;
318
335
  }
319
336
 
@@ -343,7 +360,6 @@ class API {
343
360
 
344
361
  throw new APIError(message, statusCode);
345
362
  }
346
-
347
363
  }
348
364
 
349
365
  module.exports = API;
@@ -455,12 +455,13 @@ class HomeyAPIV3 extends HomeyAPI {
455
455
  }
456
456
 
457
457
  this.__debug(method, `${baseUrl}${path}`);
458
- const res = await Util.timeout(
459
- Util.fetch(`${baseUrl}${path}`, {
458
+ const res = await Util.fetch(
459
+ `${baseUrl}${path}`,
460
+ {
460
461
  method,
461
462
  headers,
462
463
  body,
463
- }),
464
+ },
464
465
  $timeout
465
466
  );
466
467
 
package/lib/Util.js CHANGED
@@ -14,25 +14,55 @@ class Util {
14
14
 
15
15
  /**
16
16
  * Makes a call using `window.fetch` or `node-fetch`.
17
- * @param {...any} args
18
- * @returns {Promise}
17
+ * @param {string} args
18
+ * @param {{}=} options
19
+ * @param {number=} timeoutDuration
20
+ * @param {string=} timeoutMessage
21
+ * @returns {Promise<any>}
19
22
  */
20
- static async fetch(...args) {
21
- if (this.isReactNative()) {
22
- return fetch(...args);
23
+ static async fetch(url, options, timeoutDuration, timeoutMessage) {
24
+ options = { ...options };
25
+ let abortTimeout = null;
26
+
27
+ if (timeoutDuration != null) {
28
+ const abortController = new AbortController();
29
+
30
+ abortTimeout = setTimeout(() => {
31
+ abortController.abort('Timeout');
32
+ }, timeoutDuration);
33
+
34
+ options.signal = abortController.signal;
23
35
  }
24
36
 
25
- if (this.isBrowser()) {
26
- return window.fetch(...args);
27
- }
37
+ let responsePromise = null;
28
38
 
29
- if (this.isNodeJS()) {
39
+ if (this.isReactNative()) {
40
+ responsePromise = fetch(url, options);
41
+ } else if (this.isBrowser()) {
42
+ responsePromise = window.fetch(url, options);
43
+ } else if (this.isNodeJS()) {
30
44
  const fetch = require('node-fetch');
31
- return fetch(...args);
45
+ responsePromise = fetch(url, options);
46
+ } else if (typeof fetch !== 'undefined') {
47
+ responsePromise = fetch(url, options);
48
+ } else {
49
+ throw new Error('No fetch implementation found');
32
50
  }
33
51
 
34
- if (typeof fetch !== 'undefined') {
35
- return fetch(...args);
52
+ try {
53
+ const result = await responsePromise;
54
+
55
+ return result;
56
+ } catch (err) {
57
+ if (err.name === 'AbortError') {
58
+ if (options.signal && options.signal.aborted && options.signal.reason === 'Timeout') {
59
+ throw new APIErrorTimeout(timeoutMessage ?? `Timeout after ${timeoutDuration}ms`);
60
+ }
61
+ }
62
+
63
+ throw err;
64
+ } finally {
65
+ clearTimeout(abortTimeout);
36
66
  }
37
67
  }
38
68
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homey-api",
3
- "version": "3.4.28",
3
+ "version": "3.4.30",
4
4
  "description": "Homey API",
5
5
  "main": "index.js",
6
6
  "files": [