iobroker.iot 5.0.11 → 5.0.13

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 (61) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +11 -10
  3. package/admin/assets/index-CJ_AWUR4.css +1 -0
  4. package/admin/assets/index-DCr4hGKK.js +705 -0
  5. package/admin/index_m.html +2 -2
  6. package/admin/rules/@mf-types/ActionVisu.d.ts +2 -0
  7. package/admin/rules/@mf-types/compiled-types/ActionVisu.d.ts +29 -0
  8. package/admin/rules/@mf-types.d.ts +3 -0
  9. package/admin/rules/@mf-types.zip +0 -0
  10. package/admin/rules/assets/ActionVisu-BN0Kjfo9.js +5 -0
  11. package/admin/rules/assets/ActionVisu__loadShare___mf_0_iobroker_mf_1_adapter_mf_2_react_mf_2_v5__loadShare__.js-D5qEIjqV.js +1 -0
  12. package/admin/rules/assets/ActionVisu__loadShare__react__loadShare__.js-aa1tDx2C.js +1 -0
  13. package/admin/rules/assets/ActionVisu__loadShare__react__loadShare__.js_commonjs-proxy-DX6cx281.js +1 -0
  14. package/admin/rules/assets/ActionVisu__loadShare__react_mf_2_dom__loadShare__.js-uY2qDezJ.js +1 -0
  15. package/admin/rules/assets/ActionVisu__loadShare__react_mf_2_dom__loadShare__.js_commonjs-proxy-27bLZRGy.js +1 -0
  16. package/admin/rules/assets/bootstrap-QjsDSZNA.js +1 -0
  17. package/admin/rules/assets/hostInit-CoWylRge.js +1 -0
  18. package/admin/rules/assets/index-C1ZEp-2N.js +2 -0
  19. package/admin/rules/assets/index-Ccpql4vu.js +1 -0
  20. package/admin/rules/assets/{index-DAfe9TMn.js → index-DiSsXjpZ.js} +4 -20
  21. package/admin/rules/assets/index-FrXvyqvW.js +1187 -0
  22. package/admin/rules/assets/jsx-runtime-CnsYFZsa.js +1 -0
  23. package/admin/rules/assets/localSharedImportMap-8wECk2hR.js +1 -0
  24. package/admin/rules/assets/virtualExposes-b6CxLzZb.js +1 -0
  25. package/admin/rules/customRuleBlocks.js +7 -2
  26. package/admin/rules/mf-stats.json +1 -0
  27. package/build/lib/AlexaSmartHomeV3/Alexa/AlexaResponse.js +2 -2
  28. package/build/lib/AlexaSmartHomeV3/Alexa/AlexaResponse.js.map +1 -1
  29. package/build/lib/AlexaSmartHomeV3/Alexa/Capabilities/EndpointHealth.js +1 -1
  30. package/build/lib/AlexaSmartHomeV3/Alexa/Capabilities/EndpointHealth.js.map +1 -1
  31. package/build/lib/AlexaSmartHomeV3/Alexa/Properties/Base.js.map +1 -1
  32. package/build/lib/AlexaSmartHomeV3/Controls/Control.js +2 -2
  33. package/build/lib/AlexaSmartHomeV3/Controls/Control.js.map +1 -1
  34. package/build/lib/AlexaSmartHomeV3/Device.js +3 -3
  35. package/build/lib/AlexaSmartHomeV3/Device.js.map +1 -1
  36. package/build/lib/AlexaSmartHomeV3/DeviceManager.js +2 -1
  37. package/build/lib/AlexaSmartHomeV3/DeviceManager.js.map +1 -1
  38. package/build/lib/AlexaSmartHomeV3/Helpers/RateLimiter.js +2 -2
  39. package/build/lib/AlexaSmartHomeV3/Helpers/RateLimiter.js.map +1 -1
  40. package/build/lib/AlexaSmartHomeV3/Helpers/Utils.js +1 -1
  41. package/build/lib/AlexaSmartHomeV3/Helpers/Utils.js.map +1 -1
  42. package/build/lib/alisa.js +4 -4
  43. package/build/main.js +35 -64
  44. package/build/main.js.map +1 -1
  45. package/io-package.json +27 -27
  46. package/package.json +13 -14
  47. package/admin/assets/index-Bd3GtHgn.css +0 -1
  48. package/admin/assets/index-BmnNw2oA.js +0 -759
  49. package/admin/rules/assets/ActionVisu-BvWg4aqg.js +0 -5
  50. package/admin/rules/assets/ActionVisu__loadShare__react__loadShare__-5Bv9wGPU.js +0 -1
  51. package/admin/rules/assets/ActionVisu__loadShare__react_mf_2_dom__loadShare__-DUk47PjY.js +0 -9
  52. package/admin/rules/assets/ActionVisu__mf_v__runtimeInit__mf_v__-BUkKpfUR.js +0 -1
  53. package/admin/rules/assets/_commonjsHelpers-Cpj98o6Y.js +0 -1
  54. package/admin/rules/assets/bootstrap-BPw119x4.js +0 -1
  55. package/admin/rules/assets/hostInit-Dxp6BaAc.js +0 -2
  56. package/admin/rules/assets/index-Do-nCdWy.js +0 -9
  57. package/admin/rules/assets/index-NkHakkqA.js +0 -2
  58. package/admin/rules/assets/index-aJU5X-xL.js +0 -1152
  59. package/admin/rules/assets/index.cjs-DyuWoUPi.js +0 -8
  60. package/admin/rules/assets/virtualExposes-BQXgT6g9.js +0 -2
  61. package/build/lib/alexaSmartHomeV2.js +0 -2788
