iobroker.iot 3.5.2 → 4.0.1

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