@@ -1,2788 +0,0 @@
1
- const Actions = require('../../admin/actions');
2
- const translateRooms = require('./rooms').default;
3
- const translateFunctions = require('./functions').default;
4
- const translateDevices = require('./devices').default;
5
-
6
- function AlexaSH2(adapter) {
7
- let smartDevices = [];
8
- let enums = [];
9
- let valuesON = {};
10
- let lang = 'de';
11
- let translate = false;
12
- let addedId = null;
13
-
14
- const words = {
15
- 'No name': { en: 'No name', de: 'Kein Name', ru: 'Нет имени' },
16
- Group: { en: 'Group', de: 'Gruppe', ru: 'Группа' },
17
- };
18
-
19
- this.setLanguage = function (_lang, _translate) {
20
- lang = _lang;
21
- translate = _translate;
22
- };
23
-
24
- /* function validateName(name) {
25
- if (!name) return false;
26
-
27
- for (let n = 0; n < name.length; n++) {
28
- if (name[n] === ';' || name[n] === '.' || name[n] === '-' || name[n] === ':') return false;
29
- }
30
-
31
- return true;
32
- } */
33
-
34
- function getSmartName(statesOrObj, id) {
35
- if (!id) {
36
- if (!adapter.config.noCommon) {
37
- return statesOrObj.common.smartName;
38
- }
39
- return statesOrObj?.common?.custom?.[adapter.namespace]
40
- ? statesOrObj.common.custom[adapter.namespace].smartName
41
- : undefined;
42
- }
43
- if (!adapter.config.noCommon) {
44
- return statesOrObj[id].common.smartName;
45
- }
46
- return statesOrObj[id]?.common?.custom?.[adapter.namespace]
47
- ? statesOrObj[id]?.common?.custom?.[adapter.namespace].smartName || null
48
- : null;
49
- }
50
-
51
- function padding(num) {
52
- num = num.toString(16);
53
- if (num.length < 2) {
54
- num = `0${num}`;
55
- }
56
- return num;
57
- }
58
-
59
- async function writeResponse(applianceId, operation, value) {
60
- for (let d = 0; d < smartDevices.length; d++) {
61
- if (smartDevices[d].applianceId === applianceId) {
62
- let text;
63
- let obj = smartDevices[d];
64
- switch (operation) {
65
- case 'ONOFF':
66
- if (value) {
67
- if (lang === 'de') {
68
- text = `${obj.friendlyName} ist <emphasis>eingeschaltet</emphasis>!`;
69
- } else if (lang === 'ru') {
70
- text = `${obj.friendlyName} в состоянии включено`;
71
- } else {
72
- text = `${obj.friendlyName} turned on`;
73
- }
74
- } else {
75
- if (lang === 'de') {
76
- text = `${obj.friendlyName} ist <emphasis>ausgeschaltet</emphasis>!`;
77
- } else if (lang === 'ru') {
78
- text = `${obj.friendlyName} в состоянии <emphasis>выключено</emphasis>`;
79
- } else {
80
- text = `${obj.friendlyName} turned off`;
81
- }
82
- }
83
- break;
84
-
85
- case '%':
86
- if (lang === 'de') {
87
- text = `${obj.friendlyName} wird auf ${value} Prozent <emphasis>gesetzt</emphasis>`;
88
- } else if (lang === 'ru') {
89
- text = `Состояние ${obj.friendlyName} <emphasis>установлено</emphasis> на ${value} процентов`;
90
- } else {
91
- text = `${obj.friendlyName} set to ${value} <emphasis>percent</emphasis>`;
92
- }
93
- break;
94
-
95
- case '°':
96
- if (lang === 'de') {
97
- text = `${obj.friendlyName} wird auf ${value} Grad <emphasis>gesetzt</emphasis>`;
98
- } else if (lang === 'ru') {
99
- text = `Состояние ${obj.friendlyName} <emphasis>установлено</emphasis> на ${value}`;
100
- } else {
101
- text = `${obj.friendlyName} set to ${value} <emphasis>grad</emphasis>`;
102
- }
103
- break;
104
-
105
- case '°<>':
106
- if (value >= 0) {
107
- if (lang === 'de') {
108
- text = `${obj.friendlyName} ist <emphasis>erhöht</emphasis> um ${value} Grad`;
109
- } else if (lang === 'ru') {
110
- text = `Состояние ${obj.friendlyName} <emphasis>увеличено</emphasis> на ${value}`;
111
- } else {
112
- text = `${obj.friendlyName} <emphasis>increased</emphasis> on ${value} percent`;
113
- }
114
- value = `+${value}`;
115
- } else {
116
- if (lang === 'de') {
117
- text = `${obj.friendlyName} ist <emphasis>verkleinert</emphasis> um ${value} Grad`;
118
- } else if (lang === 'ru') {
119
- text = `Состояние ${obj.friendlyName} <emphasis>уменьшено</emphasis> на ${value}`;
120
- } else {
121
- text = `${obj.friendlyName} <emphasis>decreased</emphasis> on ${value} grad`;
122
- }
123
- value = `-${value}`;
124
- }
125
- break;
126
-
127
- case '<>':
128
- if (value >= 0) {
129
- if (lang === 'de') {
130
- text = `${obj.friendlyName} ist <emphasis>erhöht</emphasis> um ${value} Prozent`;
131
- } else if (lang === 'ru') {
132
- text = `Состояние ${obj.friendlyName} <emphasis>увеличено</emphasis> на ${value}`;
133
- } else {
134
- text = `${obj.friendlyName} <emphasis>increased</emphasis> on ${value} percent`;
135
- }
136
- value = `+${value}`;
137
- } else {
138
- if (lang === 'de') {
139
- text = `${obj.friendlyName} ist <emphasis>verkleinert</emphasis> um ${value} Prozent`;
140
- } else if (lang === 'ru') {
141
- text = `Состояние ${obj.friendlyName} <emphasis>уменьшено</emphasis> на ${value}`;
142
- } else {
143
- text = `${obj.friendlyName} <emphasis>decreased</emphasis> on ${value} percent`;
144
- }
145
- value = `-${value}`;
146
- }
147
- break;
148
- }
149
-
150
- if (text) {
151
- await adapter.setStateAsync('smart.lastResponse', text, true);
152
- if (adapter.config.responseOID) {
153
- await adapter.setForeignStateAsync(adapter.config.responseOID, text, false);
154
- }
155
-
156
- await adapter.setStateAsync('smart.lastFunction', obj.additionalApplianceDetails.func, true);
157
- await adapter.setStateAsync('smart.lastRoom', obj.additionalApplianceDetails.room, true);
158
- await adapter.setStateAsync('smart.lastCommand', value, true);
159
- }
160
- return;
161
- }
162
- }
163
- adapter.log.warn(`[ALEXA] Unknown applianceId: ${applianceId}`);
164
- }
165
-
166
- function processState(states, id, room, func, alexaIds, groups, names, result) {
167
- // Make sure to also add the other necessary Endpoints:
168
- /*adapter.log.debug('[ALEXA] Process: ' + id);
169
- if(states[id].common.role == 'level.color.hue') {
170
- let sat = findRole(states,id,'level.color.saturation');
171
- let bri = findRole(states,id,'level.dimmer');
172
- let on = findRole(states,id,'switch');
173
- adapter.log.debug('[ALEXA] Adding needed: ' + sat + ' ' + bri + ' ' + on);
174
- if(sat) processState(states, sat, room, func, alexaIds, groups, names, result);
175
- if(bri) processState(states, bri, room, func, alexaIds, groups, names, result);
176
- if(on) processState(states, on, room, func, alexaIds, groups, names, result);
177
- }*/
178
-
179
- try {
180
- let friendlyName = getSmartName(states, id);
181
- let nameModified = false;
182
- let byON;
183
- let smartType;
184
- if (!id) {
185
- return 'id is empty';
186
- }
187
-
188
- if (states[id]) {
189
- // try to convert old notation to new one
190
- if (states[id].native && !adapter.config.noCommon) {
191
- if (states[id].native.byON) {
192
- byON = states[id].native.byON;
193
- delete states[id].native.byON;
194
- let smartName = states[id].common.smartName;
195
-
196
- if (!smartName || typeof smartName !== 'object') {
197
- smartName = {
198
- byON,
199
- en: smartName,
200
- };
201
- smartName[lang] = smartName.en;
202
- } else {
203
- smartName.byON = byON;
204
- }
205
- states[id].common.smartName = smartName || {};
206
- friendlyName = states[id].common.smartName;
207
- } else if (typeof states[id].common.smartName === 'string') {
208
- let nnn = states[id].common.smartName;
209
- states[id].common.smartName = {};
210
- states[id].common.smartName[lang] = nnn;
211
- friendlyName = states[id].common.smartName;
212
- }
213
- }
214
- } else {
215
- adapter.log.debug(`[ALEXA] Invalid state "${id}". Not exist or no native part.`);
216
- return `"${id}" not exists or no native part.`;
217
- }
218
-
219
- byON = friendlyName && typeof friendlyName === 'object' ? friendlyName.byON : '';
220
- smartType = friendlyName && typeof friendlyName === 'object' ? friendlyName.smartType : null;
221
-
222
- if (typeof friendlyName === 'object' && friendlyName) {
223
- friendlyName = friendlyName[lang] || friendlyName.en;
224
- }
225
-
226
- if (friendlyName === 'ignore' || friendlyName === false) {
227
- return `"${id}" must be ignored, because of the settings`;
228
- }
229
-
230
- if (!friendlyName && !room && !func) {
231
- return `No friendly name and no room or function found for "${id}"`;
232
- }
233
-
234
- if (room && typeof room === 'object') {
235
- room = room[lang] || room.en;
236
- }
237
- if (func && typeof func === 'object') {
238
- func = func[lang] || func.en;
239
- }
240
- let friendlyNames = [];
241
- if (!friendlyName) {
242
- if (room) {
243
- // translate room
244
- if (translate) {
245
- room = translateRooms(lang, room);
246
- func = translateFunctions(lang, func);
247
- }
248
-
249
- if (adapter.config.functionFirst) {
250
- if (lang === 'en') {
251
- friendlyName = `${func}${adapter.config.concatWord ? ` ${adapter.config.concatWord}` : ''} ${room}`;
252
- } else {
253
- friendlyName = `${func}${adapter.config.concatWord ? ` ${adapter.config.concatWord}` : ''} ${room}`;
254
- }
255
- } else {
256
- if (lang === 'en') {
257
- friendlyName = `${room}${adapter.config.concatWord ? ` ${adapter.config.concatWord}` : ''} ${func}`;
258
- } else {
259
- friendlyName = `${room}${adapter.config.concatWord ? ` ${adapter.config.concatWord}` : ''} ${func}`;
260
- }
261
- }
262
- } else {
263
- friendlyName = states[id].common.name;
264
- if (adapter.config.replaces) {
265
- for (let r = 0; r < adapter.config.replaces.length; r++) {
266
- friendlyName = friendlyName.replace(adapter.config.replaces[r], '');
267
- }
268
- }
269
- }
270
- friendlyNames[0] = friendlyName;
271
- nameModified = false;
272
- } else if (translate) {
273
- friendlyName = translateDevices(lang, friendlyName);
274
- nameModified = true;
275
- friendlyNames = friendlyName.split(',');
276
- } else {
277
- friendlyNames = friendlyName.split(',');
278
- nameModified = true;
279
- }
280
- for (let i = friendlyNames.length - 1; i >= 0; i--) {
281
- friendlyNames[i] = (friendlyNames[i] || '').trim();
282
- if (!friendlyNames[i]) {
283
- friendlyNames.splice(i, 1);
284
- } else {
285
- // friendlyName may not be longer than 128
286
- friendlyNames[i] = friendlyNames[i]
287
- .substring(0, 128)
288
- .replace(/[^.a-zA-Z0-9äÄüÜöÖßÉéÈèÀàÂâÊêÙùÛûÇçÎîËëÏïŸÿÔôŒœãõìòáíóú]+/g, ' ');
289
- }
290
- }
291
-
292
- if (!friendlyNames[0]) {
293
- adapter.log.warn(`[ALEXA] State ${id} is invalid.`);
294
- return `State "${id}" has invalid friendly name`;
295
- }
296
-
297
- let friendlyDescription = states[id].common.name || id;
298
- if (typeof friendlyDescription === 'object') {
299
- friendlyDescription = friendlyDescription[lang] || friendlyDescription.en;
300
- }
301
-
302
- let res = Actions.getActions(states[id]);
303
- if (!res) {
304
- adapter.log.debug(`[ALEXA] Name "${friendlyDescription}" cannot be written and will be ignored`);
305
- return `State "${id}" cannot be written and will be ignored`;
306
- }
307
- let type = res.type;
308
- let actions = res.actions;
309
-
310
- friendlyDescription = friendlyDescription
311
- .substring(0, 128)
312
- .replace(/[^.a-zA-Z0-9äÄüÜöÖßÉéÈèÀàÂâÊêÙùÛûÇçÎîËëÏïŸÿÔôŒœãõìòáíóú]+/g, ' ');
313
- // any letter or number and _ - = # ; : ? @ &
314
- // let applianceId = id.substring(0, 256).replace(/[^a-zA-Z0-9_=#;:?@&-]+/g, '_');
315
-
316
- let pos;
317
- if (alexaIds && (pos = alexaIds.indexOf(id)) !== -1) {
318
- alexaIds.splice(pos, 1);
319
- }
320
-
321
- type = type ? byON || '100' : false;
322
- let name = states[id].common.name || '';
323
- if (typeof name === 'object') {
324
- name = name[lang] || name.en;
325
- }
326
- name = name.substring(0, 128);
327
-
328
- for (let n = 0; n < friendlyNames.length; n++) {
329
- if (names[friendlyNames[n]]) {
330
- // Ignore it, because yet in the list
331
- if (names[friendlyNames[n]].additionalApplianceDetails.id === id) {
332
- return;
333
- }
334
-
335
- // create the virtual group
336
- if (groups[friendlyNames[n]]) {
337
- /* // let ids = JSON.parse(groups[friendlyNames[n]].additionalApplianceDetails.ids);
338
- let _names = JSON.parse(groups[friendlyNames[n]].additionalApplianceDetails.names || '[]');
339
- let types = JSON.parse(groups[friendlyNames[n]].additionalApplianceDetails.byONs || '[]');
340
- // ids.push(id);
341
- _names.push(name);
342
- types.push(type);
343
-
344
- // merge actions
345
- for (let a = 0; a < actions.length; a++) {
346
- if (!groups[friendlyNames[n]].actions.includes(actions[a])) {
347
- groups[friendlyNames[n]].actions.push(actions[a]);
348
- }
349
- }
350
-
351
- // groups[friendlyNames[n]].additionalApplianceDetails.ids = JSON.stringify(ids);
352
- groups[friendlyNames[n]].additionalApplianceDetails.names = JSON.stringify(_names);
353
- groups[friendlyNames[n]].additionalApplianceDetails.byONs = JSON.stringify(types);*/
354
-
355
- actions.forEach(
356
- action =>
357
- !groups[friendlyNames[n]].actions.includes(action) &&
358
- groups[friendlyNames[n]].actions.push(action),
359
- );
360
-
361
- if (smartType && !groups[friendlyNames[n]].applianceTypes.includes(smartType)) {
362
- groups[friendlyNames[n]].applianceTypes.push(smartType);
363
- }
364
-
365
- groups[friendlyNames[n]].additionalApplianceDetails.byONs[id] = type;
366
- groups[friendlyNames[n]].additionalApplianceDetails.names[id] = name;
367
- groups[friendlyNames[n]].additionalApplianceDetails.smartTypes[id] = smartType;
368
- let addids = [id];
369
- for (let i = 0; i < addids.length; i++) {
370
- let newid = addids[i];
371
- let _parts = newid.split('.');
372
- _parts.pop();
373
- let channel = _parts.join('.');
374
- if (groups[friendlyNames[n]].additionalApplianceDetails.channels.hasOwnProperty(channel)) {
375
- groups[friendlyNames[n]].additionalApplianceDetails.channels[channel].push({
376
- id: newid,
377
- role: states[addids[i]].common.role,
378
- actions,
379
- });
380
- } else {
381
- groups[friendlyNames[n]].additionalApplianceDetails.channels[channel] = [
382
- { id: newid, role: states[addids[i]].common.role, actions },
383
- ];
384
- }
385
- }
386
- } else {
387
- // convert a single device into a group, because at least two devices found with the same name
388
- groups[friendlyNames[n]] = {
389
- applianceId: friendlyNames[n].replace(/[^a-zA-Zа-яА-Я0-9_=#;:?@&-]+/g, '_').substring(0, 128),
390
- applianceTypes: JSON.parse(JSON.stringify(names[friendlyNames[n]].applianceTypes)),
391
- manufacturerName: 'ioBroker group',
392
- modelName: (name || words['No name'][lang]).substring(0, 128),
393
- version: '1',
394
- friendlyName: friendlyNames[n].substring(0, 128),
395
- friendlyDescription: `${words['Group'][lang]} ${friendlyNames[n]}`.substring(0, 128),
396
- isReachable: true,
397
- actions: JSON.parse(JSON.stringify(actions)),
398
- additionalApplianceDetails: {
399
- group: true,
400
- channels: {},
401
- smartTypes: {},
402
- names: {},
403
- byONs: {},
404
- room,
405
- func,
406
- },
407
- };
408
-
409
- const oldActions = names[friendlyNames[n]].actions;
410
- // merge actions for the first group, too!
411
- for (let a = 0; a < oldActions.length; a++) {
412
- if (!groups[friendlyNames[n]].actions.includes(oldActions[a])) {
413
- groups[friendlyNames[n]].actions.push(oldActions[a]);
414
- }
415
- }
416
-
417
- let oldObjDetails = names[friendlyNames[n]].additionalApplianceDetails;
418
-
419
- if (smartType && !groups[friendlyNames[n]].applianceTypes.includes(smartType)) {
420
- groups[friendlyNames[n]].applianceTypes.push(smartType);
421
- }
422
-
423
- groups[friendlyNames[n]].additionalApplianceDetails.byONs[oldObjDetails.id] =
424
- oldObjDetails.byON;
425
- groups[friendlyNames[n]].additionalApplianceDetails.names[oldObjDetails.id] =
426
- oldObjDetails.name;
427
- groups[friendlyNames[n]].additionalApplianceDetails.smartTypes[oldObjDetails.id] =
428
- oldObjDetails.smartType;
429
- groups[friendlyNames[n]].additionalApplianceDetails.byONs[id] = type;
430
- groups[friendlyNames[n]].additionalApplianceDetails.names[id] = name;
431
- groups[friendlyNames[n]].additionalApplianceDetails.smartTypes[id] = smartType;
432
-
433
- let addIDs = [names[friendlyNames[n]].additionalApplianceDetails.id, id];
434
- for (let i = 0; i < addIDs.length; i++) {
435
- let newID = addIDs[i];
436
- let _parts = newID.split('.');
437
- _parts.pop();
438
- let channel = _parts.join('.');
439
- if (groups[friendlyNames[n]].additionalApplianceDetails.channels.hasOwnProperty(channel)) {
440
- groups[friendlyNames[n]].additionalApplianceDetails.channels[channel].push({
441
- id: newID,
442
- role: states[addIDs[i]].common.role,
443
- actions: newID === id ? actions : oldActions,
444
- });
445
- } else {
446
- groups[friendlyNames[n]].additionalApplianceDetails.channels[channel] = [
447
- {
448
- id: newID,
449
- role: states[addIDs[i]].common.role,
450
- actions: newID === id ? actions : oldActions,
451
- },
452
- ];
453
- }
454
- }
455
-
456
- if (JSON.stringify(groups[friendlyNames[n]].additionalApplianceDetails).length > 5000) {
457
- adapter.log.warn(`[ALEXA] "${groups[friendlyNames[n]].friendlyName}" has too long additionalApplianceDetails`);
458
- return;
459
- }
460
-
461
- result.push(groups[friendlyNames[n]]);
462
- names[friendlyNames[n]].disabled = true;
463
- }
464
- } else {
465
- const obj = {
466
- applianceId: friendlyNames[n].replace(/[^a-zA-Zа-яА-Я0-9_=#;:?@&-]+/g, '_').substring(0, 128),
467
- applianceTypes: [],
468
- manufacturerName: 'ioBroker',
469
- modelName: (name || words['No name'][lang]).substring(0, 128),
470
- version: '1',
471
- friendlyName: friendlyNames[n].substring(0, 128),
472
- friendlyDescription: friendlyDescription.substring(0, 128),
473
- isReachable: true,
474
- actions: JSON.parse(JSON.stringify(actions)),
475
- additionalApplianceDetails: {
476
- id: id.substring(0, 1024),
477
- role: states[id].common.role,
478
- name,
479
- friendlyNames: friendlyNames.join(', '),
480
- smartType,
481
- byON: type,
482
- nameModified,
483
- room,
484
- func,
485
- },
486
- };
487
- if (JSON.stringify(obj.additionalApplianceDetails).length > 5000) {
488
- adapter.log.warn(`[ALEXA] "${id}" has too long additionalApplianceDetails`);
489
- return;
490
- }
491
-
492
- names[friendlyNames[n]] = obj;
493
- smartType && names[friendlyNames[n]].applianceTypes.push(smartType);
494
- result.push(obj);
495
- }
496
- }
497
- } catch (e) {
498
- adapter.log.error(`[ALEXA] Cannot process "${id}": ${e}`);
499
- return `Error by processing of "${id}": ${e}`;
500
- }
501
- }
502
-
503
- async function controlOnOff(toggle, id, value, writeStates) {
504
- let obj;
505
- try {
506
- obj = await adapter.getForeignObjectAsync(id);
507
- } catch (err) {
508
- adapter.log.error(`[ALEXA] Cannot control non state "${id}": ${err}`);
509
- }
510
-
511
- if (!obj || obj.type !== 'state') {
512
- throw new Error(`Cannot control non state: ${id} ${obj ? obj.type : 'no object'}`);
513
- }
514
-
515
- let smartName = getSmartName(obj);
516
- let byON = smartName && typeof smartName === 'object' ? smartName.byON : null;
517
-
518
- if (toggle && toggle !== id) {
519
- adapter.log.debug(`Won't control ${id} as we have a switch available`);
520
- return;
521
- }
522
-
523
- if (byON === 'omit') {
524
- adapter.log.debug(`Won't control value for "${id}", because "omit" configured`);
525
- return;
526
- }
527
-
528
- if (obj.common.type === 'number') {
529
- // if ON
530
- if (value) {
531
- if (byON === 'stored' && valuesON[id]) {
532
- adapter.log.debug(`[ALEXA] Use stored ON value for "${id}": ${valuesON[id]}`);
533
- value = valuesON[id];
534
- } else {
535
- const min = typeof obj.common.min !== 'undefined' ? obj.common.min : 0;
536
- const max = typeof obj.common.max !== 'undefined' ? obj.common.max : 100;
537
-
538
- value = byON ? Math.round(((parseFloat(byON) || 100) * (max - min)) / 100 + min) : max;
539
- }
540
- } else {
541
- // if OFF
542
- if (byON === 'stored') {
543
- // remember the last state
544
- let state;
545
- try {
546
- state = await adapter.getForeignStateAsync(id);
547
- } catch (err) {
548
- adapter.log.error(`[ALEXA] Cannot get state: ${err}`);
549
- }
550
-
551
- if (typeof obj.common.min !== 'undefined') {
552
- value = obj.common.min;
553
- } else {
554
- value = 0;
555
- }
556
- // do not remember the minimum/off value
557
- if (state && state.val !== value) {
558
- valuesON[id] = state.val;
559
- }
560
-
561
- adapter.log.debug(`[ALEXA] OFF Stored: Set "${id}" to ${value} and store old value "${id}"`);
562
- } else {
563
- // blinds
564
- if (typeof obj.common.min !== 'undefined') {
565
- value = obj.common.min;
566
- } else {
567
- value = 0;
568
- }
569
- }
570
- }
571
- } else if (obj.common.role === 'level.color.rgb') {
572
- if (value) {
573
- if (byON === 'stored' && valuesON[id]) {
574
- adapter.log.debug(`[ALEXA] Use stored ON value for "${id}": ${valuesON[id]}`);
575
- value = valuesON[id];
576
- } else {
577
- value = '#FFFFFF';
578
- }
579
- } else {
580
- if (byON === 'stored') {
581
- // remember last state
582
- let state;
583
- try {
584
- state = await adapter.getForeignStateAsync(id);
585
- } catch (err) {
586
- adapter.log.error(`[ALEXA] Cannot get state: ${err}`);
587
- }
588
-
589
- value = '#000000';
590
- // do not remember the minimum/off value
591
- if (state && state.val !== value) {
592
- valuesON[id] = state.val;
593
- }
594
-
595
- adapter.log.debug(`[ALEXA] OFF Stored: Set "${id}" to ${value} and store old value "${id}"`);
596
- } else {
597
- value = '#000000';
598
- }
599
- }
600
- }
601
-
602
- adapter.log.debug(`[ALEXA] Set "${id}" to ${value}`);
603
-
604
- if (writeStates) {
605
- await adapter.setStateAsync('smart.lastObjectID', id, true);
606
- }
607
-
608
- try {
609
- await adapter.setForeignState(id, value);
610
- } catch (err) {
611
- throw new Error(`Cannot switch device: ${err}`);
612
- }
613
- }
614
-
615
- async function controlPercent(dimmer, id, value, writeStates) {
616
- let obj;
617
- try {
618
- obj = await adapter.getForeignObjectAsync(id);
619
- } catch (err) {
620
- adapter.log.error(`[ALEXA] Cannot control non state "${id}": ${err}`);
621
- }
622
-
623
- if (!obj || obj.type !== 'state') {
624
- throw new Error(`Cannot control non state: ${id} ${obj ? obj.type : 'no object'}`);
625
- }
626
-
627
- if (dimmer && dimmer !== id) {
628
- adapter.log.debug(`[ALEXA] Won't control ${id} as we have a dimmer available for this channel.`);
629
- return;
630
- }
631
-
632
- let res = Actions.getActions(obj);
633
- if (!res || !res.actions.includes('setPercentage')) {
634
- adapter.log.debug(`[ALEXA] ${id} is no valid datapoint to set the percentage.`);
635
- return;
636
- }
637
-
638
- adapter.log.debug(`[ALEXA] Controlling ${id} .`);
639
-
640
- let max = 100;
641
- let min = 0;
642
-
643
- if (typeof obj.common.max !== 'undefined') {
644
- max = parseFloat(obj.common.max);
645
- }
646
- if (typeof obj.common.min !== 'undefined') {
647
- min = parseFloat(obj.common.min);
648
- }
649
-
650
- value = (value / 100) * (max - min) + min;
651
-
652
- if (obj.common.type === 'boolean') {
653
- value = value >= adapter.config.deviceOffLevel;
654
- } else if (
655
- adapter.config.deviceOffLevel &&
656
- value >= adapter.config.deviceOffLevel &&
657
- (!obj.common.role || !obj.common.role.includes('blind'))
658
- ) {
659
- valuesON[id] = value;
660
- adapter.log.debug(`[ALEXA] Remember ON value for "${id}": ${value}`);
661
- }
662
-
663
- if (writeStates) {
664
- await adapter.setStateAsync('smart.lastObjectID', id, true);
665
- }
666
-
667
- try {
668
- await adapter.setForeignState(id, value);
669
- } catch (err) {
670
- throw new Error(`Cannot switch device: ${err}`);
671
- }
672
- }
673
-
674
- async function controlDelta(dimmer, id, delta, writeStates) {
675
- let obj;
676
- try {
677
- obj = await adapter.getForeignObjectAsync(id);
678
- } catch (err) {
679
- adapter.log.error(`[ALEXA] Cannot control non state "${id}": ${err}`);
680
- }
681
-
682
- if (!obj || obj.type !== 'state') {
683
- throw new Error(`[ALEXA] Cannot control non state: ${id} ${obj ? obj.type : 'no object'}`);
684
- }
685
-
686
- if (obj.common.type === 'boolean') {
687
- adapter.log.debug(`[ALEXA] Object ${id} does not support Deltas.`);
688
- return;
689
- }
690
-
691
- if (dimmer && dimmer !== id) {
692
- adapter.log.debug(`[ALEXA] Won't control ${id} as we have a dimmer available for this channel.`);
693
- return;
694
- }
695
-
696
- let res = Actions.getActions(obj);
697
- if (!res || (!res.actions.includes('incrementPercentage') && !res.actions.includes('decrementPercentage'))) {
698
- adapter.log.debug(`[ALEXA] ${id} is no valid datapoint to increment or decrement the percentage.`);
699
- return;
700
- }
701
-
702
- adapter.log.debug(`[ALEXA] Controlling delta ${id}`);
703
-
704
- let state;
705
- try {
706
- state = await adapter.getForeignStateAsync(id);
707
- } catch (err) {
708
- adapter.log.error(`[ALEXA] Cannot get state "${id}": ${err}`);
709
- }
710
-
711
- let value = state ? state.val || 0 : 0;
712
- let max = 100;
713
- let min = 0;
714
- if (typeof obj.common.max !== 'undefined') {
715
- max = parseFloat(obj.common.max);
716
- }
717
- if (typeof obj.common.min !== 'undefined') {
718
- min = parseFloat(obj.common.min);
719
- }
720
-
721
- // Absolute value => percent => add delta
722
- value = ((value - min) / (max - min)) * 100 + delta;
723
- if (value > 100) {
724
- value = 100;
725
- }
726
- if (value < 0) {
727
- value = 0;
728
- }
729
- // percent => absolute value
730
- value = (value / 100) * (max - min) + min;
731
-
732
- if (adapter.config.deviceOffLevel && value >= adapter.config.deviceOffLevel) {
733
- adapter.log.debug(`[ALEXA] Remember ON value for "${id}": ${value}`);
734
- valuesON[id] = value;
735
- }
736
-
737
- if (writeStates) {
738
- await adapter.setStateAsync('smart.lastObjectID', id, true);
739
- }
740
-
741
- try {
742
- await adapter.setForeignStateAsync(id, value);
743
- } catch (err) {
744
- throw new Error(`Cannot set device: ${err}`);
745
- }
746
- }
747
-
748
- async function controlTemperature(id, value, writeStates) {
749
- //{
750
- // "header" : {
751
- // "namespace" : "Alexa.ConnectedHome.Control",
752
- // "name" : "SetTargetTemperatureConfirmation",
753
- // "payloadVersion" : "2",
754
- // "messageId" : "cc36e80c-6357-41e0-9dd4-b76cb3a394e3"
755
- // },
756
- // "payload" : {
757
- // "targetTemperature" : {
758
- // "value" : 25.0
759
- // },
760
- // "temperatureMode" : {
761
- // "value" : "AUTO"
762
- // },
763
- // "previousState" : {
764
- // "targetTemperature" : {
765
- // "value" : 21.0
766
- // },
767
- // "mode" : {
768
- // "value" : "AUTO"
769
- // }
770
- // }
771
- // }
772
- //}
773
- let obj;
774
- try {
775
- obj = await adapter.getForeignObjectAsync(id);
776
- } catch (err) {
777
- adapter.log.error(`[ALEXA] Cannot control non state "${id}": ${err}`);
778
- }
779
-
780
- if (!obj || obj.type !== 'state') {
781
- throw new Error(`Cannot control non state: ${id} ${obj ? obj.type : 'no object'}`);
782
- }
783
-
784
- let res = Actions.getActions(obj);
785
- if (!res || !res.actions.includes('setTargetTemperature')) {
786
- adapter.log.debug(`[ALEXA] ${id} is no valid datapoint to set the target temperature.`);
787
- return;
788
- }
789
-
790
- value = parseFloat(value);
791
- let max;
792
- let min;
793
- if (typeof obj.common.max !== 'undefined') {
794
- max = parseFloat(obj.common.max);
795
- }
796
- if (typeof obj.common.min !== 'undefined') {
797
- min = parseFloat(obj.common.min);
798
- }
799
-
800
- if (min !== undefined && value < min) {
801
- value = min;
802
- }
803
- if (max !== undefined && value > max) {
804
- value = max;
805
- }
806
-
807
- if (obj.common.type === 'boolean') {
808
- value = !!value;
809
- }
810
-
811
- let state;
812
- try {
813
- state = await adapter.getForeignStateAsync(id);
814
- } catch (err) {
815
- adapter.log.error(`[ALEXA] Cannot get state "${id}": ${err}`);
816
- }
817
-
818
- if (writeStates) {
819
- await adapter.setStateAsync('smart.lastObjectID', id, true);
820
- }
821
-
822
- try {
823
- await adapter.setForeignStateAsync(id, value);
824
- } catch (err) {
825
- adapter.log.error(`[ALEXA] Cannot set device: ${err}`);
826
- }
827
-
828
- return {
829
- payload: {
830
- targetTemperature: {
831
- value,
832
- },
833
- temperatureMode: {
834
- value: 'AUTO',
835
- },
836
- previousState: {
837
- targetTemperature: {
838
- value: state ? parseFloat(state.val) || 0 : 0,
839
- },
840
- mode: {
841
- value: 'AUTO',
842
- },
843
- },
844
- },
845
- };
846
- }
847
-
848
- async function getTemperature(id, writeStates) {
849
- let obj;
850
- try {
851
- obj = await adapter.getForeignObjectAsync(id);
852
- } catch (err) {
853
- adapter.log.error(`[ALEXA] Cannot ask non state "${id}": ${err}`);
854
- }
855
-
856
- if (!obj || obj.type !== 'state') {
857
- adapter.log.error(`[ALEXA] Cannot ask non state: ${id} ${obj ? obj.type : 'no object'}`);
858
- return;
859
- }
860
-
861
- let res = Actions.getActions(obj);
862
- if (!res || !res.actions.includes('getTemperatureReading')) {
863
- adapter.log.debug(`[ALEXA] ${id} is no valid datapoint to get the actual temperature.`);
864
- return;
865
- }
866
-
867
- let state;
868
- try {
869
- state = await adapter.getForeignStateAsync(id);
870
- } catch (err) {
871
- adapter.log.error(`[ALEXA] Cannot get state "${id}": ${err}`);
872
- }
873
-
874
- if (writeStates) {
875
- await adapter.setStateAsync('smart.lastObjectID', id, true);
876
- }
877
-
878
- return { value: state ? state.val : null, ts: state ? state.ts : null };
879
- }
880
-
881
- async function getTargetTemperature(id, writeStates) {
882
- let obj;
883
- try {
884
- obj = await adapter.getForeignObjectAsync(id);
885
- } catch (err) {
886
- adapter.log.error(`[ALEXA] Cannot ask non state "${id}": ${err}`);
887
- }
888
-
889
- if (!obj || obj.type !== 'state') {
890
- adapter.log.error(`[ALEXA] Cannot ask non state: ${id} ${obj ? obj.type : 'no object'}`);
891
- return;
892
- }
893
-
894
- let res = Actions.getActions(obj);
895
- if (!res || !res.actions.includes('getTargetTemperature')) {
896
- adapter.log.debug(`[ALEXA] ${id} is no valid datapoint to get the target temperature.`);
897
- return;
898
- }
899
-
900
- let state;
901
- try {
902
- state = await adapter.getForeignStateAsync(id);
903
- } catch (err) {
904
- adapter.log.error(`[ALEXA] Cannot get state "${id}": ${err}`);
905
- }
906
-
907
- if (writeStates) {
908
- await adapter.setStateAsync('smart.lastObjectID', id, true);
909
- }
910
-
911
- return { value: state ? state.val : null, ts: state ? state.ts : null };
912
- }
913
-
914
- async function controlTemperatureDelta(id, delta, writeStates) {
915
- let obj;
916
- try {
917
- obj = await adapter.getForeignObjectAsync(id);
918
- } catch (err) {
919
- throw new Error(`Cannot control non state "${id}": ${err}`);
920
- }
921
-
922
- if (!obj || obj.type !== 'state') {
923
- adapter.log.error(`[ALEXA] Cannot control non state: ${id} ${obj ? obj.type : 'no object'}`);
924
- throw new Error(`Invalid object: ${id}`);
925
- }
926
-
927
- let res = Actions.getActions(obj);
928
- if (!res || !res.actions.includes('setTargetTemperature')) {
929
- adapter.log.debug(`[ALEXA] ${id} is no valid datapoint to set the target temperature.`);
930
- return;
931
- }
932
-
933
- let state;
934
- try {
935
- state = await adapter.getForeignStateAsync(id);
936
- } catch (err) {
937
- adapter.log.error(`[ALEXA] Cannot get state "${id}": ${err}`);
938
- }
939
-
940
- let value = state ? state.val || 0 : 0;
941
- let max;
942
- let min;
943
- if (typeof obj.common.max !== 'undefined') {
944
- max = parseFloat(obj.common.max);
945
- }
946
- if (typeof obj.common.min !== 'undefined') {
947
- min = parseFloat(obj.common.min);
948
- }
949
-
950
- // Absolute value => percent => add delta
951
- value = value + delta;
952
- if (max !== undefined && value > max) {
953
- value = max;
954
- }
955
- if (min !== undefined && value < min) {
956
- value = min;
957
- }
958
-
959
- if (obj.common.type === 'boolean') {
960
- value = !!value;
961
- }
962
-
963
- if (writeStates) {
964
- await adapter.setStateAsync('smart.lastObjectID', id, true);
965
- }
966
-
967
- try {
968
- await adapter.setForeignStateAsync(id, value);
969
- } catch (err) {
970
- throw new Error(`[ALEXA] Cannot switch device: ${err}`);
971
- }
972
-
973
- return {
974
- payload: {
975
- targetTemperature: {
976
- value,
977
- },
978
- temperatureMode: {
979
- value: 'AUTO',
980
- },
981
- previousState: {
982
- targetTemperature: {
983
- value: state ? parseFloat(state.val) || 0 : 0,
984
- },
985
- mode: {
986
- value: 'AUTO',
987
- },
988
- },
989
- },
990
- };
991
- }
992
-
993
- async function controlLock(id, writeStates) {
994
- let obj;
995
- try {
996
- obj = await adapter.getForeignObjectAsync(id);
997
- } catch (err) {
998
- adapter.log.error(`[ALEXA] Cannot control non state "${id}": ${err}`);
999
- }
1000
-
1001
- if (!obj || obj.type !== 'state') {
1002
- throw new Error(`Cannot control non state: ${id} ${obj ? obj.type : 'no object'}`);
1003
- }
1004
-
1005
- adapter.log.debug(`[ALEXA] Lock "${id}"`);
1006
-
1007
- if (writeStates) {
1008
- await adapter.setStateAsync('smart.lastObjectID', id, true);
1009
- }
1010
- if (obj.native.LOCK_VALUE === undefined && obj.native.CONTROL_VALUE === undefined) {
1011
- adapter.log.warn(
1012
- `[ALEXA] Cannot choose value for lock: Please define in "${id}" the "native.LOCK_VALUE" or "native.CONTROL_VALUE" with locking value`,
1013
- );
1014
- throw new Error('Cannot choose value for lock');
1015
- } else {
1016
- try {
1017
- await adapter.setForeignStateAsync(
1018
- id,
1019
- obj.native.CONTROL_VALUE === undefined ? obj.native.LOCK_VALUE : obj.native.CONTROL_VALUE,
1020
- );
1021
- } catch (err) {
1022
- throw new Error(`[ALEXA] Cannot set device: ${err}`);
1023
- }
1024
- }
1025
- }
1026
-
1027
- async function getLock(id, writeStates) {
1028
- let obj;
1029
- try {
1030
- obj = await adapter.getForeignObjectAsync(id);
1031
- } catch (err) {
1032
- adapter.log.error(`[ALEXA] Cannot control non state "${id}": ${err}`);
1033
- }
1034
-
1035
- if (!obj || obj.type !== 'state') {
1036
- throw new Error(`Cannot read non state: ${id} ${obj ? obj.type : 'no object'}`);
1037
- }
1038
-
1039
- adapter.log.debug(`[ALEXA] Get lock state "${id}"`);
1040
-
1041
- if (writeStates) {
1042
- await adapter.setStateAsync('smart.lastObjectID', id, true);
1043
- }
1044
-
1045
- if (obj.native.LOCK_VALUE === undefined) {
1046
- adapter.log.warn(
1047
- `[ALEXA] Cannot choose value for lock: Please define in "${id}" the "native.LOCK_VALUE" with locking value`,
1048
- );
1049
- throw new Error('Cannot choose value for lock');
1050
- } else {
1051
- let state;
1052
- try {
1053
- state = await adapter.getForeignStateAsync(id);
1054
- } catch (err) {
1055
- adapter.log.error(`[ALEXA] Cannot get state "${id}": ${err}`);
1056
- }
1057
- if (
1058
- obj.native.LOCK_VALUE === 'true' ||
1059
- obj.native.LOCK_VALUE === '1' ||
1060
- obj.native.LOCK_VALUE === 1 ||
1061
- obj.native.LOCK_VALUE === 'locked'
1062
- ) {
1063
- obj.native.LOCK_VALUE = true;
1064
- }
1065
- if (
1066
- obj.native.LOCK_VALUE === 'false' ||
1067
- obj.native.LOCK_VALUE === '0' ||
1068
- obj.native.LOCK_VALUE === 0 ||
1069
- obj.native.LOCK_VALUE === 'unlocked'
1070
- ) {
1071
- obj.native.LOCK_VALUE = false;
1072
- }
1073
- if (state.val === 'true' || state.val === '1' || state.val === 1 || state.val === 'locked') {
1074
- state.val = true;
1075
- }
1076
- if (state.val === 'false' || state.val === '0' || state.val === 0 || state.val === 'unlocked') {
1077
- state.val = false;
1078
- }
1079
-
1080
- return { value: state.val === obj.native.LOCK_VALUE, ts: state.lc || state.ts };
1081
- }
1082
- }
1083
-
1084
- // expected hue range: [0, 1)
1085
- // expected saturation range: [0, 1]
1086
- // expected lightness range: [0, 1]
1087
- // Based on http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
1088
- function hsvToRgb(h, s, v) {
1089
- let r;
1090
- let g;
1091
- let b;
1092
- let i = Math.floor(h * 6);
1093
- let f = h * 6 - i;
1094
- let p = v * (1 - s);
1095
- let q = v * (1 - f * s);
1096
- let t = v * (1 - (1 - f) * s);
1097
-
1098
- switch (i % 6) {
1099
- case 0:
1100
- r = v;
1101
- g = t;
1102
- b = p;
1103
- break;
1104
-
1105
- case 1:
1106
- r = q;
1107
- g = v;
1108
- b = p;
1109
- break;
1110
-
1111
- case 2:
1112
- r = p;
1113
- g = v;
1114
- b = t;
1115
- break;
1116
-
1117
- case 3:
1118
- r = p;
1119
- g = q;
1120
- b = v;
1121
- break;
1122
-
1123
- case 4:
1124
- r = t;
1125
- g = p;
1126
- b = v;
1127
- break;
1128
-
1129
- case 5:
1130
- r = v;
1131
- g = p;
1132
- b = q;
1133
- break;
1134
- }
1135
- return '#' + padding(Math.round(r * 255)) + padding(Math.round(g * 255)) + padding(Math.round(b * 255));
1136
- }
1137
-
1138
- async function controlColorRgb(id, color, writeStates) {
1139
- adapter.log.debug(`[ALEXA] ID: ${id} Color: ${JSON.stringify(color)}`);
1140
- // "color": {
1141
- // "hue": 0.0,
1142
- // "saturation": 1.0000,
1143
- // "brightness": 1.0000
1144
- // }
1145
- let obj;
1146
- try {
1147
- obj = await adapter.getForeignObjectAsync(id);
1148
- } catch (err) {
1149
- adapter.log.error(`[ALEXA] Cannot control non state "${id}": ${err}`);
1150
- }
1151
-
1152
- if (!obj || obj.type !== 'state') {
1153
- throw new Error(`Cannot control non state: ${id} ${obj ? obj.type : 'no object'}`);
1154
- }
1155
-
1156
- let rgb = hsvToRgb(color.hue / 360, color.saturation, color.brightness);
1157
-
1158
- if (writeStates) {
1159
- await adapter.setStateAsync('smart.lastObjectID', id, true);
1160
- }
1161
- try {
1162
- await adapter.setForeignStateAsync(id, rgb);
1163
- } catch (err) {
1164
- throw new Error(`[ALEXA] Cannot set device: ${err}`);
1165
- }
1166
- }
1167
-
1168
- async function controlColorHue(ids, idh, idb, color, writeStates) {
1169
- // "color": {
1170
- // "hue": 0.0,
1171
- // "saturation": 1.0000,
1172
- // "brightness": 1.0000
1173
- // }
1174
- let obj;
1175
- try {
1176
- obj = await adapter.getForeignObjectAsync(idh);
1177
- } catch (err) {
1178
- adapter.log.error(`[ALEXA] Cannot control non state "${idh}": ${err}`);
1179
- }
1180
-
1181
- if (!obj || obj.type !== 'state') {
1182
- throw new Error(`Cannot control non state: ${idh} ${obj ? obj.type : 'no object'}`);
1183
- }
1184
-
1185
- if (obj.common && obj.common.min !== undefined && obj.common.max !== undefined) {
1186
- color.hue = Math.round((obj.common.max - obj.common.min) * (color.hue / 360) + obj.common.min);
1187
- }
1188
-
1189
- if (writeStates) {
1190
- await adapter.setStateAsync('smart.lastObjectID', idh, true);
1191
- }
1192
-
1193
- try {
1194
- await adapter.setForeignStateAsync(idh, color.hue);
1195
- } catch (err) {
1196
- adapter.log.error(`[ALEXA] Cannot set device: ${err}`);
1197
- }
1198
-
1199
- if (!ids) {
1200
- adapter.log.info('Unable to control saturation. No Saturation Endpoint in Smart Device.');
1201
- return;
1202
- }
1203
-
1204
- try {
1205
- obj = await adapter.getForeignObjectAsync(ids);
1206
- } catch (err) {
1207
- adapter.log.error(`[ALEXA] Cannot control non state "${ids}": ${err}`);
1208
- }
1209
-
1210
- if (obj && obj.common && obj.common.min !== undefined && obj.common.max !== undefined) {
1211
- color.saturation = (obj.common.max - obj.common.min) * color.saturation + obj.common.min;
1212
- } else {
1213
- color.saturation *= 100;
1214
- }
1215
-
1216
- try {
1217
- await adapter.setForeignStateAsync(ids, color.saturation);
1218
- } catch (err) {
1219
- adapter.log.error(`[ALEXA] Cannot set device: ${err}`);
1220
- }
1221
-
1222
- if (!idb) {
1223
- adapter.log.info('Unable to control brightness. No Dimmer Endpoint in Smart Device.');
1224
- return;
1225
- }
1226
- try {
1227
- obj = await adapter.getForeignObjectAsync(idb);
1228
- } catch (err) {
1229
- adapter.log.error(`[ALEXA] Cannot control non state "${idb}": ${err}`);
1230
- }
1231
-
1232
- if (obj && obj.common && (obj.common.ignoreAlexaColor === 'true' || obj.common.ignoreAlexaColor === true)) {
1233
- return;
1234
- }
1235
-
1236
- if (obj && obj.common && obj.common.min !== undefined && obj.common.max !== undefined) {
1237
- color.brightness = (obj.common.max - obj.common.min) * color.brightness + obj.common.min;
1238
- } else {
1239
- color.brightness *= 100;
1240
- }
1241
-
1242
- try {
1243
- await adapter.setForeignStateAsync(idb, color.brightness);
1244
- } catch (err) {
1245
- throw new Error(`Cannot set device: ${err}`);
1246
- }
1247
- }
1248
-
1249
- async function controlColorTemperature(temperature, id, value, writeStates) {
1250
- let obj;
1251
- try {
1252
- obj = await adapter.getForeignObjectAsync(id);
1253
- } catch (err) {
1254
- adapter.log.error(`[ALEXA] Cannot control non state "${id}": ${err}`);
1255
- }
1256
-
1257
- if (!obj || obj.type !== 'state') {
1258
- throw new Error(`Cannot control non state: ${id} ${obj ? obj.type : 'no object'}`);
1259
- }
1260
-
1261
- if (!temperature || (temperature && temperature !== id)) {
1262
- adapter.log.debug(`[ALEXA] Won't control ${id} as not a color temperature.`);
1263
- return;
1264
- }
1265
-
1266
- const unit = obj.common.unit;
1267
- let friendlyUnit;
1268
- if (unit == null) {
1269
- // default to mired
1270
- friendlyUnit = 'mired';
1271
- } else if (unit.match('K')) {
1272
- friendlyUnit = 'kelvin';
1273
- } else if (unit === '%') {
1274
- friendlyUnit = 'percent';
1275
- }
1276
-
1277
- // Alexa reports a value in Kelvin between 1000 and 10000
1278
- // By default we limit ourselves to the predefined values:
1279
- // warm, warm white 2200
1280
- // incandescent, soft white 2700
1281
- // white 4000
1282
- // daylight, daylight white 5500
1283
- // cool, cool white 7000
1284
- let minK = 2200;
1285
- let maxK = 7000;
1286
-
1287
- if (friendlyUnit === 'kelvin') {
1288
- if (obj.common.min != null) minK = parseFloat(obj.common.min);
1289
- if (obj.common.max != null) maxK = parseFloat(obj.common.max);
1290
- value = Math.max(minK, Math.min(value, maxK));
1291
- } else {
1292
- // % or mired
1293
- // for non-kelvin scales we have to re-calculate the value
1294
- // The internal representation is in mired
1295
- value = 1e6 / value;
1296
-
1297
- let minM = Math.round(1e6 / maxK);
1298
- let maxM = Math.round(1e6 / minK);
1299
- if (friendlyUnit === 'mired') {
1300
- // respect the defined min/max
1301
- if (obj.common.min != null) minM = parseFloat(obj.common.min);
1302
- if (obj.common.max != null) maxM = parseFloat(obj.common.max);
1303
- } else if (friendlyUnit === 'percent') {
1304
- // scale the value from minM (0%) to maxM (100%)
1305
- value = ((value - minM) / (maxM - minM)) * 100;
1306
- // set the limits to 0..100
1307
- minM = 0;
1308
- maxM = 100;
1309
- }
1310
- value = Math.round(value);
1311
- value = Math.max(minM, Math.min(value, maxM));
1312
- }
1313
-
1314
- adapter.log.debug(`[ALEXA] Controlling: ${id} setting to ${value}`);
1315
-
1316
- if (writeStates) {
1317
- await adapter.setStateAsync('smart.lastObjectID', id, true);
1318
- }
1319
-
1320
- try {
1321
- await adapter.setForeignStateAsync(id, value);
1322
- } catch (err) {
1323
- adapter.log.error(`[ALEXA] Cannot switch device: ${err}`);
1324
- }
1325
- }
1326
-
1327
- async function controlColorTemperatureDelta(temperature, id, delta, writeStates) {
1328
- let obj;
1329
- try {
1330
- obj = await adapter.getForeignObjectAsync(id);
1331
- } catch (err) {
1332
- adapter.log.error(`[ALEXA] Cannot control non state "${id}": ${err}`);
1333
- }
1334
-
1335
- if (!obj || obj.type !== 'state') {
1336
- adapter.log.error(`[ALEXA] Cannot control non state: ${id} ${obj ? obj.type : 'no object'}`);
1337
- throw new Error('Not controlling');
1338
- }
1339
-
1340
- if (!temperature || (temperature && temperature !== id)) {
1341
- adapter.log.debug(`[ALEXA] Won't control ${id} as not a color temperature.`);
1342
- throw new Error('Not controlling');
1343
- }
1344
-
1345
- const unit = obj.common.unit;
1346
- let friendlyUnit;
1347
- if (unit == null) {
1348
- // default to mired
1349
- friendlyUnit = 'mired';
1350
- } else if (unit.match('K')) {
1351
- friendlyUnit = 'kelvin';
1352
- } else if (unit === '%') {
1353
- friendlyUnit = 'percent';
1354
- }
1355
-
1356
- // see controlColorTemperature for a description
1357
- const minK = 2200;
1358
- const maxK = 7000;
1359
- let minValue = minK;
1360
- let maxValue = maxK;
1361
-
1362
- switch (friendlyUnit) {
1363
- case 'kelvin': {
1364
- delta = delta * -1;
1365
- if (obj.common.min != null) {
1366
- minValue = parseFloat(obj.common.min);
1367
- }
1368
- if (obj.common.max != null) {
1369
- maxValue = parseFloat(obj.common.max);
1370
- }
1371
- break;
1372
- }
1373
- case 'mired': {
1374
- minValue = Math.round(1e6 / maxValue);
1375
- maxValue = Math.round(1e6 / minValue);
1376
- if (obj.common.min != null) {
1377
- minValue = parseFloat(obj.common.min);
1378
- }
1379
- if (obj.common.max != null) {
1380
- maxValue = parseFloat(obj.common.max);
1381
- }
1382
- break;
1383
- }
1384
- case 'percent': {
1385
- minValue = 0;
1386
- maxValue = 100;
1387
- }
1388
- }
1389
-
1390
- let state;
1391
- try {
1392
- state = await adapter.getForeignStateAsync(id);
1393
- } catch (err) {
1394
- adapter.log.error(`[ALEXA] Cannot get state "${id}": ${err}`);
1395
- }
1396
- let value = state ? state.val || 0 : 0;
1397
-
1398
- // percentage of the state's range that is added/subtracted from the current value
1399
- const deltaFactor = 0.25;
1400
- value = Math.round(value + delta * deltaFactor * (maxValue - minValue));
1401
- value = Math.max(minValue, Math.min(value, maxValue));
1402
-
1403
- adapter.log.debug(`[ALEXA] Controlling: ${id} setting to ${value}`);
1404
-
1405
- if (writeStates) {
1406
- await adapter.setStateAsync('smart.lastObjectID', id, true);
1407
- }
1408
-
1409
- try {
1410
- await adapter.setForeignStateAsync(id, value);
1411
- } catch (err) {
1412
- adapter.log.error(`[ALEXA] Cannot switch device: ${err}`);
1413
- }
1414
-
1415
- // convert value back to Kelvin for reporting
1416
- if (friendlyUnit === 'percent') {
1417
- // back to mired
1418
- const minM = 1e6 / maxK;
1419
- const maxM = 1e6 / minK;
1420
- value = minM + (value / 100) * (maxM - minM);
1421
- }
1422
-
1423
- if (friendlyUnit === 'mired' || friendlyUnit === 'percent') {
1424
- // back to Kelvin
1425
- value = Math.round(1e6 / value);
1426
- }
1427
-
1428
- return value;
1429
- }
1430
-
1431
- function findRoleInChannel(channel, role) {
1432
- for (let i = 0; i < channel.length; i++) {
1433
- let dev = channel[i];
1434
- if (dev.role === role) {
1435
- return dev.id;
1436
- }
1437
- }
1438
- return null;
1439
- }
1440
-
1441
- this.getDebug = function (cb) {
1442
- let discoveredAppliances = JSON.parse(JSON.stringify(smartDevices));
1443
- for (let j = 0; j < discoveredAppliances.length; j++) {
1444
- if (!discoveredAppliances[j].additionalApplianceDetails) continue;
1445
- if (discoveredAppliances[j].additionalApplianceDetails.names !== undefined)
1446
- delete discoveredAppliances[j].additionalApplianceDetails.names;
1447
- if (discoveredAppliances[j].additionalApplianceDetails.name !== undefined)
1448
- delete discoveredAppliances[j].additionalApplianceDetails.name;
1449
- if (discoveredAppliances[j].additionalApplianceDetails.byON !== undefined)
1450
- delete discoveredAppliances[j].additionalApplianceDetails.byON;
1451
- if (discoveredAppliances[j].additionalApplianceDetails.byONs !== undefined)
1452
- delete discoveredAppliances[j].additionalApplianceDetails.byONs;
1453
- if (discoveredAppliances[j].additionalApplianceDetails.nameModified !== undefined)
1454
- delete discoveredAppliances[j].additionalApplianceDetails.nameModified;
1455
- if (discoveredAppliances[j].additionalApplianceDetails.room !== undefined)
1456
- delete discoveredAppliances[j].additionalApplianceDetails.room;
1457
- if (discoveredAppliances[j].additionalApplianceDetails.func !== undefined)
1458
- delete discoveredAppliances[j].additionalApplianceDetails.func;
1459
- if (discoveredAppliances[j].additionalApplianceDetails.smartType !== undefined)
1460
- delete discoveredAppliances[j].additionalApplianceDetails.smartType;
1461
- if (discoveredAppliances[j].additionalApplianceDetails.smartTypes !== undefined)
1462
- delete discoveredAppliances[j].additionalApplianceDetails.smartTypes;
1463
- if (discoveredAppliances[j].additionalApplianceDetails.channels !== undefined)
1464
- delete discoveredAppliances[j].additionalApplianceDetails.channels;
1465
- }
1466
-
1467
- cb({
1468
- header: {},
1469
- payload: {
1470
- discoveredAppliances,
1471
- },
1472
- });
1473
- };
1474
-
1475
- this.process = async (request, isEnabled) => {
1476
- let channels = {};
1477
- let count = 0;
1478
- let device;
1479
-
1480
- if (!isEnabled) {
1481
- request.header.name = 'NotSupportedInCurrentModeError';
1482
- return {
1483
- header: request.header,
1484
- payload: {},
1485
- };
1486
- }
1487
-
1488
- if (
1489
- request &&
1490
- request.payload &&
1491
- request.payload.appliance &&
1492
- request.payload.appliance.additionalApplianceDetails
1493
- ) {
1494
- let details = null;
1495
- for (let i = 0; i < smartDevices.length; i++) {
1496
- if (smartDevices[i].applianceId === request.payload.appliance.applianceId) {
1497
- device = smartDevices[i];
1498
- details = smartDevices[i].additionalApplianceDetails;
1499
- }
1500
- }
1501
-
1502
- if (adapter.common.loglevel === 'debug') {
1503
- adapter.log.debug(`[ALEXA] Found following devices to control: ${JSON.stringify(details)}`);
1504
- }
1505
-
1506
- if (details) {
1507
- if (details.group) {
1508
- channels = details.channels;
1509
- } else {
1510
- let id = details.id;
1511
- let role = details.role;
1512
- let _parts = id.split('.');
1513
- _parts.pop();
1514
- let channel = _parts.join('.');
1515
- channels[channel] = [{ id: id, role: role }];
1516
- }
1517
- }
1518
-
1519
- for (const chan in channels) {
1520
- if (channels.hasOwnProperty(chan)) {
1521
- count += channels[chan].length;
1522
- }
1523
- }
1524
- }
1525
- adapter.log.debug(`[ALEXA] New Request: ${request.header.name}`);
1526
-
1527
- switch (request.header.name) {
1528
- case 'DiscoverAppliancesRequest': {
1529
- //{
1530
- // "header": {
1531
- // "messageId": "6d6d6e14-8aee-473e-8c24-0d31ff9c17a2",
1532
- // "name": "DiscoverAppliancesRequest",
1533
- // "namespace": "Alexa.ConnectedHome.Discovery",
1534
- // "payloadVersion": "2"
1535
- // },
1536
- // "payload": {
1537
- // "accessToken": "*OAuth Token here*"
1538
- // }
1539
- //}
1540
- request.header.name = 'DiscoverAppliancesResponse';
1541
- //if (smartDevices.length > 100) smartDevices.splice(50, smartDevices.length - 50);
1542
- //console.log(JSON.stringify(smartDevices));
1543
- const discoveredAppliances = JSON.parse(JSON.stringify(smartDevices));
1544
- for (let j = 0; j < discoveredAppliances.length; j++) {
1545
- if (!discoveredAppliances[j].additionalApplianceDetails) continue;
1546
- if (discoveredAppliances[j].additionalApplianceDetails.names !== undefined)
1547
- delete discoveredAppliances[j].additionalApplianceDetails.names;
1548
- if (discoveredAppliances[j].additionalApplianceDetails.name !== undefined)
1549
- delete discoveredAppliances[j].additionalApplianceDetails.name;
1550
- if (discoveredAppliances[j].additionalApplianceDetails.byON !== undefined)
1551
- delete discoveredAppliances[j].additionalApplianceDetails.byON;
1552
- if (discoveredAppliances[j].additionalApplianceDetails.byONs !== undefined)
1553
- delete discoveredAppliances[j].additionalApplianceDetails.byONs;
1554
- if (discoveredAppliances[j].additionalApplianceDetails.nameModified !== undefined)
1555
- delete discoveredAppliances[j].additionalApplianceDetails.nameModified;
1556
- if (discoveredAppliances[j].additionalApplianceDetails.room !== undefined)
1557
- delete discoveredAppliances[j].additionalApplianceDetails.room;
1558
- if (discoveredAppliances[j].additionalApplianceDetails.func !== undefined)
1559
- delete discoveredAppliances[j].additionalApplianceDetails.func;
1560
- if (discoveredAppliances[j].additionalApplianceDetails.smartType !== undefined)
1561
- delete discoveredAppliances[j].additionalApplianceDetails.smartType;
1562
- if (discoveredAppliances[j].additionalApplianceDetails.smartTypes !== undefined)
1563
- delete discoveredAppliances[j].additionalApplianceDetails.smartTypes;
1564
- if (discoveredAppliances[j].additionalApplianceDetails.channels !== undefined)
1565
- delete discoveredAppliances[j].additionalApplianceDetails.channels;
1566
- }
1567
-
1568
- let response = {
1569
- header: request.header,
1570
- payload: {
1571
- discoveredAppliances /*[
1572
- {
1573
- "applianceId": "hm-rpc",
1574
- "manufacturerName": "ioBroker",
1575
- "modelName": "Bad.Hauptlicht.Aktor.STATE",
1576
- "version": "1",
1577
- "friendlyName": "Licht im Bad",
1578
- "friendlyDescription": "Bad Hauptlicht Aktor STATE",
1579
- "isReachable": true,
1580
- "actions": [
1581
- "incrementTargetTemperature",
1582
- "decrementTargetTemperature",
1583
- "setTargetTemperature"
1584
- ],
1585
- "additionalApplianceDetails": {
1586
- id: 'hm-rpc.1.1'
1587
- }
1588
- },{
1589
- "applianceId": "hm-rpc-1",
1590
- "manufacturerName": "ioBroker",
1591
- "modelName": "Bad.Hauptlicht.Aktor.STATE",
1592
- "version": "1",
1593
- "friendlyName": "Licht im Bad",
1594
- "friendlyDescription": "Bad Hauptlicht Aktor STATE",
1595
- "isReachable": true,
1596
- "actions": [
1597
- "incrementTargetTemperature",
1598
- "decrementTargetTemperature",
1599
- "setTargetTemperature"
1600
- ],
1601
- "additionalApplianceDetails": {}
1602
- },
1603
- {
1604
- "applianceId": "uniqueThermostatDeviceId",
1605
- "manufacturerName": "yourManufacturerName",
1606
- "modelName": "fancyThermostat",
1607
- "version": "your software version number here.",
1608
- "friendlyName": "Bedroom Thermostat",
1609
- "friendlyDescription": "descriptionThatIsShownToCustomer",
1610
- "isReachable": true,
1611
- "actions": [
1612
- "incrementTargetTemperature",
1613
- "decrementTargetTemperature",
1614
- "setTargetTemperature"
1615
- ],
1616
- "additionalApplianceDetails": {
1617
- }
1618
- },
1619
- {
1620
- "actions": [
1621
- "incrementPercentage",
1622
- "decrementPercentage",
1623
- "setPercentage",
1624
- "turnOn",
1625
- "turnOff"
1626
- ],
1627
- "additionalApplianceDetails": {},
1628
- "applianceId": "uniqueLightDeviceId",
1629
- "friendlyDescription": "descriptionThatIsShownToCustomer",
1630
- "friendlyName": "Living Room",
1631
- "isReachable": true,
1632
- "manufacturerName": "yourManufacturerName",
1633
- "modelName": "fancyLight",
1634
- "version": "your software version number here."
1635
- }
1636
- ]*/,
1637
- },
1638
- };
1639
-
1640
- adapter.log.debug(`[ALEXA] Response size: ${Math.round(JSON.stringify(response).length / 1024)}kb`);
1641
- // adapter.log.debug('[ALEXA] Response: ' + JSON.stringify(response));
1642
- return response;
1643
- }
1644
-
1645
- case 'TurnOnRequest': {
1646
- // {
1647
- // "header": {
1648
- // "messageId": "01ebf625-0b89-4c4d-b3aa-32340e894688",
1649
- // "name": "TurnOnRequest",
1650
- // "namespace": "Alexa.ConnectedHome.Control",
1651
- // "payloadVersion": "2"
1652
- // },
1653
- // "payload": {
1654
- // "accessToken": "[OAuth Token here]",
1655
- // "appliance": {
1656
- // "additionalApplianceDetails": {},
1657
- // "applianceId": "[Device ID for Ceiling Fan]"
1658
- // }
1659
- // }
1660
- // }
1661
- adapter.log.debug(`[ALEXA] ALEXA ON: ${request.payload.appliance.applianceId}`);
1662
-
1663
- for (let channel in channels) {
1664
- if (!channels.hasOwnProperty(channel)) {
1665
- continue;
1666
- }
1667
- // try to find ON value for dimmer
1668
- let toggle = findRoleInChannel(channels[channel], 'level.dimmer');
1669
- if (toggle) {
1670
- const byON = device.additionalApplianceDetails.group
1671
- ? device.additionalApplianceDetails.byONs[toggle]
1672
- : device.additionalApplianceDetails.byON;
1673
- if (!byON || byON === '-' || byON === 'omit') {
1674
- toggle = null;
1675
- }
1676
- }
1677
-
1678
- toggle = toggle || findRoleInChannel(channels[channel], 'switch');
1679
-
1680
- for (let i = 0; i < channels[channel].length; i++) {
1681
- let id = channels[channel][i].id;
1682
- adapter.log.debug(`[ALEXA] Controlling: ${id}`);
1683
- try {
1684
- await controlOnOff(toggle, id, true, Object.keys(channels).length === 1);
1685
- } catch (err) {
1686
- adapter.log.warn(`[ALEXA] Cannot controlOnOff ${err}`);
1687
- }
1688
- }
1689
- }
1690
-
1691
- writeResponse(request.payload.appliance.applianceId, 'ONOFF', true).catch(err =>
1692
- adapter.log.error(`[ALEXA] ${err}`),
1693
- );
1694
-
1695
- request.header.name = 'TurnOnConfirmation';
1696
-
1697
- return {
1698
- header: request.header,
1699
- payload: {},
1700
- };
1701
- }
1702
-
1703
- case 'TurnOffRequest': {
1704
- // {
1705
- // "header": {
1706
- // "messageId": "01ebf625-0b89-4c4d-b3aa-32340e894688",
1707
- // "name": "TurnOffRequest",
1708
- // "namespace": "Alexa.ConnectedHome.Control",
1709
- // "payloadVersion": "2"
1710
- // },
1711
- // "payload": {
1712
- // "accessToken": "[OAuth Token here]",
1713
- // "appliance": {
1714
- // "additionalApplianceDetails": {},
1715
- // "applianceId": "[Device ID for Ceiling Fan]"
1716
- // }
1717
- // }
1718
- // }
1719
- adapter.log.debug(`[ALEXA] ALEXA OFF: ${request.payload.appliance.applianceId}`);
1720
-
1721
- for (let channel in channels) {
1722
- if (!channels.hasOwnProperty(channel)) {
1723
- continue;
1724
- }
1725
- let toggle = findRoleInChannel(channels[channel], 'level.dimmer');
1726
- if (toggle) {
1727
- const byON = device.additionalApplianceDetails.group
1728
- ? device.additionalApplianceDetails.byONs[toggle]
1729
- : device.additionalApplianceDetails.byON;
1730
- if (!byON || byON === '-' || byON === 'omit') {
1731
- toggle = null;
1732
- }
1733
- }
1734
-
1735
- toggle = toggle || findRoleInChannel(channels[channel], 'switch');
1736
-
1737
- adapter.log.debug(toggle);
1738
- for (let i = 0; i < channels[channel].length; i++) {
1739
- let id = channels[channel][i].id;
1740
- adapter.log.debug(`[ALEXA] Controlling off: ${id}`);
1741
- try {
1742
- await controlOnOff(toggle, id, false, Object.keys(channels).length === 1);
1743
- } catch (err) {
1744
- adapter.log.warn(`[ALEXA] Cannot controlOnOff: ${err}`);
1745
- }
1746
- }
1747
- }
1748
- request.header.name = 'TurnOffConfirmation';
1749
-
1750
- writeResponse(request.payload.appliance.applianceId, 'ONOFF', false).catch(err =>
1751
- adapter.log.error(`[ALEXA] ${err}`),
1752
- );
1753
-
1754
- return {
1755
- header: request.header,
1756
- payload: {},
1757
- };
1758
- }
1759
-
1760
- case 'SetLockStateRequest': {
1761
- // {
1762
- // "header": {
1763
- // "messageId": "01ebf625-0b89-4c4d-b3aa-32340e894688",
1764
- // "name": "TurnOnRequest",
1765
- // "namespace": "Alexa.ConnectedHome.Control",
1766
- // "payloadVersion": "2"
1767
- // },
1768
- // "payload": {
1769
- // "accessToken": "[OAuth Token here]",
1770
- // "appliance": {
1771
- // "additionalApplianceDetails": {},
1772
- // "applianceId": "[Device ID for Ceiling Fan]"
1773
- // }
1774
- // }
1775
- // }
1776
- adapter.log.debug(`[ALEXA] ALEXA LOCK: ${request.payload.appliance.applianceId}`);
1777
- let err;
1778
- for (let channel in channels) {
1779
- if (!channels.hasOwnProperty(channel)) {
1780
- continue;
1781
- }
1782
- for (let i = 0; i < channels[channel].length; i++) {
1783
- let id = channels[channel][i].id;
1784
- adapter.log.debug(`[ALEXA] Controlling lock: ${id}`);
1785
- try {
1786
- await controlLock(id, Object.keys(channels).length === 1);
1787
- } catch (_err) {
1788
- adapter.log.error(`[ALEXA] Cannot controlLock: ${_err}`);
1789
- err = _err;
1790
- }
1791
- }
1792
- }
1793
-
1794
- writeResponse(request.payload.appliance.applianceId, 'ONOFF', true).catch(err =>
1795
- adapter.log.error(`[ALEXA] ${err}`),
1796
- );
1797
-
1798
- request.header.name = 'SetLockStateConfirmation';
1799
-
1800
- if (err) {
1801
- return {
1802
- header: request.header,
1803
- payload: {
1804
- lockState: 'UNLOCKED',
1805
- },
1806
- };
1807
- }
1808
-
1809
- return {
1810
- header: request.header,
1811
- payload: {
1812
- lockState: 'LOCKED',
1813
- },
1814
- };
1815
- }
1816
-
1817
- case 'GetLockStateRequest': {
1818
- // {
1819
- // "header": {
1820
- // "messageId": "01ebf625-0b89-4c4d-b3aa-32340e894688",
1821
- // "name": "TurnOnRequest",
1822
- // "namespace": "Alexa.ConnectedHome.Control",
1823
- // "payloadVersion": "2"
1824
- // },
1825
- // "payload": {
1826
- // "accessToken": "[OAuth Token here]",
1827
- // "appliance": {
1828
- // "additionalApplianceDetails": {},
1829
- // "applianceId": "[Device ID for Ceiling Fan]"
1830
- // }
1831
- // }
1832
- // }
1833
- adapter.log.debug(`[ALEXA] ALEXA GetLOCK: ${request.payload.appliance.applianceId}`);
1834
- let value;
1835
- let ts;
1836
- let err;
1837
- for (let channel in channels) {
1838
- if (!channels.hasOwnProperty(channel)) {
1839
- continue;
1840
- }
1841
- for (let i = 0; i < channels[channel].length; i++) {
1842
- let id = channels[channel][i].id;
1843
- adapter.log.debug(`[ALEXA] Controlling lock: ${id}`);
1844
- let result;
1845
- try {
1846
- result = await getLock(id, Object.keys(channels).length === 1);
1847
- } catch (_err) {
1848
- err = _err;
1849
- adapter.log.error(`[ALEXA] Cannot getLock: ${err}`);
1850
- }
1851
-
1852
- if (result) {
1853
- value = result.value;
1854
- ts = result.ts;
1855
- adapter.log.debug(`[ALEXA] Settings result: ${value}`);
1856
- }
1857
- }
1858
- }
1859
-
1860
- request.header.name = 'GetLockStateResponse';
1861
-
1862
- if (err) {
1863
- return {
1864
- header: request.header,
1865
- payload: {
1866
- lockState: 'UNLOCKED',
1867
- },
1868
- };
1869
- }
1870
-
1871
- return {
1872
- header: request.header,
1873
- payload: {
1874
- lockState: value ? 'LOCKED' : 'UNLOCKED',
1875
- applianceResponseTimestamp: ts ? new Date(ts).toISOString() : new Date().toISOString(),
1876
- },
1877
- };
1878
- }
1879
-
1880
- case 'SetPercentageRequest': {
1881
- adapter.log.debug(
1882
- `[ALEXA] ALEXA Percent: ${request.payload.appliance.applianceId} ${request.payload.percentageState.value}%`,
1883
- );
1884
- for (let channel in channels) {
1885
- if (!channels.hasOwnProperty(channel)) {
1886
- continue;
1887
- }
1888
- let dimmer = findRoleInChannel(channels[channel], 'level.dimmer');
1889
- adapter.log.debug(`[ALEXA] DATA: ${JSON.stringify(channels[channel])}`);
1890
- adapter.log.debug(dimmer);
1891
- for (let i = 0; i < channels[channel].length; i++) {
1892
- let id = channels[channel][i].id;
1893
- adapter.log.debug(`[ALEXA] Controlling percentage: ${id}`);
1894
- try {
1895
- await controlPercent(
1896
- dimmer,
1897
- id,
1898
- request.payload.percentageState.value,
1899
- Object.keys(channels).length === 1,
1900
- );
1901
- } catch (err) {
1902
- adapter.log.error(`[ALEXA] Cannot controlPercent: ${err}`);
1903
- }
1904
- }
1905
- }
1906
- request.header.name = 'SetPercentageConfirmation';
1907
-
1908
- writeResponse(request.payload.appliance.applianceId, '%', request.payload.percentageState.value).catch(
1909
- err => adapter.log.error(`[ALEXA] ${err}`),
1910
- );
1911
-
1912
- return {
1913
- header: request.header,
1914
- payload: {},
1915
- };
1916
- }
1917
-
1918
- case 'IncrementPercentageRequest': {
1919
- adapter.log.debug(
1920
- `[ALEXA] ALEXA Increment: ${request.payload.appliance.applianceId} ${request.payload.deltaPercentage.value}%`,
1921
- );
1922
- for (let channel in channels) {
1923
- if (!channels.hasOwnProperty(channel)) {
1924
- continue;
1925
- }
1926
- let dimmer = findRoleInChannel(channels[channel], 'level.dimmer');
1927
-
1928
- adapter.log.debug(`[ALEXA] DATA: ${JSON.stringify(channels[channel])}`);
1929
- adapter.log.debug(dimmer);
1930
-
1931
- for (let i = 0; i < channels[channel].length; i++) {
1932
- let id = channels[channel][i].id;
1933
- adapter.log.debug(`[ALEXA] Controlling increment percentage: ${id}`);
1934
- try {
1935
- await controlDelta(
1936
- dimmer,
1937
- id,
1938
- request.payload.percentageState.value,
1939
- Object.keys(channels).length === 1,
1940
- );
1941
- } catch (err) {
1942
- adapter.log.error(`[ALEXA] Cannot controlDelta: ${err}`);
1943
- }
1944
- }
1945
- }
1946
-
1947
- request.header.name = 'IncrementPercentageConfirmation';
1948
-
1949
- writeResponse(request.payload.appliance.applianceId, '<>', request.payload.deltaPercentage.value).catch(
1950
- err => adapter.log.error(`[ALEXA] ${err}`),
1951
- );
1952
-
1953
- return {
1954
- header: request.header,
1955
- payload: {},
1956
- };
1957
- }
1958
-
1959
- case 'DecrementPercentageRequest': {
1960
- adapter.log.debug(
1961
- `[ALEXA] ALEXA decrement: ${request.payload.appliance.applianceId} ${request.payload.deltaPercentage.value}%`,
1962
- );
1963
- for (let channel in channels) {
1964
- if (!channels.hasOwnProperty(channel)) {
1965
- continue;
1966
- }
1967
- let dimmer = findRoleInChannel(channels[channel], 'level.dimmer');
1968
-
1969
- adapter.log.debug(`[ALEXA] DATA: ${JSON.stringify(channels[channel])}`);
1970
- adapter.log.debug(dimmer);
1971
-
1972
- for (let i = 0; i < channels[channel].length; i++) {
1973
- let id = channels[channel][i].id;
1974
- adapter.log.debug(`[ALEXA] Controlling decrement percentage: ${id}`);
1975
- try {
1976
- await controlDelta(
1977
- dimmer,
1978
- id,
1979
- request.payload.percentageState.value * -1,
1980
- Object.keys(channels).length === 1,
1981
- );
1982
- } catch (err) {
1983
- adapter.log.error(`[ALEXA] Cannot controlDelta: ${err}`);
1984
- }
1985
- }
1986
- }
1987
-
1988
- request.header.name = 'DecrementPercentageConfirmation';
1989
-
1990
- writeResponse(
1991
- request.payload.appliance.applianceId,
1992
- '<>',
1993
- -1 * request.payload.deltaPercentage.value,
1994
- ).catch(err => adapter.log.error(`[ALEXA] ${err}`));
1995
-
1996
- return {
1997
- header: request.header,
1998
- payload: {},
1999
- };
2000
- }
2001
-
2002
- case 'SetTargetTemperatureRequest': {
2003
- adapter.log.debug(
2004
- `[ALEXA] ALEXA temperature Percent: ${request.payload.appliance.applianceId} ${request.payload.targetTemperature.value} grad`,
2005
- );
2006
- let err;
2007
- let response;
2008
- for (let channel in channels) {
2009
- if (!channels.hasOwnProperty(channel)) {
2010
- continue;
2011
- }
2012
-
2013
- for (let i = 0; i < channels[channel].length; i++) {
2014
- let id = channels[channel][i].id;
2015
-
2016
- adapter.log.debug(`[ALEXA] Controlling temperature: ${id}`);
2017
- try {
2018
- const _response = await controlTemperature(
2019
- id,
2020
- request.payload.targetTemperature.value,
2021
- Object.keys(channels).length === 1,
2022
- );
2023
- if (_response && !response) {
2024
- response = _response;
2025
- }
2026
- } catch (_err) {
2027
- err = _err;
2028
- adapter.log.error(`[ALEXA] Cannot controlTemperature: ${err}`);
2029
- }
2030
- }
2031
- }
2032
-
2033
- writeResponse(
2034
- request.payload.appliance.applianceId,
2035
- '°',
2036
- request.payload.targetTemperature.value,
2037
- ).catch(err => adapter.log.error(`[ALEXA] ${err}`));
2038
-
2039
- request.header.name = 'SetTargetTemperatureConfirmation';
2040
-
2041
- if (err || !response) {
2042
- return {
2043
- header: request.header,
2044
- payload: {
2045
- targetTemperature: {
2046
- value: 0,
2047
- },
2048
- temperatureMode: {
2049
- value: 'AUTO',
2050
- },
2051
- previousState: {
2052
- targetTemperature: {
2053
- value: 0,
2054
- },
2055
- mode: {
2056
- value: 'AUTO',
2057
- },
2058
- },
2059
- },
2060
- };
2061
- }
2062
- response.header = request.header;
2063
- return response;
2064
- }
2065
-
2066
- case 'IncrementTargetTemperatureRequest': {
2067
- request.payload.deltaTemperature.value = request.payload.deltaTemperature.value || 1;
2068
- adapter.log.debug(
2069
- `[ALEXA] ALEXA temperature Increment: ${request.payload.appliance.applianceId} ${request.payload.deltaTemperature.value} grad`,
2070
- );
2071
- let response;
2072
- let err;
2073
-
2074
- for (let channel in channels) {
2075
- if (!channels.hasOwnProperty(channel)) {
2076
- continue;
2077
- }
2078
- for (let i = 0; i < channels[channel].length; i++) {
2079
- let id = channels[channel][i].id;
2080
- adapter.log.debug(`[ALEXA] Controlling increment temperature: ${id}`);
2081
- try {
2082
- const _response = await controlTemperatureDelta(
2083
- id,
2084
- request.payload.deltaTemperature.value,
2085
- Object.keys(channels).length === 1,
2086
- );
2087
- if (_response && !response) {
2088
- response = _response;
2089
- }
2090
- } catch (_err) {
2091
- err = _err;
2092
- adapter.log.error(`[ALEXA] Cannot controlTemperatureDelta: ${err}`);
2093
- }
2094
- }
2095
- }
2096
-
2097
- writeResponse(
2098
- request.payload.appliance.applianceId,
2099
- '°<>',
2100
- request.payload.targetTemperature.value,
2101
- ).catch(err => adapter.log.error(`[ALEXA] ${err}`));
2102
-
2103
- request.header.name = 'IncrementTargetTemperatureConfirmation';
2104
-
2105
- if (err || !response) {
2106
- return {
2107
- header: request.header,
2108
- payload: {
2109
- targetTemperature: {
2110
- value: 0,
2111
- },
2112
- temperatureMode: {
2113
- value: 'AUTO',
2114
- },
2115
- previousState: {
2116
- targetTemperature: {
2117
- value: 0,
2118
- },
2119
- mode: {
2120
- value: 'AUTO',
2121
- },
2122
- },
2123
- },
2124
- };
2125
- }
2126
- response.header = request.header;
2127
- return response;
2128
- }
2129
-
2130
- case 'DecrementTargetTemperatureRequest': {
2131
- request.payload.deltaTemperature.value = request.payload.deltaTemperature.value || 1;
2132
- adapter.log.debug(
2133
- `[ALEXA] ALEXA temperature decrement: ${request.payload.appliance.applianceId} ${request.payload.deltaTemperature.value} grad`,
2134
- );
2135
- let response;
2136
- let err;
2137
-
2138
- for (let channel in channels) {
2139
- if (!channels.hasOwnProperty(channel)) {
2140
- continue;
2141
- }
2142
-
2143
- for (let i = 0; i < channels[channel].length; i++) {
2144
- let id = channels[channel][i].id;
2145
-
2146
- adapter.log.debug(`[ALEXA] Controlling decrement temperature: ${id}`);
2147
-
2148
- try {
2149
- const _response = await controlTemperatureDelta(
2150
- id,
2151
- request.payload.deltaTemperature.value * -1,
2152
- Object.keys(channels).length === 1,
2153
- );
2154
- if (_response && !response) {
2155
- response = _response;
2156
- }
2157
- } catch (_err) {
2158
- err = _err;
2159
- adapter.log.error(`[ALEXA] Cannot controlTemperatureDelta: ${err}`);
2160
- }
2161
- }
2162
- }
2163
-
2164
- writeResponse(
2165
- request.payload.appliance.applianceId,
2166
- '°<>',
2167
- -1 * request.payload.targetTemperature.value,
2168
- ).catch(err => adapter.log.error(`[ALEXA] ${err}`));
2169
-
2170
- request.header.name = 'DecrementTargetTemperatureConfirmation';
2171
-
2172
- if (err || !response) {
2173
- return {
2174
- header: request.header,
2175
- payload: {
2176
- targetTemperature: {
2177
- value: 0,
2178
- },
2179
- temperatureMode: {
2180
- value: 'AUTO',
2181
- },
2182
- previousState: {
2183
- targetTemperature: {
2184
- value: 0,
2185
- },
2186
- mode: {
2187
- value: 'AUTO',
2188
- },
2189
- },
2190
- },
2191
- };
2192
- }
2193
- response.header = request.header;
2194
- return response;
2195
- }
2196
-
2197
- case 'GetTemperatureReadingRequest': {
2198
- adapter.log.debug(`[ALEXA] ALEXA temperature get: ${request.payload.appliance.applianceId}`);
2199
- let values = 0;
2200
- let num = 0;
2201
- let err;
2202
- let ts;
2203
- for (let channel in channels) {
2204
- if (!channels.hasOwnProperty(channel)) {
2205
- continue;
2206
- }
2207
- for (let i = 0; i < channels[channel].length; i++) {
2208
- let id = channels[channel][i].id;
2209
-
2210
- adapter.log.debug(`[ALEXA] Get temperature: ${id}`);
2211
- let result;
2212
- try {
2213
- result = await getTemperature(id, Object.keys(channels).length === 1);
2214
- } catch (_err) {
2215
- adapter.log.error(`[ALEXA] Cannot getTemperature: ${_err}`);
2216
- err = _err;
2217
- }
2218
- ts = result && result.ts;
2219
- const value = result && result.value;
2220
-
2221
- // calculate average temperature
2222
- if (value !== null && value !== undefined) {
2223
- num++;
2224
- values += value;
2225
- }
2226
- }
2227
- }
2228
- request.header.name = 'GetTemperatureReadingResponse';
2229
-
2230
- if (err) {
2231
- return {
2232
- header: request.header,
2233
- payload: {
2234
- temperatureReading: {
2235
- value: 0,
2236
- },
2237
- applianceResponseTimestamp: new Date().toISOString(),
2238
- },
2239
- };
2240
- }
2241
-
2242
- return {
2243
- header: request.header,
2244
- payload: {
2245
- temperatureReading: {
2246
- value: Math.round((values * 10) / num) / 10,
2247
- },
2248
- applianceResponseTimestamp: ts ? new Date(ts).toISOString() : new Date().toISOString(),
2249
- },
2250
- };
2251
- }
2252
-
2253
- case 'GetTargetTemperatureRequest': {
2254
- adapter.log.debug(`[ALEXA] ALEXA TargetTemperature get: ${request.payload.appliance.applianceId}`);
2255
- let ts;
2256
- let value;
2257
- for (let channel in channels) {
2258
- if (!channels.hasOwnProperty(channel)) {
2259
- continue;
2260
- }
2261
- for (let i = 0; i < channels[channel].length; i++) {
2262
- let id = channels[channel][i].id;
2263
-
2264
- adapter.log.debug(`[ALEXA] Getting target temperature: ${id}`);
2265
-
2266
- let result;
2267
- try {
2268
- result = await getTargetTemperature(id, Object.keys(channels).length === 1);
2269
- } catch (err) {
2270
- adapter.log.error(`[ALEXA] Cannot getTargetTemperature: ${err}`);
2271
- }
2272
- if (result && result.ts) {
2273
- ts = result.ts;
2274
- }
2275
- if (result && result.value) {
2276
- value = result.value;
2277
- }
2278
- }
2279
- }
2280
-
2281
- request.header.name = 'GetTargetTemperatureResponse';
2282
- adapter.log.debug(`[ALEXA] Got: ${value}`);
2283
-
2284
- return {
2285
- header: request.header,
2286
- payload: {
2287
- targetTemperature: {
2288
- value: value || 0,
2289
- },
2290
- temperatureMode: {
2291
- value: 'CUSTOM',
2292
- friendlyName: '',
2293
- },
2294
- applianceResponseTimestamp: ts ? new Date(ts).toISOString() : new Date().toISOString(),
2295
- },
2296
- };
2297
- }
2298
-
2299
- case 'SetColorRequest': {
2300
- adapter.log.debug(
2301
- `[ALEXA] ALEXA Color: ${request.payload.appliance.applianceId} ${JSON.stringify(request.payload.color)}`,
2302
- );
2303
-
2304
- count = Object.keys(channels).length;
2305
-
2306
- for (let channel in channels) {
2307
- if (!channels.hasOwnProperty(channel)) {
2308
- continue;
2309
- }
2310
- let hue = findRoleInChannel(channels[channel], 'level.color.hue');
2311
- if (hue) {
2312
- adapter.log.debug(`[ALEXA] Using HUE for: ${channel}`);
2313
- let sat = findRoleInChannel(channels[channel], 'level.color.saturation');
2314
- let bri = findRoleInChannel(channels[channel], 'level.dimmer');
2315
- let color = JSON.parse(JSON.stringify(request.payload.color));
2316
- try {
2317
- await controlColorHue(sat, hue, bri, color, Object.keys(channels).length === 1);
2318
- } catch (err) {
2319
- adapter.log.error(`[ALEXA] Cannot SetColorRequest: ${err}`);
2320
- }
2321
- continue;
2322
- }
2323
-
2324
- let rgb = findRoleInChannel(channels[channel], 'level.color.rgb');
2325
- if (rgb) {
2326
- adapter.log.debug(`[ALEXA] Using RGB for: ${channel}`);
2327
- let color = JSON.parse(JSON.stringify(request.payload.color));
2328
- try {
2329
- await controlColorRgb(rgb, color, Object.keys(channels).length === 1);
2330
- } catch (err) {
2331
- adapter.log.error(`[ALEXA] Cannot SetColorRequest: ${err}`);
2332
- }
2333
- continue;
2334
- }
2335
- adapter.log.debug(`[ALEXA] Unable to set color for: ${channel}`);
2336
- adapter.log.debug(`[ALEXA] Count: ${count}`);
2337
- }
2338
-
2339
- // writeResponse(request.payload.appliance.applianceId, '%', request.payload.percentageState.value);
2340
- request.header.name = 'SetColorConfirmation';
2341
-
2342
- return {
2343
- header: request.header,
2344
- payload: {
2345
- achievedState: {
2346
- color: JSON.parse(JSON.stringify(request.payload.color)),
2347
- },
2348
- },
2349
- };
2350
- }
2351
-
2352
- case 'SetColorTemperatureRequest': {
2353
- for (let channel in channels) {
2354
- if (!channels.hasOwnProperty(channel)) {
2355
- continue;
2356
- }
2357
- let temperature = findRoleInChannel(channels[channel], 'level.color.temperature');
2358
- for (let i = 0; i < channels[channel].length; i++) {
2359
- let id = channels[channel][i].id;
2360
- adapter.log.debug(`[ALEXA] Controlling temperature kelvin: ${id}`);
2361
- try {
2362
- await controlColorTemperature(
2363
- temperature,
2364
- id,
2365
- request.payload.colorTemperature.value,
2366
- Object.keys(channels).length === 1,
2367
- );
2368
- } catch (err) {
2369
- adapter.log.error(`[ALEXA] Cannot controlColorTemperature: ${err}`);
2370
- }
2371
- }
2372
- }
2373
-
2374
- request.header.name = 'SetColorTemperatureConfirmation';
2375
-
2376
- return {
2377
- header: request.header,
2378
- payload: {
2379
- achievedState: {
2380
- colorTemperature: {
2381
- value: request.payload.colorTemperature.value,
2382
- },
2383
- },
2384
- },
2385
- };
2386
- }
2387
- case 'IncrementColorTemperatureRequest': {
2388
- let res;
2389
- for (let channel in channels) {
2390
- if (!channels.hasOwnProperty(channel)) {
2391
- continue;
2392
- }
2393
- let temperature = findRoleInChannel(channels[channel], 'level.color.temperature');
2394
- for (let i = 0; i < channels[channel].length; i++) {
2395
- let id = channels[channel][i].id;
2396
- adapter.log.debug(`[ALEXA] Controlling temperature kelvin: ${id}`);
2397
- try {
2398
- const _res = await controlColorTemperatureDelta(
2399
- temperature,
2400
- id,
2401
- -1,
2402
- Object.keys(channels).length === 1,
2403
- );
2404
- if (_res !== undefined && _res !== null) {
2405
- res = _res;
2406
- }
2407
- } catch (err) {
2408
- adapter.log.warn(`[ALEXA] Cannot controlColorTemperatureDelta: ${err}`);
2409
- }
2410
- }
2411
- }
2412
-
2413
- request.header.name = 'IncrementColorTemperatureConfirmation';
2414
-
2415
- return {
2416
- header: request.header,
2417
- payload: {
2418
- achievedState: {
2419
- colorTemperature: {
2420
- value: res,
2421
- },
2422
- },
2423
- },
2424
- };
2425
- }
2426
-
2427
- case 'DecrementColorTemperatureRequest': {
2428
- let res;
2429
- for (let channel in channels) {
2430
- if (!channels.hasOwnProperty(channel)) {
2431
- continue;
2432
- }
2433
- let temperature = findRoleInChannel(channels[channel], 'level.color.temperature');
2434
- for (let i = 0; i < channels[channel].length; i++) {
2435
- let id = channels[channel][i].id;
2436
- adapter.log.debug(`[ALEXA] Controlling temperature kelvin: ${id}`);
2437
- try {
2438
- const _res = await controlColorTemperatureDelta(
2439
- temperature,
2440
- id,
2441
- 1,
2442
- Object.keys(channels).length === 1,
2443
- );
2444
- if (_res !== undefined && _res !== null) {
2445
- res = _res;
2446
- }
2447
- } catch (err) {
2448
- adapter.log.warn(`[ALEXA] Cannot controlColorTemperatureDelta: ${err}`);
2449
- }
2450
- }
2451
- }
2452
-
2453
- request.header.name = 'DecrementColorTemperatureConfirmation';
2454
-
2455
- return {
2456
- header: request.header,
2457
- payload: {
2458
- achievedState: {
2459
- colorTemperature: {
2460
- value: res,
2461
- },
2462
- },
2463
- },
2464
- };
2465
- }
2466
-
2467
- case 'HealthCheckRequest': {
2468
- request.header.name = 'HealthCheckResponse';
2469
- try {
2470
- adapter.log.debug(
2471
- `[ALEXA] HealthCheckRequest duration: ${Date.now() - request.payload.initiationTimestamp} ms`,
2472
- );
2473
- } catch (e) {
2474
- adapter.log.error('[ALEXA] No payload');
2475
- }
2476
- let text = 'Das System ist OK';
2477
- if (lang === 'ru') {
2478
- text = 'Система в порядке';
2479
- } else if (lang === 'en') {
2480
- text = 'The system is OK';
2481
- }
2482
- return {
2483
- header: request.header,
2484
- payload: {
2485
- description: text,
2486
- isHealthy: true,
2487
- },
2488
- };
2489
- }
2490
-
2491
- default: {
2492
- request.header.name = 'NotSupportedInCurrentModeError';
2493
-
2494
- return {
2495
- header: request.header,
2496
- payload: {},
2497
- };
2498
- }
2499
- }
2500
- };
2501
-
2502
- this.updateDevices = function (_addedId, callback) {
2503
- if (typeof _addedId === 'function') {
2504
- callback = _addedId;
2505
- _addedId = null;
2506
- }
2507
-
2508
- addedId = _addedId;
2509
-
2510
- this.getDevices((err, result, analyseAddedId) => {
2511
- addedId = null;
2512
- smartDevices = result;
2513
- callback && callback(analyseAddedId);
2514
- });
2515
- };
2516
-
2517
- this.getEnums = function () {
2518
- return enums;
2519
- };
2520
-
2521
- this.getDevices = function (callback) {
2522
- if (!callback) {
2523
- return smartDevices;
2524
- }
2525
- adapter.getObjectView('system', 'state', {}, (err, _states) => {
2526
- let states = {};
2527
- let ids = [];
2528
- let alexaIds = [];
2529
- let groups = {};
2530
- let names = {};
2531
- enums = [];
2532
-
2533
- if (_states?.rows) {
2534
- for (let i = 0; i < _states.rows.length; i++) {
2535
- if (_states.rows[i].value) {
2536
- states[_states.rows[i].id] = _states.rows[i].value;
2537
- ids.push(_states.rows[i].id);
2538
-
2539
- if (adapter.config.noCommon) {
2540
- if (
2541
- _states.rows[i].value.common?.custom?.[adapter.namespace]?.smartName &&
2542
- _states.rows[i].value.common.custom[adapter.namespace].smartName !== 'ignore'
2543
- ) {
2544
- alexaIds.push(_states.rows[i].id);
2545
- }
2546
- } else {
2547
- if (
2548
- _states.rows[i].value.common?.smartName &&
2549
- _states.rows[i].value.common.smartName !== 'ignore'
2550
- ) {
2551
- alexaIds.push(_states.rows[i].id);
2552
- }
2553
- }
2554
- }
2555
- }
2556
- }
2557
- ids.sort();
2558
- adapter.getObjectView('system', 'enum', {}, (err, doc) => {
2559
- // Build overlap from rooms and functions
2560
- let rooms = [];
2561
- let funcs = [];
2562
- let smartName;
2563
- if (doc?.rows) {
2564
- for (let i = 0, l = doc.rows.length; i < l; i++) {
2565
- if (doc.rows[i].value) {
2566
- let _id = doc.rows[i].id;
2567
- smartName = getSmartName(doc.rows[i].value);
2568
- if (_id.match(/^enum\.rooms\./) && smartName !== 'ignore' && smartName !== false) {
2569
- rooms.push(doc.rows[i].value);
2570
- }
2571
- if (_id.match(/^enum\.functions\./) && smartName !== 'ignore' && smartName !== false) {
2572
- funcs.push(doc.rows[i].value);
2573
- }
2574
- if (_id.match(/^enum\.rooms\./) || _id.match(/^enum\.functions\./)) {
2575
- if (!doc.rows[i].value) {
2576
- doc.rows[i].value = {};
2577
- }
2578
- if (!doc.rows[i].value.common) {
2579
- doc.rows[i].value.common = {};
2580
- }
2581
-
2582
- const en = {
2583
- id: _id,
2584
- name: doc.rows[i].value.common.name,
2585
- color: doc.rows[i].value.common.color,
2586
- icon: doc.rows[i].value.common.icon,
2587
- type: 'enum',
2588
- smartName,
2589
- };
2590
- if (typeof en.name === 'object') {
2591
- en.name = en.name[lang] || en.name.en;
2592
- }
2593
- enums.push(en);
2594
- }
2595
- }
2596
- }
2597
- }
2598
- let result = [];
2599
- for (let f = 0; f < funcs.length; f++) {
2600
- if (
2601
- !funcs[f].common ||
2602
- !funcs[f].common.members ||
2603
- typeof funcs[f].common.members !== 'object' ||
2604
- !funcs[f].common.members.length
2605
- ) {
2606
- continue;
2607
- }
2608
-
2609
- for (let s = 0; s < funcs[f].common.members.length; s++) {
2610
- let id = funcs[f].common.members[s];
2611
- if (typeof id !== 'string') {
2612
- continue;
2613
- }
2614
- smartName = getSmartName(funcs[f]);
2615
- if (smartName && typeof smartName === 'object') {
2616
- smartName = smartName[lang] || smartName.en;
2617
- }
2618
- let func = smartName || funcs[f].common.name;
2619
-
2620
- if (!func) {
2621
- func = funcs[f]._id.substring('enum.functions.'.length);
2622
- func = func[0].toUpperCase() + func.substring(1);
2623
- }
2624
-
2625
- // Find room
2626
- let room = '';
2627
- for (let r = 0; r < rooms.length; r++) {
2628
- if (
2629
- !rooms[r].common?.members ||
2630
- typeof rooms[r].common.members !== 'object' ||
2631
- !rooms[r].common.members.length
2632
- ) {
2633
- continue;
2634
- }
2635
-
2636
- if (rooms[r].common.members.includes(id)) {
2637
- smartName = getSmartName(rooms[r]);
2638
- if (smartName && typeof smartName === 'object') {
2639
- smartName = smartName[lang] || smartName.en;
2640
- }
2641
- room = smartName || rooms[r].common.name;
2642
- if (!room) {
2643
- room = rooms[r]._id.substring('enum.rooms.'.length);
2644
- room = room[0].toUpperCase() + room.substring(1);
2645
- }
2646
- }
2647
-
2648
- if (!room) {
2649
- // may be the channel is in the room
2650
- let _parts = id.split('.');
2651
- _parts.pop();
2652
- let channel = _parts.join('.');
2653
- if (rooms[r].common.members.includes(channel)) {
2654
- smartName = getSmartName(funcs[f]);
2655
- if (smartName && typeof smartName === 'object') {
2656
- smartName = smartName[lang] || smartName.en;
2657
- }
2658
-
2659
- room = smartName || rooms[r].common.name;
2660
-
2661
- if (!room) {
2662
- room = rooms[r]._id.substring('enum.rooms.'.length);
2663
- room = room[0].toUpperCase() + room.substring(1);
2664
- }
2665
- }
2666
- }
2667
- if (room) {
2668
- break;
2669
- }
2670
- }
2671
-
2672
- if (!states[id]) {
2673
- let m = new RegExp(`^${id.replace(/\./g, '\\.')}`);
2674
- for (let ii = 0; ii < ids.length; ii++) {
2675
- if (ids[ii] < id) {
2676
- continue;
2677
- }
2678
- if (m.exec(ids[ii])) {
2679
- if (
2680
- states[ids[ii]].common.role &&
2681
- (states[ids[ii]].common.role === 'state' ||
2682
- states[ids[ii]].common.role.match(/^switch/) ||
2683
- states[ids[ii]].common.role.match(/^level/))
2684
- ) {
2685
- processState(states, ids[ii], room, func, alexaIds, groups, names, result);
2686
- }
2687
- continue;
2688
- }
2689
- break;
2690
- }
2691
- } else {
2692
- processState(states, id, room, func, alexaIds, groups, names, result);
2693
- }
2694
- }
2695
- }
2696
-
2697
- let analyseAddedId = null;
2698
-
2699
- // process states with defined smartName
2700
- for (let j = 0; j < alexaIds.length; j++) {
2701
- const errorText = processState(states, alexaIds[j], null, null, null, groups, names, result);
2702
- if (addedId && !analyseAddedId && alexaIds[j] === addedId && errorText) {
2703
- adapter.log.error(errorText);
2704
- analyseAddedId = errorText;
2705
- }
2706
- }
2707
-
2708
- result.sort((a, b) => {
2709
- let fnA = a.friendlyName;
2710
- if (typeof fnA === 'object') {
2711
- fnA = fnA[lang] || fnA['en'];
2712
- }
2713
- let fnB = b.friendlyName;
2714
- if (typeof fnB === 'object') {
2715
- fnB = fnB[lang] || fnB['en'];
2716
- }
2717
- if (fnA > fnB) {
2718
- return 1;
2719
- }
2720
- if (fnA < fnB) {
2721
- return -1;
2722
- }
2723
- return 0;
2724
- });
2725
-
2726
- for (let k = result.length - 1; k >= 0; k--) {
2727
- if (result[k].disabled) {
2728
- result.splice(k, 1);
2729
- } else {
2730
- let fn = result[k].friendlyName;
2731
- if (typeof fn === 'object') {
2732
- fn = fn[lang] || fn['en'];
2733
- }
2734
- adapter.log.debug(`[ALEXA] Created ALEXA device: ${fn} ${JSON.stringify(result[k].actions)}`);
2735
- }
2736
- }
2737
-
2738
- // Check that all applianceId are unique: https://developer.amazon.com/en-US/blogs/alexa/post/Tx480XF5QCA6IN/managing-device-discovery-for-your-alexa-smart-home-skil
2739
- const uniqueIds = [];
2740
- for (let i = result.length - 1; i >= 0; i--) {
2741
- if (uniqueIds.includes(result[i].applianceId)) {
2742
- adapter.log.error(`[ALEXA] Duplicate applianceId: ${result[i].applianceId}`);
2743
- result.splice(i, 1);
2744
- continue;
2745
- }
2746
-
2747
- uniqueIds.push(result[i].applianceId);
2748
-
2749
- // check the maximum length of capabilities
2750
- if (result[i].actions.length > 100) {
2751
- adapter.log.error(`[ALEXA] Too many actions by "${result[i].applianceId}": ${result[i].actions.length}`);
2752
- result.splice(i, 1);
2753
- }
2754
- }
2755
-
2756
- // Check the maximum number of devices
2757
- if (result.length > 300) {
2758
- adapter.log.error(`[ALEXA] Too many devices: ${result.length}`);
2759
- result.splice(300);
2760
- }
2761
-
2762
- while (JSON.stringify(result).length > 255 * 1024) {
2763
- // Find the biggest one
2764
- let i = -1;
2765
- let size = 0;
2766
- for (let j = 0; j < result.length; j++) {
2767
- const s = JSON.stringify(result[j]).length;
2768
- if (s > size) {
2769
- size = s;
2770
- i = j;
2771
- }
2772
- }
2773
-
2774
- if (i === -1) {
2775
- break;
2776
- }
2777
- adapter.log.warn(`[ALEXA] Too big response. Device "${result[i].applianceId}" will be removed`);
2778
- // Check the maximum size of the response
2779
- result.splice(i, 1);
2780
- }
2781
-
2782
- callback(err, result, analyseAddedId);
2783
- });
2784
- });
2785
- };
2786
- }
2787
-
2788
- module.exports = AlexaSH2;