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
package/lib/googleHome.js DELETED
@@ -1,3323 +0,0 @@
1
- const axios = require('axios');
2
- const { Types, ChannelDetector } = require('iobroker.type-detector');
3
-
4
- const textsT = require('./texts');
5
- const roomsT = require('./rooms');
6
- const funcsT = require('./functions');
7
- const version = require('../package.json').version;
8
-
9
- const PROTOCOL_VERSION = 1;
10
- const RETRY_UNKNOWN_DEVICES_INTERVAL = 10 * 60000; // 10 minutes
11
-
12
- const traitEnum = {
13
- 'action.devices.traits.ArmDisarm': {
14
- command: 'arm',
15
- defaultAttributes: `{
16
- "availableArmLevels": {
17
- "levels": [
18
- {
19
- "level_name": "L1",
20
- "level_values": [
21
- {
22
- "level_synonym": [
23
- "home and guarding",
24
- "SL1"
25
- ],
26
- "lang": "en"
27
- },
28
- {
29
- "level_synonym": [
30
- "zuhause und bewachen",
31
- "SL1"
32
- ],
33
- "lang": "de"
34
- },
35
- {
36
- "level_synonym": [
37
- "дома и охрана",
38
- "SL1"
39
- ],
40
- "lang": "ru"
41
- }
42
- ]
43
- },
44
- {
45
- "level_name": "L2",
46
- "level_values": [
47
- {
48
- "level_synonym": [
49
- "away and guarding",
50
- "SL2"
51
- ],
52
- "lang": "en"
53
- },
54
- {
55
- "level_synonym": [
56
- "weg und bewachen",
57
- "SL2"
58
- ],
59
- "lang": "de"
60
- },
61
- {
62
- "level_synonym": [
63
- "все ушли и охрана",
64
- "SL2"
65
- ],
66
- "lang": "ru"
67
- }
68
- ]
69
- }
70
- ],
71
- "ordered": true
72
- }
73
- }`,
74
- },
75
- 'action.devices.traits.Brightness': {
76
- command: 'brightness',
77
- defaultAttributes: '{}',
78
- },
79
- 'action.devices.traits.CameraStream': {
80
- command: 'cameraStream',
81
- defaultAttributes: `{
82
- "cameraStreamSupportedProtocols": [
83
- "hls",
84
- "dash"
85
- ],
86
- "cameraStreamNeedAuthToken": true,
87
- "cameraStreamNeedDrmEncryption": false
88
- }`,
89
- },
90
- 'action.devices.traits.ColorSetting_temperature': {
91
- command: 'color_temperature',
92
- defaultAttributes: `{
93
- "colorModel": "rgb",
94
- "colorTemperatureRange": {
95
- "temperatureMinK": 2000,
96
- "temperatureMaxK": 9000
97
- },
98
- "commandOnlyColorSetting": false
99
- }`,
100
- },
101
- 'action.devices.traits.ColorSetting_spectrumRGB': {
102
- command: 'color_spectrumRGB',
103
- defaultAttributes: `{
104
- "colorModel": "rgb",
105
- "colorTemperatureRange": {
106
- "temperatureMinK": 2000,
107
- "temperatureMaxK": 9000
108
- },
109
- "commandOnlyColorSetting": false
110
- }`,
111
- },
112
- 'action.devices.traits.Dock': {
113
- command: 'command',
114
- defaultAttributes: '{}',
115
- },
116
- 'action.devices.traits.FanSpeed': {
117
- command: 'fanSpeed',
118
- getter: 'currentFanSpeedSetting',
119
- defaultAttributes: `{
120
- "availableFanSpeeds": {
121
- "speeds": [
122
- {
123
- "speed_name": "Low",
124
- "speed_values": [
125
- {
126
- "speed_synonym": [
127
- "low",
128
- "slow"
129
- ],
130
- "lang": "en"
131
- },
132
- {
133
- "speed_synonym": [
134
- "niedrig",
135
- "schleppend"
136
- ],
137
- "lang": "de"
138
- },
139
- {
140
- "speed_synonym": [
141
- "вниз",
142
- "медленно"
143
- ],
144
- "lang": "ru"
145
- }
146
- ]
147
- },
148
- {
149
- "speed_name": "High",
150
- "speed_values": [
151
- {
152
- "speed_synonym": [
153
- "high"
154
- ],
155
- "lang": "en"
156
- },
157
- {
158
- "speed_synonym": [
159
- "hoch"
160
- ],
161
- "lang": "de"
162
- },
163
- {
164
- "speed_synonym": [
165
- "вверх"
166
- ],
167
- "lang": "ru"
168
- }
169
- ]
170
- }
171
- ],
172
- "ordered": true
173
- },
174
- "reversible": true
175
- }`,
176
- },
177
- 'action.devices.traits.LightEffects': {
178
- command: 'command',
179
- defaultAttributes: `{
180
- "supportedEffects": [
181
- "colorLoop"
182
- ]
183
- }`,
184
- },
185
- 'action.devices.traits.Locator': {
186
- command: 'command',
187
- defaultAttributes: '{}',
188
- },
189
- 'action.devices.traits.LockUnlock': {
190
- command: 'lock',
191
- getter: 'isLocked',
192
- defaultAttributes: '{}',
193
- },
194
- 'action.devices.traits.Modes': {
195
- command: 'updateModeSettings',
196
- defaultAttributes: `{
197
- "availableModes": [
198
- {
199
- "name": "load",
200
- "name_values": [
201
- {
202
- "name_synonym": [
203
- "load",
204
- "size",
205
- "load size"
206
- ],
207
- "lang": "en"
208
- },
209
- {
210
- "name_synonym": [
211
- "beladung",
212
- "gewicht",
213
- "beladungsgewicht"
214
- ],
215
- "lang": "de"
216
- },
217
- {
218
- "name_synonym": [
219
- "загрузка",
220
- "размер",
221
- "размер загрузки"
222
- ],
223
- "lang": "ru"
224
- }
225
- ],
226
- "settings": [
227
- {
228
- "setting_name": "small",
229
- "setting_values": [
230
- {
231
- "setting_synonym": [
232
- "small",
233
- "half"
234
- ],
235
- "lang": "en"
236
- },
237
- {
238
- "setting_synonym": [
239
- "klein",
240
- "hälfte"
241
- ],
242
- "lang": "de"
243
- },
244
- {
245
- "setting_synonym": [
246
- "малый",
247
- "половниа"
248
- ],
249
- "lang": "ru"
250
- }
251
- ]
252
- },
253
- {
254
- "setting_name": "large",
255
- "setting_values": [
256
- {
257
- "setting_synonym": [
258
- "large",
259
- "full"
260
- ],
261
- "lang": "en"
262
- },
263
- {
264
- "setting_synonym": [
265
- "große",
266
- "voll"
267
- ],
268
- "lang": "de"
269
- },
270
- {
271
- "setting_synonym": [
272
- "большая",
273
- "полная"
274
- ],
275
- "lang": "ru"
276
- }
277
- ]
278
- }
279
- ],
280
- "ordered": true
281
- }
282
- ]
283
- }`,
284
- },
285
- 'action.devices.traits.OnOff': {
286
- command: 'on',
287
- defaultAttributes: `{
288
- "commandOnlyOnOff": false
289
- }`,
290
- },
291
- 'action.devices.traits.OpenClose': {
292
- command: 'openPercent',
293
- defaultAttributes: `{
294
- "openDirection": [
295
- "UP",
296
- "DOWN"
297
- ]
298
- }`,
299
- },
300
- 'action.devices.traits.RunCycle': {
301
- command: 'currentTotalRemainingTime',
302
- defaultAttributes: '{}',
303
- },
304
- 'action.devices.traits.Scene': {
305
- command: 'ActivateScene',
306
- defaultAttributes: `{
307
- "sceneReversible": true
308
- }`,
309
- },
310
- 'action.devices.traits.StartStop': {
311
- command: 'start',
312
- getter: 'isRunning',
313
- defaultAttributes: ` {
314
- "pausable": false,
315
- "availableZones": [
316
- "kitchen",
317
- "living room",
318
- "master bedroom"
319
- ]
320
- }`,
321
- },
322
- 'action.devices.traits.TemperatureControl_temperatureSetpointCelsius': {
323
- command: 'temperature',
324
- getter: 'temperatureSetpointCelsius',
325
- defaultAttributes: `{
326
- "temperatureRange": {
327
- "minThresholdCelsius": 30,
328
- "maxThresholdCelsius": 100
329
- },
330
- "temperatureStepCelsius": 1,
331
- "temperatureUnitForUX": "C"
332
- }`,
333
- },
334
- 'action.devices.traits.TemperatureControl_temperatureAmbientCelsius': {
335
- command: '',
336
- getter: 'temperatureAmbientCelsius',
337
- defaultAttributes: '{}',
338
- },
339
- 'action.devices.traits.TemperatureSetting_thermostatTemperatureSetpoint': {
340
- command: 'thermostatTemperatureSetpoint',
341
- defaultAttributes: `{
342
- "availableThermostatModes": "off,heat,cool,on",
343
- "thermostatTemperatureUnit": "C"
344
- }`,
345
- },
346
- 'action.devices.traits.TemperatureSetting_thermostatMode': {
347
- command: 'thermostatMode',
348
- defaultAttributes: `{}`,
349
- },
350
- 'action.devices.traits.TemperatureSetting_thermostatTemperatureAmbient': {
351
- command: '',
352
- getter: 'thermostatTemperatureAmbient',
353
- defaultAttributes: `{}`,
354
- },
355
- 'action.devices.traits.TemperatureSetting_thermostatHumidityAmbient': {
356
- command: '',
357
- getter: 'thermostatHumidityAmbient',
358
- defaultAttributes: `{}`,
359
- },
360
- 'action.devices.traits.Timer': {
361
- command: 'timerRemainingSec',
362
- defaultAttributes: `{
363
- "temperatureRange": {
364
- "minThresholdCelsius": 65.5,
365
- "maxThresholdCelcius": 288
366
- },
367
- "temperatureUnitForUX": "C",
368
- "pausable": false,
369
- "maxTimerLimitSec": 7200,
370
- "commandOnlyTimer": false
371
- }`,
372
- },
373
- 'action.devices.traits.Toggles': {
374
- command: 'updateToggleSettings',
375
- defaultAttributes: `{
376
- "availableToggles": [
377
- {
378
- "name": "sterilization",
379
- "name_values": [
380
- {
381
- "name_synonym": [
382
- "bio-clean",
383
- "ultrasound"
384
- ],
385
- "lang": "en"
386
- }
387
- ]
388
- }
389
- ]
390
- }`,
391
- },
392
- 'action.devices.traits.Volume': {
393
- command: 'volumeLevel',
394
- defaultAttributes: '{}',
395
- },
396
- };
397
-
398
- const customToTraitEnum = {
399
- on: 'action.devices.traits.OnOff',
400
- openClose: 'action.devices.traits.OpenClose',
401
- openDirection: 'action.devices.traits.OpenClose',
402
- openPercent: 'action.devices.traits.OpenClose',
403
- isLocked: 'action.devices.traits.LockUnlock',
404
- brightness: 'action.devices.traits.Brightness',
405
- thermostatTemperatureSetpoint: 'action.devices.traits.TemperatureSetting_thermostatTemperatureSetpoint',
406
- thermostatTemperatureAmbient: 'action.devices.traits.TemperatureSetting_thermostatTemperatureAmbient',
407
- thermostatHumidityAmbient: 'action.devices.traits.TemperatureSetting_thermostatHumidityAmbient',
408
- color_spectrumRGB: 'action.devices.traits.ColorSetting_spectrumRGB',
409
- color_hue: 'action.devices.traits.ColorSetting_spectrumRGB',
410
- color_saturation: 'action.devices.traits.ColorSetting_spectrumRGB',
411
- color_temperature: 'action.devices.traits.ColorSetting_temperature',
412
- };
413
-
414
- const URL_STATUS = 'https://gstatus.iobroker.in/v1/googleHomeStatus';
415
-
416
- const ignoreIds = [/^system\./, /^script\./];
417
-
418
- class GoogleHome {
419
- constructor(adapter, urlKey) {
420
- this.adapter = adapter;
421
- this.urlKey = urlKey;
422
- this.lang = 'de';
423
- this.agentUserId = adapter.config.login.replace(/[^-_:a-zA-Z1-9]/g, '_');
424
-
425
- this.smartDevices = {};
426
- this.smartDevicesSentToGoogle = {};
427
- this.enums = [];
428
- this.usedIds = [];
429
- this.detector = new ChannelDetector();
430
- this.urlKeyOk = false;
431
- this.keyPromise = null;
432
- this.keyPromiseTime = null;
433
- this.unknownDevices = {};
434
- this.reportedStates = {};
435
- this.rateCalculation = [];
436
-
437
- this.tasksTimer = null;
438
-
439
- this.converter = {
440
- [Types.socket]: this.processSocket.bind(this),
441
- [Types.light]: this.processLight.bind(this),
442
- [Types.info]: this.processInfo.bind(this),
443
- [Types.dimmer]: this.processDimmer.bind(this),
444
- [Types.rgbSingle]: this.processRgbSingle.bind(this),
445
- [Types.rgb]: this.processRgb.bind(this),
446
- [Types.hue]: this.processHue.bind(this),
447
- [Types.ct]: this.processCT.bind(this),
448
- [Types.temperature]: this.processTemperature.bind(this),
449
- [Types.thermostat]: this.processThermostat.bind(this),
450
- [Types.button]: this.processButton.bind(this),
451
- [Types.windowTilt]: this.processWindowTilt.bind(this),
452
- [Types.door]: this.processWindowTilt.bind(this),
453
- [Types.window]: this.processWindowTilt.bind(this),
454
- [Types.blind]: this.processBlind.bind(this),
455
- [Types.slider]: this.processBlind.bind(this),
456
- [Types.media]: this.processMedia.bind(this),
457
- };
458
- }
459
-
460
- checkUrlKey() {
461
- const now = Date.now();
462
- if (!this.keyPromise || now - this.keyPromiseTime > 900000) {
463
- /* 15 Minutes */
464
- this.keyPromiseTime = now;
465
-
466
- const url = `${URL_STATUS}?user=${encodeURIComponent(this.adapter.config.login)}&urlKey=${encodeURIComponent(this.urlKey ? this.urlKey.key : '')}&p=${PROTOCOL_VERSION}&v=${version}`;
467
-
468
- this.keyPromise = axios
469
- .get(url, { validateStatus: status => status === 200 })
470
- .then(response => {
471
- this.adapter.log.debug(`[GHOME] CHECK URL reported: ${JSON.stringify(response.data)}`);
472
- this.urlKeyOk = true;
473
- })
474
- .catch(error => {
475
- let errorMessage;
476
- if (error.response) {
477
- errorMessage = error.response.data || error.response.status;
478
- } else if (error.request) {
479
- errorMessage = 'No answer';
480
- } else {
481
- errorMessage = error.message;
482
- }
483
- this.adapter.config.googleHome &&
484
- this.adapter.log.error(
485
- `[GHOME] Url Key error. Google Request and Response are working. But device states are not reported automatically. If you have pro license please try to delete iot.0.certs: ${JSON.stringify(errorMessage)}`,
486
- );
487
- });
488
- }
489
-
490
- return this.keyPromise;
491
- }
492
-
493
- _subscribeAllIds(ids, cb) {
494
- if (!ids || !ids.length) {
495
- cb && cb();
496
- } else {
497
- const id = ids.shift();
498
- if (!id) {
499
- setImmediate(() => this._subscribeAllIds(ids, cb));
500
- } else {
501
- console.log(`[GHOME] Subscribe ${id}`);
502
- this.adapter.subscribeForeignStates(id, () => setImmediate(() => this._subscribeAllIds(ids, cb)));
503
- }
504
- }
505
- }
506
-
507
- _unsubscribeAllIds(ids, cb) {
508
- if (!ids || !ids.length) {
509
- cb && cb();
510
- } else {
511
- const id = ids.shift();
512
- if (!id) {
513
- setImmediate(() => this._unsubscribeAllIds(ids, cb));
514
- } else {
515
- console.log(`[GHOME] Unsubscribe ${id}`);
516
- this.adapter.unsubscribeForeignStates(id, () => setImmediate(() => this._unsubscribeAllIds(ids, cb)));
517
- }
518
- }
519
- }
520
-
521
- unsubscribeAllIds(cb) {
522
- const ids = [];
523
- this.smartDevices &&
524
- Object.keys(this.smartDevices).forEach(devId => {
525
- const custom = this.smartDevices[devId].customData;
526
- custom &&
527
- Object.keys(custom).forEach(attr => {
528
- attr && attr.startsWith('get_') && !ids.includes(custom[attr]) && ids.push(custom[attr]);
529
- });
530
- });
531
-
532
- this.adapter.log.debug(`[GHOME] Unsubscribe ${ids.length} states for google home`);
533
- this._unsubscribeAllIds(ids, () => {
534
- this.adapter.log.debug(`[GHOME] Unsubscribe done`);
535
- cb && cb();
536
- });
537
- }
538
-
539
- subscribeAllIds(cb) {
540
- const ids = [];
541
- this.smartDevices &&
542
- Object.keys(this.smartDevices).forEach(devId => {
543
- const custom = this.smartDevices[devId].customData;
544
- custom &&
545
- Object.keys(custom).forEach(
546
- attr =>
547
- attr && attr.startsWith('get_') && !ids.includes(custom[attr]) && ids.push(custom[attr]),
548
- );
549
- });
550
-
551
- this.adapter.log.debug(`[GHOME] Subscribe ${ids.length} states for google home`);
552
-
553
- this._subscribeAllIds(ids, () => {
554
- this.adapter.log.debug(`[GHOME] Subscribe done`);
555
- cb && cb();
556
- });
557
- }
558
-
559
- getObjectName(obj, onlySimpleName) {
560
- let name = '';
561
- // extract from smartName the name
562
- if (!onlySimpleName) {
563
- if (this.adapter.config.noCommon) {
564
- if (
565
- obj.common &&
566
- obj.common.custom &&
567
- obj.common.custom[this.adapter.namespace] &&
568
- obj.common.custom[this.adapter.namespace].smartName &&
569
- obj.common.custom[this.adapter.namespace].smartName !== 'ignore'
570
- ) {
571
- name = obj.common.custom[this.adapter.namespace].smartName;
572
- }
573
- } else {
574
- if (
575
- obj.common &&
576
- obj.common.smartName &&
577
- obj.common.smartName !== true &&
578
- obj.common.smartName !== 'ignore'
579
- ) {
580
- name = obj.common.smartName;
581
- }
582
- }
583
- }
584
- // if no smart name found, get the normal key
585
- if (!name && obj && obj.common && obj.common.name) {
586
- name = obj.common.name;
587
- }
588
-
589
- if (name && typeof name === 'object') {
590
- name = name[this.lang] || name['en'];
591
- }
592
-
593
- if (!name && obj) {
594
- name = obj._id.split('.').pop();
595
- }
596
-
597
- return name;
598
- }
599
-
600
- checkName(name, obj, room, func) {
601
- if (!name) {
602
- name = name || this.getObjectName(obj) || '';
603
- name = name.replace(/[^a-zA-ZöäüßÖÄÜа-яА-Я0-9ÉéÈèÀàÂâÊêÙùÛûÇçÎîËëÏïŸÿÔôŒœãõìòáíóú]/g, ' ');
604
- let _name = name.toLowerCase();
605
- let pos;
606
- if (room) {
607
- pos = _name.indexOf(room.toLowerCase());
608
- if (pos !== -1) {
609
- name = name.substring(0, pos) + name.substring(pos + room.length);
610
- _name = _name.substring(0, pos) + _name.substring(pos + room.length);
611
- }
612
- }
613
- if (func) {
614
- pos = _name.indexOf(func.toLowerCase());
615
- if (pos !== -1) {
616
- name = name.substring(0, pos) + name.substring(pos + func.length);
617
- }
618
- }
619
- name = name.replace(/\s\s+/g, ' ').trim();
620
- }
621
- return name || func;
622
- }
623
-
624
- processSocket(id, control, name, room, func, obj) {
625
- const setOnOffState = control.states.find(state => state.name === 'SET' && state.id);
626
- const set_on = setOnOffState && setOnOffState.id;
627
-
628
- const getOnOffState = control.states.find(state => state.name === 'ACTUAL' && state.id);
629
- const get_on = (getOnOffState && getOnOffState.id) || set_on;
630
-
631
- name = this.checkName(name, obj, room, func);
632
-
633
- return {
634
- type: 'action.devices.types.OUTLET',
635
- traits: ['action.devices.traits.OnOff'],
636
- name: {
637
- defaultNames: [room + 'steckdose'],
638
- name: this.getObjectName(obj) || name,
639
- nicknames: [name],
640
- },
641
- willReportState: true,
642
- roomHint: room || '',
643
- deviceInfo: {
644
- manufacturer: 'ioBroker',
645
- model: id.split('.')[0],
646
- },
647
- customData: {
648
- set_on,
649
- get_on,
650
- },
651
- id,
652
- };
653
- }
654
-
655
- processLight(id, control, name, room, func, obj) {
656
- const setOnOffState = control.states.find(state => state.name === 'SET' && state.id);
657
- const set_on = setOnOffState && setOnOffState.id;
658
-
659
- const getOnOffState = control.states.find(state => state.name === 'ACTUAL' && state.id);
660
- const get_on = (getOnOffState && getOnOffState.id) || set_on;
661
-
662
- const traits = ['action.devices.traits.OnOff'];
663
- name = this.checkName(name, obj, room, func);
664
-
665
- return {
666
- type: 'action.devices.types.LIGHT',
667
- traits,
668
- name: {
669
- defaultNames: [textsT(this.lang, 'light', room)],
670
- name: this.getObjectName(obj) || name,
671
- nicknames: [name],
672
- },
673
- willReportState: true,
674
- roomHint: room || '',
675
- deviceInfo: {
676
- manufacturer: 'ioBroker',
677
- model: id.split('.')[0],
678
- },
679
- customData: {
680
- set_on,
681
- get_on,
682
- },
683
- id,
684
- };
685
- }
686
-
687
- processInfo(id, control, name, room, func, obj) {
688
- const getOnOffState = control.states.find(state => state.name === 'ACTUAL' && state.id);
689
- const get_on = getOnOffState && getOnOffState.id;
690
-
691
- name = this.checkName(name, obj, room, func);
692
-
693
- const get_isLocked = get_on;
694
- const set_lock = get_on;
695
- const set_openPercent = set_lock;
696
- const get_openPercent = get_isLocked;
697
-
698
- const traits = [];
699
-
700
- traits.push('action.devices.traits.LockUnlock');
701
- traits.push('action.devices.traits.OpenClose');
702
-
703
- return {
704
- type: 'action.devices.types.SENSOR',
705
- traits: traits,
706
- displayTraits: ['action.devices.traits.OpenClose'],
707
- name: {
708
- defaultNames: [room + func],
709
- name: this.getObjectName(obj) || name,
710
- nicknames: [name],
711
- },
712
- attributes: {
713
- queryOnlyOpenClose: true,
714
- },
715
- displayAttributes: JSON.stringify({
716
- queryOnlyOpenClose: true,
717
- }),
718
- willReportState: true,
719
- roomHint: room || '',
720
- deviceInfo: {
721
- manufacturer: 'ioBroker',
722
- model: id.split('.')[0],
723
- },
724
- customData: {
725
- get_isLocked,
726
- set_lock,
727
- set_openPercent,
728
- get_openPercent,
729
- },
730
- id,
731
- };
732
- }
733
-
734
- processButton(id, control, name, room, func, obj) {
735
- const setOnOffState = control.states.find(state => state.name === 'SET' && state.id);
736
- const set_on = setOnOffState && setOnOffState.id;
737
-
738
- const getOnOffState = control.states.find(state => state.name === 'ACTUAL' && state.id);
739
- const get_on = (getOnOffState && getOnOffState.id) || set_on;
740
-
741
- const traits = ['action.devices.traits.OnOff'];
742
- name = this.checkName(name, obj, room, func);
743
-
744
- return {
745
- type: 'action.devices.types.SWITCH',
746
- traits,
747
- name: {
748
- defaultNames: [room + func],
749
- name: this.getObjectName(obj) || name,
750
- nicknames: [name],
751
- },
752
- willReportState: true,
753
- roomHint: room || '',
754
- deviceInfo: {
755
- manufacturer: 'ioBroker',
756
- model: id.split('.')[0],
757
- },
758
- customData: {
759
- set_on,
760
- get_on,
761
- },
762
- id,
763
- };
764
- }
765
-
766
- processDimmer(id, control, name, room, func, obj) {
767
- const setBrightnessState = control.states.find(state => state.name === 'SET' && state.id);
768
- let set_brightness = setBrightnessState && setBrightnessState.id;
769
- if (set_brightness.indexOf('.dimspeed') !== -1) {
770
- let idArray = set_brightness.split('.');
771
- idArray.pop();
772
- idArray.push('bri');
773
- set_brightness = idArray.join('.');
774
- }
775
- const getBrightnessState = control.states.find(state => state.name === 'ACTUAL' && state.id);
776
- const get_brightness = (getBrightnessState && getBrightnessState.id) || set_brightness;
777
-
778
- const setOnOffState = control.states.find(state => state.name === 'ON_SET' && state.id);
779
- const set_on = (setOnOffState && setOnOffState.id) || set_brightness;
780
-
781
- const getOnOffState = control.states.find(state => state.name === 'ON_ACTUAL' && state.id);
782
- const get_on = (getOnOffState && getOnOffState.id) || set_on;
783
-
784
- const traits = [];
785
-
786
- if (set_on) {
787
- traits.push('action.devices.traits.OnOff');
788
- }
789
-
790
- if (set_brightness) {
791
- traits.push('action.devices.traits.Brightness');
792
- }
793
-
794
- name = this.checkName(name, obj, room, func);
795
-
796
- return {
797
- type: 'action.devices.types.LIGHT',
798
- traits,
799
- displayTraits: ['action.devices.traits.Brightness'],
800
- name: {
801
- defaultNames: [textsT(this.lang, 'light', room)],
802
- name: this.getObjectName(obj) || name,
803
- nicknames: [name],
804
- },
805
- willReportState: true,
806
- roomHint: room || '',
807
- deviceInfo: {
808
- manufacturer: 'ioBroker',
809
- model: id.split('.')[0],
810
- },
811
- customData: {
812
- set_on,
813
- get_on,
814
- set_brightness,
815
- get_brightness,
816
- },
817
- id,
818
- };
819
- }
820
-
821
- processHue(id, control, name, room, func, obj) {
822
- let setBrightnessState = control.states.find(state => state.name === 'BRIGHTNESS' && state.id);
823
- if (!setBrightnessState) {
824
- setBrightnessState = control.states.find(state => state.name === 'DIMMER' && state.id);
825
- }
826
- const set_brightness = setBrightnessState && setBrightnessState.id;
827
- const get_brightness = set_brightness;
828
-
829
- let setOnOffState = control.states.find(state => state.name === 'ON' && state.id);
830
-
831
- const set_on = (setOnOffState && setOnOffState.id) || set_brightness;
832
- const get_on = set_on;
833
-
834
- let setHueState = control.states.find(state => state.name === 'HUE' && state.id);
835
-
836
- const set_color_hue = setHueState && setHueState.id;
837
- const get_color_hue = set_color_hue;
838
-
839
- let setSaturationState = control.states.find(state => state.name === 'SATURATION' && state.id);
840
-
841
- const set_color_saturation = setSaturationState && setSaturationState.id;
842
- const get_color_saturation = set_color_saturation;
843
-
844
- let setTempState = control.states.find(state => state.name === 'TEMPERATURE' && state.id);
845
-
846
- const set_color_temperature = setTempState && setTempState.id;
847
- const get_color_temperature = set_color_temperature;
848
-
849
- const traits = [];
850
-
851
- if (set_on) {
852
- traits.push('action.devices.traits.OnOff');
853
- }
854
-
855
- if (set_brightness) {
856
- traits.push('action.devices.traits.Brightness');
857
- }
858
- if (set_color_hue) {
859
- traits.push('action.devices.traits.ColorSetting');
860
- }
861
- name = this.checkName(name, obj, room, func);
862
-
863
- return {
864
- type: 'action.devices.types.LIGHT',
865
- traits,
866
- displayTraits: ['action.devices.traits.ColorSetting_spectrumRGB'],
867
-
868
- attributes: {
869
- colorModel: 'rgb',
870
- colorTemperatureRange: {
871
- temperatureMinK: 2000,
872
- temperatureMaxK: 9000,
873
- },
874
- },
875
- displayAttributes: JSON.stringify({
876
- colorModel: 'rgb',
877
- colorTemperatureRange: {
878
- temperatureMinK: 2000,
879
- temperatureMaxK: 9000,
880
- },
881
- }),
882
- name: {
883
- defaultNames: [textsT(this.lang, 'light', room)],
884
- name: this.getObjectName(obj) || name,
885
- nicknames: [name],
886
- },
887
- willReportState: true,
888
- roomHint: room || '',
889
- deviceInfo: {
890
- manufacturer: 'ioBroker',
891
- model: id.split('.')[0],
892
- },
893
- customData: {
894
- set_on,
895
- get_on,
896
- set_brightness,
897
- get_brightness,
898
- set_color_hue,
899
- get_color_hue,
900
- set_color_saturation,
901
- get_color_saturation,
902
- set_color_temperature,
903
- get_color_temperature,
904
- },
905
- id,
906
- };
907
- }
908
-
909
- processRgbSingle(id, control, name, room, func, obj) {
910
- let setBrightnessState = control.states.find(state => state.name === 'BRIGHTNESS' && state.id);
911
- if (!setBrightnessState) {
912
- setBrightnessState = control.states.find(state => state.name === 'DIMMER' && state.id);
913
- }
914
- const set_brightness = setBrightnessState && setBrightnessState.id;
915
- const get_brightness = set_brightness;
916
-
917
- let setOnOffState = control.states.find(state => state.name === 'ON_LIGHT' && state.id);
918
- if (!setOnOffState) {
919
- setOnOffState = control.states.find(state => state.name === 'ON' && state.id);
920
- }
921
- const set_on = (setOnOffState && setOnOffState.id) || set_brightness;
922
- const get_on = set_on;
923
-
924
- let setRGBState = control.states.find(state => state.name === 'RGB' && state.id);
925
-
926
- const set_color_spectrumRGB = setRGBState && setRGBState.id;
927
- const get_color_spectrumRGB = set_color_spectrumRGB;
928
-
929
- let setTempState = control.states.find(state => state.name === 'TEMPERATURE' && state.id);
930
-
931
- const set_color_temperature = setTempState && setTempState.id;
932
- const get_color_temperature = set_color_temperature;
933
-
934
- const traits = [];
935
-
936
- if (set_on) {
937
- traits.push('action.devices.traits.OnOff');
938
- }
939
-
940
- if (set_brightness) {
941
- traits.push('action.devices.traits.Brightness');
942
- }
943
-
944
- if (set_color_spectrumRGB) {
945
- traits.push('action.devices.traits.ColorSetting');
946
- }
947
-
948
- name = this.checkName(name, obj, room, func);
949
-
950
- return {
951
- type: 'action.devices.types.LIGHT',
952
- traits,
953
- displayTraits: ['action.devices.traits.ColorSetting_spectrumRGB'],
954
-
955
- attributes: {
956
- colorModel: 'rgb',
957
- colorTemperatureRange: {
958
- temperatureMinK: 2000,
959
- temperatureMaxK: 9000,
960
- },
961
- },
962
- displayAttributes: JSON.stringify({
963
- colorModel: 'rgb',
964
- colorTemperatureRange: {
965
- temperatureMinK: 2000,
966
- temperatureMaxK: 9000,
967
- },
968
- }),
969
- name: {
970
- defaultNames: [textsT(this.lang, 'light', room)],
971
- name: this.getObjectName(obj) || name,
972
- nicknames: [name],
973
- },
974
- willReportState: true,
975
- roomHint: room || '',
976
- deviceInfo: {
977
- manufacturer: 'ioBroker',
978
- model: id.split('.')[0],
979
- },
980
- customData: {
981
- set_on,
982
- get_on,
983
- set_brightness,
984
- get_brightness,
985
- set_color_spectrumRGB,
986
- get_color_spectrumRGB,
987
- set_color_temperature,
988
- get_color_temperature,
989
- },
990
- id,
991
- };
992
- }
993
-
994
- processRgb(id, control, name, room, func, obj) {
995
- let setBrightnessState = control.states.find(state => state.name === 'BRIGHTNESS' && state.id);
996
- if (!setBrightnessState) {
997
- setBrightnessState = control.states.find(state => state.name === 'DIMMER' && state.id);
998
- }
999
- const set_brightness = setBrightnessState && setBrightnessState.id;
1000
- const get_brightness = set_brightness;
1001
-
1002
- let setOnOffState = control.states.find(state => state.name === 'ON_LIGHT' && state.id);
1003
- if (!setOnOffState) {
1004
- setOnOffState = control.states.find(state => state.name === 'ON' && state.id);
1005
- }
1006
- const set_on = (setOnOffState && setOnOffState.id) || set_brightness;
1007
- const get_on = set_on;
1008
-
1009
- let setTempState = control.states.find(state => state.name === 'TEMPERATURE' && state.id);
1010
-
1011
- const set_color_temperature = setTempState && setTempState.id;
1012
- const get_color_temperature = set_color_temperature;
1013
-
1014
- let setRState = control.states.find(state => state.name === 'RED' && state.id);
1015
-
1016
- const set_color_R = setRState && setRState.id;
1017
- const get_color_R = set_color_R;
1018
-
1019
- let setGState = control.states.find(state => state.name === 'GREEN' && state.id);
1020
-
1021
- const set_color_G = setGState && setGState.id;
1022
- const get_color_G = set_color_G;
1023
-
1024
- let setBState = control.states.find(state => state.name === 'BLUE' && state.id);
1025
-
1026
- const set_color_B = setBState && setBState.id;
1027
- const get_color_B = set_color_B;
1028
-
1029
- const traits = [];
1030
-
1031
- if (set_on) {
1032
- traits.push('action.devices.traits.OnOff');
1033
- }
1034
-
1035
- if (set_brightness) {
1036
- traits.push('action.devices.traits.Brightness');
1037
- }
1038
-
1039
- traits.push('action.devices.traits.ColorSetting');
1040
-
1041
- name = this.checkName(name, obj, room, func);
1042
-
1043
- return {
1044
- type: 'action.devices.types.LIGHT',
1045
- traits,
1046
- displayTraits: ['action.devices.traits.ColorSetting_spectrumRGB'],
1047
-
1048
- attributes: {
1049
- colorModel: 'rgb',
1050
- colorTemperatureRange: {
1051
- temperatureMinK: 2000,
1052
- temperatureMaxK: 9000,
1053
- },
1054
- },
1055
- displayAttributes: JSON.stringify({
1056
- colorModel: 'rgb',
1057
- colorTemperatureRange: {
1058
- temperatureMinK: 2000,
1059
- temperatureMaxK: 9000,
1060
- },
1061
- }),
1062
- name: {
1063
- defaultNames: [textsT(this.lang, 'light', room)],
1064
- name: this.getObjectName(obj) || name,
1065
- nicknames: [name],
1066
- },
1067
- willReportState: true,
1068
- roomHint: room || '',
1069
- deviceInfo: {
1070
- manufacturer: 'ioBroker',
1071
- model: id.split('.')[0],
1072
- },
1073
- customData: {
1074
- set_on,
1075
- get_on,
1076
- set_brightness,
1077
- get_brightness,
1078
- set_color_temperature,
1079
- get_color_temperature,
1080
- set_color_R,
1081
- get_color_R,
1082
- set_color_G,
1083
- get_color_G,
1084
- set_color_B,
1085
- get_color_B,
1086
- },
1087
- id,
1088
- };
1089
- }
1090
-
1091
- processCT(id, control, name, room, func, obj) {
1092
- let setBrightnessState = control.states.find(state => state.name === 'BRIGHTNESS' && state.id);
1093
- if (!setBrightnessState) {
1094
- setBrightnessState = control.states.find(state => state.name === 'DIMMER' && state.id);
1095
- }
1096
- const set_brightness = setBrightnessState && setBrightnessState.id;
1097
- const get_brightness = set_brightness;
1098
-
1099
- let setOnOffState = control.states.find(state => state.name === 'ON' && state.id);
1100
- if (!setOnOffState) {
1101
- setOnOffState = control.states.find(state => state.name === 'ON_LIGHT' && state.id);
1102
- }
1103
- const set_on = (setOnOffState && setOnOffState.id) || set_brightness;
1104
- const get_on = set_on;
1105
-
1106
- let setTempState = control.states.find(state => state.name === 'TEMPERATURE' && state.id);
1107
-
1108
- const set_color_temperature = setTempState && setTempState.id;
1109
- const get_color_temperature = set_color_temperature;
1110
-
1111
- const traits = [];
1112
-
1113
- if (set_on) {
1114
- traits.push('action.devices.traits.OnOff');
1115
- }
1116
-
1117
- if (set_brightness) {
1118
- traits.push('action.devices.traits.Brightness');
1119
- }
1120
- if (set_color_temperature) {
1121
- traits.push('action.devices.traits.ColorSetting');
1122
- }
1123
- name = this.checkName(name, obj, room, func);
1124
-
1125
- return {
1126
- type: 'action.devices.types.LIGHT',
1127
- traits,
1128
- displayTraits: ['action.devices.traits.ColorSetting_temperature'],
1129
- attributes: {
1130
- colorModel: 'rgb',
1131
- colorTemperatureRange: {
1132
- temperatureMinK: 2000,
1133
- temperatureMaxK: 9000,
1134
- },
1135
- },
1136
- displayAttributes: JSON.stringify({
1137
- colorModel: 'rgb',
1138
- colorTemperatureRange: {
1139
- temperatureMinK: 2000,
1140
- temperatureMaxK: 9000,
1141
- },
1142
- }),
1143
- name: {
1144
- defaultNames: [textsT(this.lang, 'light', room)],
1145
- name: this.getObjectName(obj) || name,
1146
- nicknames: [name],
1147
- },
1148
- willReportState: true,
1149
- roomHint: room || '',
1150
- deviceInfo: {
1151
- manufacturer: 'ioBroker',
1152
- model: id.split('.')[0],
1153
- },
1154
- customData: {
1155
- set_on,
1156
- get_on,
1157
- set_brightness,
1158
- get_brightness,
1159
- set_color_temperature,
1160
- get_color_temperature,
1161
- },
1162
- id,
1163
- };
1164
- }
1165
-
1166
- processWindowTilt(id, control, name, room, func, obj) {
1167
- const getWindowTile = control.states.find(state => state.name === 'ACTUAL' && state.id);
1168
- const get_isLocked = getWindowTile && getWindowTile.id;
1169
- const set_lock = getWindowTile && getWindowTile.id;
1170
- const set_openPercent = set_lock;
1171
- const get_openPercent = get_isLocked;
1172
-
1173
- const traits = [];
1174
-
1175
- traits.push('action.devices.traits.LockUnlock');
1176
- traits.push('action.devices.traits.OpenClose');
1177
-
1178
- name = this.checkName(name, obj, room, func);
1179
-
1180
- return {
1181
- type: 'action.devices.types.WINDOW',
1182
- traits,
1183
- attributes: {
1184
- queryOnlyOpenClose: true,
1185
- },
1186
- displayAttributes: JSON.stringify({
1187
- queryOnlyOpenClose: true,
1188
- }),
1189
- name: {
1190
- defaultNames: [textsT(this.lang, 'window', room)],
1191
- name: this.getObjectName(obj) || name,
1192
- nicknames: [name],
1193
- },
1194
- willReportState: true,
1195
- roomHint: room || '',
1196
- deviceInfo: {
1197
- manufacturer: 'ioBroker',
1198
- model: id.split('.')[0],
1199
- },
1200
- customData: {
1201
- set_lock,
1202
- get_isLocked,
1203
- set_openPercent,
1204
- get_openPercent,
1205
- },
1206
- id,
1207
- };
1208
- }
1209
-
1210
- processBlind(id, control, name, room, func, obj) {
1211
- const getOpenPercent = control.states.find(state => state.name === 'SET' && state.id);
1212
- const set_openPercent = getOpenPercent && getOpenPercent.id;
1213
- const get_openPercent = set_openPercent;
1214
-
1215
- const getOpenDirection = control.states.find(state => state.name === 'DIRECTION' && state.id);
1216
- const set_openDirection = getOpenDirection && getOpenDirection.id;
1217
- const get_openDirection = set_openDirection;
1218
-
1219
- const traits = [];
1220
-
1221
- traits.push('action.devices.traits.OpenClose');
1222
-
1223
- name = this.checkName(name, obj, room, func);
1224
-
1225
- return {
1226
- type: 'action.devices.types.BLINDS',
1227
- traits,
1228
- name: {
1229
- defaultNames: [textsT(this.lang, 'blinds', room)],
1230
- name: this.getObjectName(obj) || name,
1231
- nicknames: [name],
1232
- },
1233
- willReportState: true,
1234
- roomHint: room || '',
1235
- deviceInfo: {
1236
- manufacturer: 'ioBroker',
1237
- model: id.split('.')[0],
1238
- },
1239
- customData: {
1240
- set_openPercent,
1241
- get_openPercent,
1242
- set_openDirection,
1243
- get_openDirection,
1244
- },
1245
- id,
1246
- };
1247
- }
1248
-
1249
- processTemperature(id, control, name, room, func, obj) {
1250
- const setThermostatTemperatureSetpoint = control.states.find(state => state.name === 'SET' && state.id);
1251
- const set_thermostatTemperatureSetpoint =
1252
- setThermostatTemperatureSetpoint && setThermostatTemperatureSetpoint.id;
1253
-
1254
- const getThermostatTemperatureAmbient = control.states.find(state => state.name === 'ACTUAL' && state.id);
1255
- const get_thermostatTemperatureAmbient =
1256
- (getThermostatTemperatureAmbient && getThermostatTemperatureAmbient.id) ||
1257
- set_thermostatTemperatureSetpoint;
1258
-
1259
- const getThermostatHumidityAmbient = control.states.find(state => state.name === 'SECOND' && state.id);
1260
- const get_thermostatHumidityAmbient = getThermostatHumidityAmbient && getThermostatHumidityAmbient.id;
1261
-
1262
- const traits = [];
1263
- traits.push('action.devices.traits.TemperatureSetting');
1264
-
1265
- name = this.checkName(name, obj, room, func);
1266
-
1267
- return {
1268
- type: 'action.devices.types.THERMOSTAT',
1269
- traits,
1270
- displayTraits: ['action.devices.traits.TemperatureSetting_thermostatTemperatureSetpoint'],
1271
- attributes: {
1272
- queryOnlyTemperatureSetting: true,
1273
- thermostatTemperatureUnit: 'C',
1274
- },
1275
- displayAttributes: JSON.stringify({
1276
- queryOnlyTemperatureSetting: true,
1277
- thermostatTemperatureUnit: 'C',
1278
- }),
1279
- name: {
1280
- defaultNames: [textsT(this.lang, 'thermostat', room)],
1281
- name: this.getObjectName(obj) || name,
1282
- nicknames: [name],
1283
- },
1284
- willReportState: true,
1285
- roomHint: room || '',
1286
- deviceInfo: {
1287
- manufacturer: 'ioBroker',
1288
- model: id.split('.')[0],
1289
- },
1290
- customData: {
1291
- set_thermostatTemperatureSetpoint,
1292
- get_thermostatTemperatureAmbient,
1293
- get_thermostatHumidityAmbient,
1294
- },
1295
- id,
1296
- };
1297
- }
1298
-
1299
- processThermostat(id, control, name, room, func, obj) {
1300
- const setThermostatTemperatureSetpoint = control.states.find(state => state.name === 'SET' && state.id);
1301
- const set_thermostatTemperatureSetpoint =
1302
- setThermostatTemperatureSetpoint && setThermostatTemperatureSetpoint.id;
1303
- const get_thermostatTemperatureSetpoint = set_thermostatTemperatureSetpoint;
1304
- const getThermostatTemperatureAmbient = control.states.find(state => state.name === 'ACTUAL' && state.id);
1305
- const get_thermostatTemperatureAmbient =
1306
- (getThermostatTemperatureAmbient && getThermostatTemperatureAmbient.id) ||
1307
- set_thermostatTemperatureSetpoint;
1308
-
1309
- const getThermostatHumidityAmbient = control.states.find(state => state.name === 'HUMIDITY' && state.id);
1310
- const get_thermostatHumidityAmbient = getThermostatHumidityAmbient && getThermostatHumidityAmbient.id;
1311
-
1312
- const traits = [];
1313
- traits.push('action.devices.traits.TemperatureSetting');
1314
-
1315
- name = this.checkName(name, obj, room, func);
1316
-
1317
- return {
1318
- type: 'action.devices.types.THERMOSTAT',
1319
- traits,
1320
- displayTraits: ['action.devices.traits.TemperatureSetting_thermostatTemperatureSetpoint'],
1321
- attributes: {
1322
- availableThermostatModes: 'off,heat,cool,on',
1323
- thermostatTemperatureUnit: 'C',
1324
- },
1325
- displayAttributes: JSON.stringify({
1326
- availableThermostatModes: 'off,heat,cool,on',
1327
- thermostatTemperatureUnit: 'C',
1328
- }),
1329
-
1330
- name: {
1331
- defaultNames: [textsT(this.lang, 'thermostat', room)],
1332
- name: this.getObjectName(obj) || name,
1333
- nicknames: [name],
1334
- },
1335
- willReportState: false,
1336
- roomHint: room || '',
1337
- deviceInfo: {
1338
- manufacturer: 'ioBroker',
1339
- model: id.split('.')[0],
1340
- },
1341
- customData: {
1342
- set_thermostatTemperatureSetpoint,
1343
- get_thermostatTemperatureSetpoint,
1344
- get_thermostatTemperatureAmbient,
1345
- get_thermostatHumidityAmbient,
1346
- },
1347
- id,
1348
- };
1349
- }
1350
-
1351
- processMedia(id, control, name, room, func, obj) {
1352
- const setOnOffState = control.states.find(state => state.name === 'STATE' && state.id);
1353
- const set_on = setOnOffState && setOnOffState.id;
1354
- const get_on = set_on;
1355
-
1356
- const setPlayState = control.states.find(state => state.name === 'PLAY' && state.id);
1357
- const set_mediaPlay = (setPlayState && setPlayState.id) || set_on;
1358
-
1359
- const setPauseState = control.states.find(state => state.name === 'PAUSE' && state.id);
1360
- const set_mediaPause = setPauseState && setPauseState.id;
1361
-
1362
- const setStopState = control.states.find(state => state.name === 'STOP' && state.id);
1363
- const set_mediaStop = setStopState && setStopState.id;
1364
-
1365
- const setNextState = control.states.find(state => state.name === 'NEXT' && state.id);
1366
- const set_mediaNext = setNextState && setNextState.id;
1367
-
1368
- const setPrevState = control.states.find(state => state.name === 'PREV' && state.id);
1369
- const set_mediaPrev = setPrevState && setPrevState.id;
1370
-
1371
- const setVolumeState = control.states.find(state => state.name === 'VOLUME' && state.id);
1372
- const set_brightness = setVolumeState && setVolumeState.id;
1373
-
1374
- const traits = [
1375
- 'action.devices.traits.OnOff',
1376
- 'action.devices.traits.MediaState',
1377
- 'action.devices.traits.Brightness',
1378
- ];
1379
- name = this.checkName(name, obj, room, func);
1380
-
1381
- return {
1382
- type: 'action.devices.types.SPEAKER',
1383
- traits,
1384
- displayTraits: ['action.devices.traits.Brightness'],
1385
- name: {
1386
- defaultNames: [textsT(this.lang, 'media', room)],
1387
- name: this.getObjectName(obj) || name,
1388
- nicknames: [name],
1389
- },
1390
- willReportState: true,
1391
- roomHint: room || '',
1392
- deviceInfo: {
1393
- manufacturer: 'ioBroker',
1394
- model: id.split('.')[0],
1395
- },
1396
- customData: {
1397
- set_on,
1398
- get_on,
1399
- set_mediaPlay,
1400
- set_mediaPause,
1401
- set_mediaStop,
1402
- set_mediaNext,
1403
- set_mediaPrev,
1404
- set_brightness,
1405
- },
1406
- id,
1407
- };
1408
- }
1409
-
1410
- setLanguage(_lang) {
1411
- this.lang = _lang || 'de';
1412
- }
1413
-
1414
- getSmartName(states, id) {
1415
- if (!id) {
1416
- if (!this.adapter.config.noCommon) {
1417
- if (states.common) {
1418
- return states.common.smartName;
1419
- } else {
1420
- this.adapter.log.warn(
1421
- `[GHOME] No common property for ${JSON.stringify(states)} IoT options available please check the state.`,
1422
- );
1423
- return null;
1424
- }
1425
- } else {
1426
- return states && states.common && states.common.custom && states.common.custom[this.adapter.namespace]
1427
- ? states.common.custom[this.adapter.namespace].smartName
1428
- : undefined;
1429
- }
1430
- } else if (!this.adapter.config.noCommon) {
1431
- return states[id] && states[id].common ? states[id].common.smartName : null;
1432
- } else {
1433
- return states[id] &&
1434
- states[id].common &&
1435
- states[id].common.custom &&
1436
- states[id].common.custom[this.adapter.namespace]
1437
- ? states[id].common.custom[this.adapter.namespace].smartName || null
1438
- : null;
1439
- }
1440
- }
1441
-
1442
- async processState(ids, objects, id, roomName, funcName, result, smartEnum, parentId) {
1443
- try {
1444
- if (!id || !objects[id] || result[id]) {
1445
- return;
1446
- }
1447
- this.adapter.log.debug(`[GHOME] Process: ${id} ${roomName} ${funcName}`);
1448
- let smartName = this.getSmartName(objects, id);
1449
-
1450
- if (smartName !== undefined && (smartName === 'ignore' || smartName === false)) {
1451
- this.adapter.log.warn(
1452
- `[GHOME] ${id} is ignored because the property smartName is false or ignore. To use this state again, remove the property smartName in Object explorer or add it manually under Google Devices`,
1453
- );
1454
- return;
1455
- }
1456
-
1457
- let friendlyName = '';
1458
- if (typeof smartName === 'object' && smartName) {
1459
- friendlyName = smartName[this.lang] || smartName.en;
1460
- }
1461
- if (!friendlyName) {
1462
- friendlyName = this.checkName('', objects[id], roomName, funcName);
1463
- }
1464
-
1465
- //check if comes from smart enum and is not writable
1466
- // if (smartEnum && objects[id].common.write === false) {
1467
- // return;
1468
- // }
1469
-
1470
- result[id] = {};
1471
- result[id].traits = [];
1472
- result[id].customData = {};
1473
- if (parentId) {
1474
- result[id].parentId = parentId;
1475
- }
1476
-
1477
- let childStates = [];
1478
- result[id].ioType = objects[id].type;
1479
- if (objects[id].type === 'channel') {
1480
- childStates = this.getAllStatesInChannel(Object.keys(objects), id);
1481
- } else if (objects[id].type === 'device') {
1482
- childStates = this.getAllStatesInDevice(Object.keys(objects), id);
1483
- // if no states, it may be device without channels
1484
- if (!childStates.length) {
1485
- childStates = this.getAllStatesInChannel(Object.keys(objects), id);
1486
- }
1487
- }
1488
-
1489
- if (typeof smartName === 'object' && smartName) {
1490
- result[id]['conv2GH'] = {};
1491
- result[id]['displayConv2GH'] = '';
1492
- result[id]['conv2iob'] = {};
1493
- result[id]['displayConv2iob'] = '';
1494
- if (smartName.ghConv2GH) {
1495
- result[id]['conv2GH'][id] = smartName.ghConv2GH;
1496
- result[id]['displayConv2GH'] = smartName.ghConv2GH;
1497
- }
1498
- if (smartName.ghConv2iob) {
1499
- result[id]['conv2iob'][id] = smartName.ghConv2iob;
1500
- result[id]['displayConv2iob'] = smartName.ghConv2iob;
1501
- }
1502
- }
1503
- if ((typeof smartName === 'object' && smartName && smartName.ghType && smartName.ghTraits) || parentId) {
1504
- if (smartName && smartName.ghType) {
1505
- result[id].type = smartName.ghType;
1506
- }
1507
- if (smartName && smartName.ghTraits && smartName.ghTraits.length > 0 && smartName.ghTraits[0]) {
1508
- result[id].traits = [smartName.ghTraits[0].split('_')[0]];
1509
- result[id].displayTraits = [smartName.ghTraits[0]];
1510
- }
1511
- try {
1512
- if (smartName && smartName.ghAttributes) {
1513
- result[id].attributes = JSON.parse(smartName.ghAttributes);
1514
- result[id].displayAttributes = JSON.stringify(result[id].attributes);
1515
- }
1516
- } catch (error) {
1517
- this.adapter.log.error(`[GHOME] Cannot parse attributes ${error} ${smartName.ghAttributes}`);
1518
- this.adapter.log.error(`[GHOME] Cannot parse attributes ${error} ${smartName.ghAttributes}`);
1519
- result[id].attributes = {};
1520
- result[id].displayAttributes = smartName.ghAttributes;
1521
- }
1522
- for (let c = 0; c < childStates.length; c++) {
1523
- await this.processState(ids, objects, childStates[c], roomName, funcName, result, false, id);
1524
- }
1525
- } else if (smartEnum) {
1526
- try {
1527
- // try to detect device
1528
- if (id.match(/^hm-rpc\..*?\.CUX/)) {
1529
- this.adapter.log.debug(`[GHOME] Ignore "${id}": Because it is a virtual device`);
1530
- return;
1531
- }
1532
- const options = {
1533
- objects: objects,
1534
- id: id,
1535
- _keysOptional: ids,
1536
- _usedIdsOptional: this.usedIds,
1537
- };
1538
-
1539
- const controls = this.detector.detect(options);
1540
- // if (id.indexOf('deconz.0.Lights.27') !== -1)
1541
- // debugger
1542
- if (controls) {
1543
- let control = controls[0];
1544
- if (controls[0].type === 'socket' && controls[1] && controls[1].type !== 'info') {
1545
- control = controls[1];
1546
- }
1547
- this.adapter.log.debug(`[GHOME] Type: ${control.type}`);
1548
-
1549
- if (this.converter.hasOwnProperty(control.type)) {
1550
- this.adapter.log.info(`[GHOME] ${id} is auto added with type ${control.type}.`);
1551
- result[id] = this.converter[control.type](
1552
- id,
1553
- control,
1554
- friendlyName,
1555
- roomName,
1556
- funcName,
1557
- objects[id],
1558
- );
1559
- result[id].displayTraits = result[id].displayTraits || result[id].traits;
1560
-
1561
- if (typeof smartName === 'object' && smartName && smartName.ghAttributes) {
1562
- result[id].attributes = JSON.parse(smartName.ghAttributes);
1563
- result[id].displayAttributes = JSON.stringify(result[id].attributes);
1564
- }
1565
-
1566
- result[id].smartEnum = 'X';
1567
- result[id]['conv2GH'] = {};
1568
- result[id]['conv2iob'] = {};
1569
-
1570
- if (result[id].customData.set_brightness) {
1571
- const briState = await this.adapter.getForeignObjectAsync(
1572
- result[id].customData.set_brightness,
1573
- );
1574
- if (briState && briState.common && briState.common.max && briState.common.max >= 101) {
1575
- result[id]['conv2GH'][result[id].customData.set_brightness] =
1576
- 'return value/' + briState.common.max / 100;
1577
- result[id]['conv2iob'][result[id].customData.set_brightness] =
1578
- 'return value*' + briState.common.max / 100;
1579
- }
1580
- }
1581
- if (result[id].customData.set_color_temperature) {
1582
- const set_color_temperature = await this.adapter.getForeignObjectAsync(
1583
- result[id].customData.set_color_temperature,
1584
- );
1585
- if (
1586
- set_color_temperature &&
1587
- set_color_temperature.common &&
1588
- set_color_temperature.common.max <= 500
1589
- ) {
1590
- result[id]['conv2GH'][result[id].customData.set_color_temperature] =
1591
- 'return 1000000/value';
1592
- result[id]['conv2iob'][result[id].customData.set_color_temperature] =
1593
- 'return 1000000/value';
1594
- }
1595
- }
1596
-
1597
- result[id].ioType = objects[id].type;
1598
-
1599
- this.adapter.log.debug(
1600
- `[GHOME] Created Google HOME device: ${result[id].name.defaultNames[0]} - ${control.type} - ${id}`,
1601
- );
1602
-
1603
- // childStates.forEach((child) => {
1604
- Object.keys(result[id].customData).forEach(element => {
1605
- // if (element.indexOf('get_') !== -1) {
1606
-
1607
- const childID = result[id].customData[element];
1608
-
1609
- if (!childID) {
1610
- return;
1611
- }
1612
- if (childID === id) {
1613
- this.adapter.log.debug(`[GHOME] SmartEnum is equal child skip child detection`);
1614
- return;
1615
- }
1616
-
1617
- if (result[childID] && !result[childID].smartEnum) {
1618
- result[childID].parentId = id;
1619
- this.adapter.log.warn(
1620
- `[GHOME] ${childID} has custom settings this is overriding auto-detected settings. To use auto-detected settings please delete this state in the instance settings under Google Devices.`,
1621
- );
1622
- return;
1623
- }
1624
- const trait = customToTraitEnum[element.substring(4)];
1625
- result[childID] = {};
1626
- result[childID].traits = [trait];
1627
- result[childID].roomHint = roomName;
1628
- result[childID].smartEnum = 'X';
1629
- result[childID].type = result[id].type;
1630
-
1631
- result[childID].ioType = objects[childID] ? objects[childID].type : '';
1632
- if (element.includes('set_')) {
1633
- result[childID].ioType =
1634
- ` SETTER:\n\u00a0\u00a0\u00a0\u00a0${result[childID].ioType}`;
1635
- }
1636
- result[childID].displayTraits = [trait];
1637
- if (childID && result[id]['conv2GH'][childID]) {
1638
- result[childID]['displayConv2GH'] = result[id]['conv2GH'][childID];
1639
- }
1640
- if (childID && result[id]['conv2iob'][childID]) {
1641
- result[childID]['displayConv2iob'] = result[id]['conv2iob'][childID];
1642
- }
1643
- result[childID].parentId = id;
1644
- result[childID].name = {
1645
- nicknames: [childID],
1646
- };
1647
- result[childID].id = childID;
1648
- // }
1649
- });
1650
- // })
1651
- } else {
1652
- this.adapter.log.info(
1653
- `[GHOME] Cannot auto convert ${id}. Type ${control.type} is not available, yet. If you need the state please add him manually`,
1654
- );
1655
- this.adapter.log.debug(`[GHOME] ${JSON.stringify(control)}`);
1656
- }
1657
- // });
1658
- } else {
1659
- console.log(`[GHOME] Nothing found for ${options.id}`);
1660
- }
1661
- } catch (e) {
1662
- this.adapter.log.error(`[GHOME] Cannot process "${id}": ${e}`);
1663
- this.adapter.log.error(`[GHOME] ${e.stack}`);
1664
- }
1665
- return;
1666
- } else if (typeof smartName === 'object' && smartName && smartName.smartType) {
1667
- //SMARTTYPES = ['LIGHT', 'SWITCH', 'THERMOSTAT', 'ACTIVITY_TRIGGER', 'SCENE_TRIGGER', 'SMARTPLUG', 'SMARTLOCK', 'CAMERA'];
1668
- switch (smartName.smartType) {
1669
- case 'LIGHT':
1670
- result[id].traits = ['action.devices.traits.OnOff'];
1671
- result[id].type = 'action.devices.types.LIGHT';
1672
- break;
1673
- case 'SWITCH':
1674
- result[id].traits = ['action.devices.traits.OnOff'];
1675
- result[id].type = 'action.devices.types.SWITCH';
1676
- break;
1677
- case 'SMARTPLUG':
1678
- result[id].traits = ['action.devices.traits.OnOff'];
1679
- result[id].type = 'action.devices.types.OUTLET';
1680
- break;
1681
- case 'SMARTLOCK':
1682
- result[id].traits = ['action.devices.traits.LockUnlock'];
1683
- result[id].type = 'action.devices.types.DOOR';
1684
- break;
1685
- }
1686
-
1687
- result[id].displayTraits = result[id].displayTraits || result[id].traits;
1688
- result[id].ioType = objects[id].type;
1689
- result[id].smartEnum = 'X';
1690
-
1691
- let friendlyNamesArray = [];
1692
- if (friendlyName) {
1693
- friendlyNamesArray = friendlyName.replace(/, /g, ',').split(',');
1694
- }
1695
-
1696
- result[id].name = {
1697
- defaultNames: [this.getObjectName(objects[id], true)],
1698
- name: friendlyNamesArray[0],
1699
- nicknames: friendlyNamesArray,
1700
- };
1701
- result[id].willReportState = true;
1702
- result[id].roomHint = roomName || '';
1703
- result[id].deviceInfo = {
1704
- manufacturer: 'ioBroker',
1705
- model: id.split('.')[0],
1706
- };
1707
- result[id].id = id;
1708
- result[id].otherDeviceIds = [
1709
- {
1710
- deviceId: id,
1711
- },
1712
- ];
1713
-
1714
- this.adapter.log.debug(
1715
- `[GHOME] Created Google HOME device from Alexa SmartType: ${result[id].name.defaultNames[0]} - ${result[id].type} - ${id}`,
1716
- );
1717
-
1718
- return;
1719
- } else {
1720
- //friendlyName = this.checkName('', objects[id], roomName, funcName);
1721
- delete result[id];
1722
- return;
1723
- }
1724
-
1725
- let friendlyNamesArray = [];
1726
- if (friendlyName) {
1727
- friendlyNamesArray = friendlyName.replace(/, /g, ',').split(',');
1728
- }
1729
-
1730
- result[id].name = {
1731
- defaultNames: [this.getObjectName(objects[id], true)],
1732
- name: friendlyNamesArray[0],
1733
- nicknames: friendlyNamesArray,
1734
- };
1735
- result[id].willReportState = true;
1736
- result[id].roomHint = roomName || '';
1737
- result[id].deviceInfo = {
1738
- manufacturer: 'ioBroker',
1739
- model: id.split('.')[0],
1740
- };
1741
- result[id].id = id;
1742
- result[id].otherDeviceIds = [
1743
- {
1744
- deviceId: id,
1745
- },
1746
- ];
1747
- if (
1748
- smartName &&
1749
- smartName.ghTraits &&
1750
- smartName.ghTraits.length > 0 &&
1751
- smartName.ghTraits[0] &&
1752
- traitEnum[smartName.ghTraits[0]]
1753
- ) {
1754
- const command = traitEnum[smartName.ghTraits[0]].command;
1755
- const getter = traitEnum[smartName.ghTraits[0]].getter;
1756
- if (command) {
1757
- result[id].customData[`set_${command}`] = id;
1758
- }
1759
- if (getter) {
1760
- result[id].customData[`get_${getter}`] = id;
1761
- } else {
1762
- result[id].customData[`get_${command}`] = id;
1763
- }
1764
-
1765
- //check if is default attributes
1766
- Object.keys(traitEnum).forEach(trait => {
1767
- try {
1768
- if (
1769
- JSON.stringify(JSON.parse(traitEnum[trait].defaultAttributes)) ===
1770
- JSON.stringify(JSON.parse(smartName.ghAttributes))
1771
- ) {
1772
- smartName.ghAttributes = '';
1773
- }
1774
- } catch (error) {}
1775
- });
1776
-
1777
- if (!smartName.ghAttributes && traitEnum[smartName.ghTraits[0]].defaultAttributes) {
1778
- const defaultAttributes = traitEnum[smartName.ghTraits[0]].defaultAttributes;
1779
- result[id].attributes = JSON.parse(defaultAttributes);
1780
- const obj = await this.adapter.getForeignObjectAsync(id);
1781
- if (
1782
- !obj.common ||
1783
- !obj.common.smartName ||
1784
- !obj.common.smartName.ghAttributes ||
1785
- obj.common.smartName.ghAttributes !== defaultAttributes
1786
- ) {
1787
- await this.adapter.extendForeignObjectAsync(id, {
1788
- common: {
1789
- smartName: {
1790
- ghAttributes: defaultAttributes,
1791
- },
1792
- },
1793
- });
1794
- }
1795
- } else {
1796
- result[id].attributes = {};
1797
- }
1798
- }
1799
-
1800
- //merge states with same name and room
1801
- if (this.smartNames[friendlyName] && this.smartNames[friendlyName].roomHint === roomName) {
1802
- if (
1803
- smartName &&
1804
- smartName.ghTraits &&
1805
- Array.isArray(smartName.ghTraits) &&
1806
- smartName.ghTraits.length > 0 &&
1807
- smartName.ghTraits[0]
1808
- ) {
1809
- const orgId = this.smartNames[friendlyName].id;
1810
- result[orgId].traits.push(smartName.ghTraits[0].split('_')[0]);
1811
-
1812
- if (result[id].attributes) {
1813
- if (result[orgId].attributes) {
1814
- result[orgId].attributes = Object.assign(result[orgId].attributes, result[id].attributes);
1815
- } else {
1816
- result[orgId].attributes = result[id].attributes;
1817
- }
1818
- }
1819
- result[orgId]['conv2GH'] = { ...result[orgId]['conv2GH'], ...result[id]['conv2GH'] };
1820
- result[orgId]['conv2iob'] = { ...result[orgId]['conv2iob'], ...result[id]['conv2iob'] };
1821
-
1822
- const command = traitEnum[smartName.ghTraits[0]].command;
1823
- const getter = traitEnum[smartName.ghTraits[0]].getter;
1824
- if (command) {
1825
- result[orgId].customData[`set_${command}`] = id;
1826
- }
1827
- if (getter) {
1828
- result[orgId].customData[`get_${getter}`] = id;
1829
- } else {
1830
- result[orgId].customData[`get_${command}`] = id;
1831
- }
1832
- this.adapter.log.debug(`[GHOME] ${JSON.stringify(result[orgId])}`);
1833
- result[id].merged = true;
1834
- }
1835
- } else {
1836
- this.smartNames[friendlyName] = result[id];
1837
- }
1838
- this.adapter.log.debug(`[GHOME] ${JSON.stringify(result[id])}`);
1839
- } catch (error) {
1840
- if (id && result[id]) {
1841
- delete result[id];
1842
- }
1843
- this.adapter.log.error(`[GHOME] Cannot process: ${id} ${error}`);
1844
- this.adapter.log.error(`[GHOME] ${objects[id]}`);
1845
- this.adapter.log.debug(`[GHOME] ${error.stack}`);
1846
- }
1847
- }
1848
-
1849
- getAllStatesInChannel(keys, channelId) {
1850
- const reg = new RegExp(`^${channelId.replace(/\./g, '\\.')}\\.[^.]+$`);
1851
- return keys.filter(_id => reg.test(_id));
1852
- }
1853
-
1854
- getAllStatesInDevice(keys, channelId) {
1855
- const reg = new RegExp(`^${channelId.replace(/\./g, '\\.')}\\.[^.]+\\.[^.]+$`);
1856
- return keys.filter(_id => reg.test(_id));
1857
- }
1858
-
1859
- _readObjects() {
1860
- return new Promise(resolve => {
1861
- this.adapter.getObjectView('system', 'state', {}, (err, _states) => {
1862
- this.adapter.getObjectView('system', 'channel', {}, (err, _channels) => {
1863
- this.adapter.getObjectView('system', 'device', {}, (err, _devices) => {
1864
- this.adapter.getObjectView('system', 'enum', {}, (err, _enums) => {
1865
- const objects = {};
1866
- const enums = {};
1867
- if (_devices && _devices.rows) {
1868
- for (let i = 0; i < _devices.rows.length; i++) {
1869
- if (
1870
- _devices.rows[i].value &&
1871
- _devices.rows[i].value._id &&
1872
- !ignoreIds.find(reg => reg.test(_devices.rows[i].value._id))
1873
- ) {
1874
- objects[_devices.rows[i].value._id] = _devices.rows[i].value;
1875
- }
1876
- }
1877
- }
1878
- if (_channels && _channels.rows) {
1879
- for (let i = 0; i < _channels.rows.length; i++) {
1880
- if (
1881
- _channels.rows[i].value &&
1882
- _channels.rows[i].value._id &&
1883
- !ignoreIds.find(reg => reg.test(_channels.rows[i].value._id))
1884
- ) {
1885
- objects[_channels.rows[i].value._id] = _channels.rows[i].value;
1886
- }
1887
- }
1888
- }
1889
- if (_states && _states.rows) {
1890
- for (let i = 0; i < _states.rows.length; i++) {
1891
- if (
1892
- _states.rows[i].value &&
1893
- _states.rows[i].value._id &&
1894
- !ignoreIds.find(reg => reg.test(_states.rows[i].value._id))
1895
- ) {
1896
- objects[_states.rows[i].value._id] = _states.rows[i].value;
1897
- }
1898
- }
1899
- }
1900
- if (_enums && _enums.rows) {
1901
- for (let i = 0; i < _enums.rows.length; i++) {
1902
- if (_enums.rows[i].value && _enums.rows[i].value._id) {
1903
- enums[_enums.rows[i].value._id] = _enums.rows[i].value;
1904
- objects[_enums.rows[i].value._id] = _enums.rows[i].value;
1905
- }
1906
- }
1907
- }
1908
- resolve({
1909
- objects,
1910
- enums,
1911
- });
1912
- });
1913
- });
1914
- });
1915
- });
1916
- });
1917
- }
1918
-
1919
- filterValidGoogleDevices() {
1920
- let returnObject = {};
1921
- Object.keys(this.smartDevices).map(id => {
1922
- if (!this.smartDevices[id].merged) {
1923
- if (
1924
- (this.smartDevices[id].name &&
1925
- this.smartDevices[id].name.name &&
1926
- this.smartDevices[id].type &&
1927
- this.smartDevices[id].traits &&
1928
- this.smartDevices[id].traits.length > 0) ||
1929
- this.smartDevices[id].parentId
1930
- ) {
1931
- returnObject[id] = this.smartDevices[id];
1932
- }
1933
- }
1934
- });
1935
- return returnObject;
1936
- }
1937
-
1938
- updateDevices(cb) {
1939
- this.unsubscribeAllIds(() => {
1940
- this._updateDevices().then(smartDevices => {
1941
- this.smartDevices = smartDevices;
1942
- this.smartDevicesSentToGoogle = this.filterValidGoogleDevices();
1943
- // Check KEY
1944
- return this.checkUrlKey()
1945
- .then(() => this.subscribeAllIds(cb))
1946
- .catch(err => {
1947
- this.adapter.config.googleHome &&
1948
- this.adapter.log.warn(
1949
- `[GHOME] Invalid URL Pro key. Status auto-update is disabled you can set states but receive states only manually: ${err}`,
1950
- );
1951
- // call cb otherwise frontend get no results
1952
- cb && cb();
1953
- });
1954
- });
1955
- });
1956
- }
1957
-
1958
- getDevices() {
1959
- const devices = Object.keys(this.smartDevices)
1960
- .filter(device => !!this.smartDevices[device].name)
1961
- .map(device => this.smartDevices[device]);
1962
- return devices;
1963
- }
1964
-
1965
- _findRoomOfId(allRooms, enums, objects, id) {
1966
- // find room
1967
- let roomHint = '';
1968
- allRooms.forEach(roomId => {
1969
- const room = enums[roomId];
1970
- if (!room.common || !room.common.members || !room.common.members.length) {
1971
- return;
1972
- }
1973
-
1974
- // If state or channel is in some room and in some function
1975
- let pos = room.common.members.indexOf(id);
1976
- if (pos === -1) {
1977
- const idArray = id.split('.');
1978
- idArray.pop();
1979
- const parent = idArray.join('.');
1980
- if (objects[parent] && objects[parent].type === 'channel') {
1981
- pos = room.common.members.indexOf(parent);
1982
- }
1983
- }
1984
- if (pos !== -1) {
1985
- // Get the name of function (with language and if name is empty)
1986
- let roomName = this.getSmartName(room);
1987
- roomName = roomName || room.common.name;
1988
- if (roomName && typeof roomName === 'object') {
1989
- roomName = roomName[this.lang] || roomName.en;
1990
- }
1991
- if (!roomName) {
1992
- roomName = roomId.substring('enum.rooms.'.length);
1993
- roomName = roomName[0].toUpperCase() + roomName.substring(1);
1994
- }
1995
- roomHint = roomName;
1996
- }
1997
- });
1998
-
1999
- return roomHint;
2000
- }
2001
-
2002
- async _updateDevices() {
2003
- const { objects, enums } = await this._readObjects();
2004
-
2005
- let ids = Object.keys(objects);
2006
-
2007
- this.enums = [];
2008
- this.smartDevices = {};
2009
- this.smartNames = {};
2010
- this.enums = [];
2011
- this.usedIds = [];
2012
- this.keys = [];
2013
-
2014
- ids.sort();
2015
-
2016
- // Build overlap from rooms and functions
2017
- let rooms = [];
2018
- let allRooms = [];
2019
- let funcs = [];
2020
- let smartName;
2021
- Object.keys(enums).forEach(id => {
2022
- smartName = this.getSmartName(enums[id]);
2023
- if (id.match(/^enum\.rooms\./)) {
2024
- allRooms.push(id);
2025
- if (smartName !== 'ignore' && smartName !== false) {
2026
- rooms.push(id);
2027
- }
2028
- } else if (id.match(/^enum\.functions\./) && smartName !== 'ignore' && smartName !== false) {
2029
- funcs.push(id);
2030
- }
2031
- });
2032
-
2033
- let result = {};
2034
- let roomNames = {};
2035
-
2036
- // find smart names without room or func
2037
- this.adapter.log.debug('[GHOME] Start non smart enum processing');
2038
- const keys = Object.keys(objects);
2039
- for (let k = 0; k < keys.length; k++) {
2040
- const id = keys[k];
2041
- smartName = this.getSmartName(objects[id]);
2042
- if (smartName && smartName !== 'ignore' && smartName !== false) {
2043
- const roomHint = this._findRoomOfId(allRooms, enums, objects, id);
2044
- await this.processState(ids, objects, id, roomHint, '', result, false);
2045
- }
2046
- }
2047
-
2048
- this.adapter.log.debug('[GHOME] Start smartenum processing');
2049
-
2050
- for (let f = 0; f < funcs.length; f++) {
2051
- const funcId = funcs[f];
2052
- const func = enums[funcId];
2053
-
2054
- if (
2055
- !func.common ||
2056
- !func.common.members ||
2057
- typeof func.common.members !== 'object' ||
2058
- !func.common.members.length
2059
- ) {
2060
- continue;
2061
- }
2062
- this.adapter.log.debug(`[GHOME] Process ${funcId}`);
2063
- // Get the name of function (with language and if name is empty)
2064
- let funcName = this.getSmartName(func);
2065
- funcName = funcName || func.common.name;
2066
-
2067
- if (funcName && typeof funcName === 'object') {
2068
- funcName = funcName[this.lang] || funcName.en;
2069
- }
2070
-
2071
- if (!funcName) {
2072
- funcName = funcId.substring('enum.functions.'.length);
2073
- funcName = funcName[0].toUpperCase() + funcName.substring(1);
2074
- }
2075
-
2076
- for (let m = 0; m < func.common.members.length; m++) {
2077
- const id = func.common.members[m];
2078
- if (!result[id]) {
2079
- for (let r = 0; r < rooms.length; r++) {
2080
- const roomId = rooms[r];
2081
- const room = enums[roomId];
2082
-
2083
- if (
2084
- !room.common ||
2085
- !room.common.members ||
2086
- typeof func.common.members !== 'object' ||
2087
- !room.common.members.length
2088
- ) {
2089
- continue;
2090
- }
2091
-
2092
- // If state or channel is in some room and in some function
2093
- const pos = room.common.members.indexOf(id);
2094
-
2095
- if (pos !== -1) {
2096
- // find name for room if not found earlier
2097
- if (!roomNames[roomId]) {
2098
- // Get the name of function (with language and if name is empty)
2099
- let roomName = this.getSmartName(room);
2100
-
2101
- roomName = roomName || room.common.name;
2102
-
2103
- if (roomName && typeof roomName === 'object') {
2104
- roomName = roomName[this.lang] || roomName.en;
2105
- }
2106
-
2107
- if (!roomName) {
2108
- roomName = roomId.substring('enum.rooms.'.length);
2109
- roomName = roomName[0].toUpperCase() + roomName.substring(1);
2110
- }
2111
- roomNames[roomId] = roomName;
2112
- }
2113
- if (objects[id] && objects[id].type === 'state') {
2114
- this.adapter.log.warn(
2115
- `[GHOME] ${id} is a state. It's recommended to add rooms and functionality to channels or devices and not to a state to get auto detected for Google Home. This works only for simple switches.`,
2116
- );
2117
- }
2118
- await this.processState(ids, objects, id, roomNames[roomId], funcName, result, true);
2119
- }
2120
- }
2121
- }
2122
- }
2123
- }
2124
-
2125
- // scan alias.* and linkeddevices.*
2126
- for (let i = 0; i < ids.length; i++) {
2127
- if (ids[i] < 'alias.') {
2128
- continue;
2129
- }
2130
- if (ids[i] > 'linkeddevices.\u9999') {
2131
- break;
2132
- }
2133
-
2134
- if (
2135
- (ids[i].startsWith('alias.') || ids[i].startsWith('linkeddevices.')) &&
2136
- objects[ids[i]] &&
2137
- (objects[ids[i]].type === 'device' || objects[ids[i]].type === 'channel')
2138
- ) {
2139
- const roomHint = this._findRoomOfId(allRooms, enums, objects, ids[i]);
2140
- if (roomHint) {
2141
- await this.processState(
2142
- ids,
2143
- objects,
2144
- ids[i],
2145
- roomsT(this.lang, roomHint),
2146
- funcsT(this.lang, 'undefined'),
2147
- result,
2148
- true,
2149
- );
2150
- }
2151
- }
2152
- }
2153
-
2154
- this.usedIds = null;
2155
- this.keys = null;
2156
-
2157
- Object.keys(result).forEach(id => this.adapter.log.debug(`[GHOME] ${id} => ${result[id].type}`));
2158
-
2159
- return result;
2160
- }
2161
-
2162
- async updateState(id, state) {
2163
- const now = Date.now();
2164
- // Only pro with a valid license can update states
2165
- if (
2166
- !this.urlKeyOk ||
2167
- (this.unknownDevices[id] && now - this.unknownDevices[id] < RETRY_UNKNOWN_DEVICES_INTERVAL)
2168
- ) {
2169
- // 10 minutes
2170
- return;
2171
- }
2172
-
2173
- let json = {};
2174
- let found = false;
2175
- for (const devId in this.smartDevicesSentToGoogle) {
2176
- if (this.smartDevicesSentToGoogle.hasOwnProperty(devId)) {
2177
- const custom = this.smartDevicesSentToGoogle[devId].customData;
2178
- let idIsAttr = false;
2179
- for (const attr in custom) {
2180
- if (custom.hasOwnProperty(attr) && attr?.startsWith('get_')) {
2181
- if (custom[attr] === id) {
2182
- idIsAttr = true;
2183
- } else {
2184
- continue;
2185
- }
2186
- const _attr = attr.substring(4);
2187
- json[devId] = json[devId] || {};
2188
- json[devId][_attr] = {
2189
- id: custom[attr],
2190
- };
2191
- }
2192
- }
2193
-
2194
- if (!idIsAttr) {
2195
- continue;
2196
- }
2197
-
2198
- for (const attr in custom) {
2199
- if (custom.hasOwnProperty(attr) && attr && custom[attr] === id && attr.startsWith('get_')) {
2200
- const _attr = attr.substring(4);
2201
- let val;
2202
- json[devId] = json[devId] || {};
2203
-
2204
- try {
2205
- if (_attr === 'on') {
2206
- val =
2207
- state.val === 1 ||
2208
- state.val === '1' ||
2209
- state.val === 'true' ||
2210
- state.val === 'ON' ||
2211
- state.val === 'on' ||
2212
- state.val === true ||
2213
- (typeof state.val === 'number' && state.val > 0);
2214
- } else if (_attr === 'color_R' || _attr === 'color_G' || _attr === 'color_B') {
2215
- if (!json[devId]['color_R'] && !!json[devId]['color_G'] && !json[devId]['color_B']) {
2216
- this.adapter.log.warn(
2217
- `[GHOME] Invalid structure for "${devId}": ${JSON.stringify(json[devId])}`,
2218
- );
2219
- val = this.reportedStates[devId][_attr].val;
2220
- } else {
2221
- // It could be only with one or two colors, so check if any absent
2222
- const r = json[devId].color_R
2223
- ? await this.adapter.getForeignStateAsync(json[devId].color_R.id)
2224
- : { val: 0 };
2225
- const g = json[devId].color_G
2226
- ? await this.adapter.getForeignStateAsync(json[devId].color_G.id)
2227
- : { val: 0 };
2228
- const b = json[devId].color_B
2229
- ? await this.adapter.getForeignStateAsync(json[devId].color_B.id)
2230
- : { val: 0 };
2231
- const spectrumRgb = (r.val << 16) + (g.val << 8) + b.val;
2232
-
2233
- val = Math.floor(spectrumRgb);
2234
- }
2235
- } else if (_attr === 'color_hue') {
2236
- json[devId].color = json[devId].color ? json[devId].color : {};
2237
- const hue = json[devId].color_hue
2238
- ? await this.adapter.getForeignStateAsync(json[devId].color_hue.id)
2239
- : { val: 0 };
2240
- const sat = json[devId].color_saturation
2241
- ? await this.adapter.getForeignStateAsync(json[devId].color_saturation.id)
2242
- : { val: 0 };
2243
- const value = json[devId].brightness
2244
- ? await this.adapter.getForeignStateAsync(json[devId].brightness.id)
2245
- : { val: 0 };
2246
- const h = hue.val / 360;
2247
- const s = sat.val / 255;
2248
- const v = value.val / 100;
2249
- const i = Math.floor(h * 6);
2250
- const f = h * 6 - i;
2251
- const p = v * (1 - s);
2252
- const q = v * (1 - f * s);
2253
- const t = v * (1 - (1 - f) * s);
2254
-
2255
- let r;
2256
- let g;
2257
- let b;
2258
-
2259
- switch (i % 6) {
2260
- case 0:
2261
- r = v;
2262
- g = t;
2263
- b = p;
2264
- break;
2265
- case 1:
2266
- r = q;
2267
- g = v;
2268
- b = p;
2269
- break;
2270
- case 2:
2271
- r = p;
2272
- g = v;
2273
- b = t;
2274
- break;
2275
- case 3:
2276
- r = p;
2277
- g = q;
2278
- b = v;
2279
- break;
2280
- case 4:
2281
- r = t;
2282
- g = p;
2283
- b = v;
2284
- break;
2285
- case 5:
2286
- r = v;
2287
- g = p;
2288
- b = q;
2289
- break;
2290
- }
2291
- val = Math.floor((r << (16 + g)) << (8 + b));
2292
- } else if (_attr === 'color_spectrumRGB') {
2293
- const rgb = state.val;
2294
- json[devId].color = json[devId].color ? json[devId].color : {};
2295
- if (rgb && rgb.substring) {
2296
- val = parseInt(rgb.substring(1), 16) || 0;
2297
- } else {
2298
- val = rgb;
2299
- }
2300
- } else if (_attr === 'color_temperature') {
2301
- const temp = state.val;
2302
- val = Math.floor(temp) || 0;
2303
- } else if (_attr === 'isLocked') {
2304
- val = !!state.val;
2305
- } else if (_attr === 'openDirection') {
2306
- val = state.val === 2 ? 'DOWN' : 'UP';
2307
- } else if (_attr === 'openPercent') {
2308
- if (state.val === true || state.val === false) {
2309
- val = state.val === false ? 100 : 0;
2310
- } else {
2311
- val = parseInt(state.val) || 0;
2312
- }
2313
- } else {
2314
- val = state.val;
2315
- }
2316
-
2317
- if (this.smartDevices[devId].conv2GH[custom[attr]]) {
2318
- try {
2319
- const conv = new Function('value', this.smartDevices[devId].conv2GH[custom[attr]]);
2320
- val = conv(val);
2321
- } catch (e) {
2322
- this.adapter.log.error(
2323
- `Invalid convert function in ${devId}/${custom[attr]}: ${this.smartDevices[devId].conv2GH[custom[attr]]}`,
2324
- );
2325
- }
2326
- }
2327
-
2328
- // do not send the same state to google
2329
- if (
2330
- (this.reportedStates[devId] &&
2331
- this.reportedStates[devId][_attr] &&
2332
- this.reportedStates[devId][_attr].val !== val) ||
2333
- !this.reportedStates[devId] ||
2334
- !this.reportedStates[devId][_attr]
2335
- ) {
2336
- this.reportedStates[devId] = this.reportedStates[devId] || {};
2337
- this.reportedStates[devId][_attr] = this.reportedStates[devId][_attr] || {};
2338
- this.reportedStates[devId][_attr].val = val;
2339
- this.reportedStates[devId][_attr].ts = now;
2340
- json[devId] = json[devId] || {};
2341
- if (_attr.includes('color_')) {
2342
- json[devId].color = json[devId].color ? json[devId].color : {};
2343
- if (_attr === 'color_temperature') {
2344
- json[devId].color.temperatureK = Math.floor(val);
2345
- } else {
2346
- json[devId].color.spectrumRGB = val;
2347
- }
2348
- } else if (_attr.substring(4).split('_').length > 1) {
2349
- const attrArray = _attr.substring(4).split('_');
2350
- if (json[devId][attrArray[0]]) {
2351
- json[devId][attrArray[0]][attrArray[1]] = val;
2352
- } else {
2353
- json[devId][attrArray[0]] = {};
2354
- json[devId][attrArray[0]][attrArray[1]] = val;
2355
- }
2356
- } else {
2357
- json[devId][_attr] = val;
2358
- }
2359
- found = true;
2360
- }
2361
- } catch (error) {
2362
- this.adapter.log.error(`[GHOME] ${error.message} ${error.stack}`);
2363
- }
2364
- }
2365
- }
2366
- }
2367
- }
2368
-
2369
- if (found && this.urlKey) {
2370
- const now = Date.now();
2371
-
2372
- let i = 0;
2373
- while (i < this.rateCalculation.length) {
2374
- if (now - this.rateCalculation[i] < 60000) {
2375
- break;
2376
- }
2377
- i++;
2378
- }
2379
- if (i) {
2380
- if (i < this.rateCalculation.length) {
2381
- this.rateCalculation.splice(0, i);
2382
- } else {
2383
- this.rateCalculation = [];
2384
- }
2385
- }
2386
-
2387
- if (this.rateCalculation.length > 60) {
2388
- return this.adapter.log.warn(
2389
- `[GHOME] Sending too fast: ${this.rateCalculation.length} in last minute!`,
2390
- );
2391
- }
2392
-
2393
- this.rateCalculation.push(now);
2394
-
2395
- const url = `${URL_STATUS}?user=${encodeURIComponent(this.adapter.config.login)}&urlKey=${encodeURIComponent(this.urlKey.key)}&p=${PROTOCOL_VERSION}&v=${version}`;
2396
- axios
2397
- .post(url, json, { validateStatus: status => status === 200 })
2398
- .then(response => {
2399
- if (this.unknownDevices[id]) {
2400
- delete this.unknownDevices[id];
2401
- }
2402
- this.adapter.log.debug(
2403
- `[GHOME] Status reported: ${JSON.stringify(json)} ${JSON.stringify(response.data)}`,
2404
- );
2405
- })
2406
- .catch(error => {
2407
- if (error.response && error.response.status === 404) {
2408
- this.adapter.log.error(`[GHOME] device ${id} is unknown to google home`);
2409
- this.unknownDevices[id] = Date.now();
2410
- } else if (error.response && error.response.status === 401) {
2411
- this.adapter.log.error(`[GHOME] auth error: ${JSON.stringify(error.response.body)}`);
2412
- this.urlKeyOk = false; // invalidate urlKey
2413
- } else if (error.response && error.response.status === 410) {
2414
- this.adapter.log.error(
2415
- `[GHOME] invalid protocol version: ${JSON.stringify(error.response.body)}`,
2416
- );
2417
- this.urlKeyOk = false; // invalidate urlKey
2418
- } else {
2419
- let errorMessage;
2420
- if (error.response) {
2421
- errorMessage = error.response.data || error.response.status;
2422
- } else if (error.request) {
2423
- errorMessage = 'No answer';
2424
- } else {
2425
- errorMessage = error.message;
2426
- }
2427
-
2428
- this.adapter.log.error(`[GHOME] Cannot updateState: ${JSON.stringify(errorMessage)}`);
2429
- this.adapter.log.debug(`[GHOME] ${JSON.stringify(json)}`);
2430
- }
2431
- });
2432
- }
2433
- }
2434
-
2435
- async updateStates(json) {
2436
- if (!this.urlKeyOk || !this.urlKey) {
2437
- return;
2438
- }
2439
- if (!json) {
2440
- json = {};
2441
- for (const devId in this.smartDevicesSentToGoogle) {
2442
- if (this.smartDevicesSentToGoogle.hasOwnProperty(devId)) {
2443
- const custom = this.smartDevicesSentToGoogle[devId].customData;
2444
- for (const attr in custom) {
2445
- if (custom.hasOwnProperty(attr) && attr && attr.startsWith('get_')) {
2446
- const _attr = attr.substring(4);
2447
- json[devId] = json[devId] || {};
2448
- json[devId][_attr] = {
2449
- id: custom[attr],
2450
- };
2451
- }
2452
- }
2453
- }
2454
- }
2455
- }
2456
-
2457
- for (let devId in json) {
2458
- try {
2459
- if (!json.hasOwnProperty(devId)) {
2460
- continue;
2461
- }
2462
-
2463
- for (let attr in json[devId]) {
2464
- if (!json[devId].hasOwnProperty(attr)) {
2465
- continue;
2466
- }
2467
-
2468
- if (typeof json[devId][attr] === 'object' && json[devId][attr].id) {
2469
- let state = await this.adapter.getForeignStateAsync(json[devId][attr].id);
2470
- if (state === null || state.val === null || state.val === '') {
2471
- delete json[devId][attr];
2472
- if (Object.keys(json[devId]).length === 0) {
2473
- delete json[devId];
2474
- }
2475
- continue;
2476
- }
2477
-
2478
- state = state || { val: false };
2479
-
2480
- if (
2481
- this.smartDevices[devId].conv2GH &&
2482
- this.smartDevices[devId].conv2GH[json[devId][attr].id]
2483
- ) {
2484
- try {
2485
- const conv = new Function(
2486
- 'value',
2487
- this.smartDevices[devId].conv2GH[json[devId][attr].id],
2488
- );
2489
- state.val = conv(state.val);
2490
- } catch (e) {
2491
- this.adapter.log.error(
2492
- `Invalid convert function in ${devId}/${attr}: ${this.smartDevices[devId].conv2GH[json[devId][attr].id]}`,
2493
- );
2494
- }
2495
- }
2496
- if (attr === 'on') {
2497
- json[devId][attr] =
2498
- state.val === 1 ||
2499
- state.val === '1' ||
2500
- state.val === 'true' ||
2501
- state.val === 'ON' ||
2502
- state.val === 'on' ||
2503
- state.val === true ||
2504
- (typeof state.val === 'number' && state.val > 0);
2505
- } else if (attr === 'color_R' || attr === 'color_G' || attr === 'color_B') {
2506
- const r = await this.adapter.getForeignStateAsync(json[devId].color_R.id);
2507
- const g = await this.adapter.getForeignStateAsync(json[devId].color_G.id);
2508
- const b = await this.adapter.getForeignStateAsync(json[devId].color_B.id);
2509
- const spectrumRgb = (r.val << 16) + (g.val << 8) + b.val;
2510
- json[devId].color = json[devId].color ? json[devId].color : {};
2511
- json[devId].color.spectrumRGB = Math.floor(spectrumRgb);
2512
- delete json[devId]['color_R'];
2513
- delete json[devId]['color_G'];
2514
- delete json[devId]['color_B'];
2515
- } else if (attr === 'color_hue') {
2516
- json[devId].color = json[devId].color ? json[devId].color : {};
2517
- if (json[devId].color_hue && json[devId].color_saturation && json[devId].brightness) {
2518
- try {
2519
- const hue = await this.adapter.getForeignStateAsync(json[devId].color_hue.id);
2520
- const sat = await this.adapter.getForeignStateAsync(
2521
- json[devId].color_saturation.id,
2522
- );
2523
- const val = await this.adapter.getForeignStateAsync(json[devId].brightness.id);
2524
- const h = hue.val / 360;
2525
- const s = sat.val / 255;
2526
- const v = val.val / 100;
2527
- const i = Math.floor(h * 6);
2528
- const f = h * 6 - i;
2529
- const p = v * (1 - s);
2530
- const q = v * (1 - f * s);
2531
- const t = v * (1 - (1 - f) * s);
2532
- let r, g, b;
2533
- switch (i % 6) {
2534
- case 0:
2535
- r = v;
2536
- g = t;
2537
- b = p;
2538
- break;
2539
- case 1:
2540
- r = q;
2541
- g = v;
2542
- b = p;
2543
- break;
2544
- case 2:
2545
- r = p;
2546
- g = v;
2547
- b = t;
2548
- break;
2549
- case 3:
2550
- r = p;
2551
- g = q;
2552
- b = v;
2553
- break;
2554
- case 4:
2555
- r = t;
2556
- g = p;
2557
- b = v;
2558
- break;
2559
- case 5:
2560
- r = v;
2561
- g = p;
2562
- b = q;
2563
- break;
2564
- }
2565
- json[devId].color.spectrumRGB = Math.floor((r << (16 + g)) << (8 + b));
2566
- } catch (error) {
2567
- this.adapter.log.error(`[GHOME] ${error}`);
2568
- }
2569
- }
2570
- delete json[devId]['color_hue'];
2571
- delete json[devId]['color_saturation'];
2572
- delete json[devId]['brightness'];
2573
- } else if (attr === 'color_spectrumRGB') {
2574
- const rgb = state.val;
2575
- json[devId].color = json[devId].color ? json[devId].color : {};
2576
- if (rgb && rgb.substring) {
2577
- json[devId].color.spectrumRGB = parseInt(rgb.substring(1), 16) || 0;
2578
- } else {
2579
- json[devId].color.spectrumRGB = rgb;
2580
- }
2581
-
2582
- delete json[devId][attr];
2583
- } else if (attr === 'color_temperature') {
2584
- const temp = state.val;
2585
-
2586
- json[devId].color = json[devId].color ? json[devId].color : {};
2587
- json[devId].color.temperatureK = Math.floor(temp);
2588
-
2589
- delete json[devId][attr];
2590
- } else if (attr === 'isLocked') {
2591
- json[devId][attr] = !!state.val;
2592
- } else if (attr === 'openDirection') {
2593
- json[devId][attr] = state.val === 2 ? 'DOWN' : 'UP';
2594
- } else if (attr === 'openPercent') {
2595
- if (state.val === true || state.val === false || isNaN(state.val)) {
2596
- json[devId][attr] = state.val === false ? 100 : 0;
2597
- } else {
2598
- json[devId][attr] = parseInt(state.val) || 0;
2599
- }
2600
- } else if (attr === 'thermostatTemperatureSetpoint') {
2601
- json[devId][attr] = state.val;
2602
- if (json[devId].thermostatTemperatureAmbient > json[devId].thermostatTemperatureSetpoint) {
2603
- json[devId].thermostatMode = 'cool';
2604
- } else {
2605
- json[devId].thermostatMode = 'heat';
2606
- }
2607
- } else {
2608
- if (attr.split('_').length > 1) {
2609
- const attrArray = attr.split('_');
2610
- delete json[devId][attr];
2611
- if (json[devId][attrArray[0]]) {
2612
- json[devId][attrArray[0]][attrArray[1]] = state.val;
2613
- } else {
2614
- json[devId][attrArray[0]] = {};
2615
- json[devId][attrArray[0]][attrArray[1]] = state.val;
2616
- }
2617
- } else {
2618
- if (!isNaN(state.val)) {
2619
- state.val = Math.floor(state.val);
2620
- }
2621
- json[devId][attr] = state.val;
2622
- }
2623
- }
2624
- // return;
2625
- }
2626
- }
2627
- } catch (error) {
2628
- this.adapter.log.error(`[GHOME] ${error}`);
2629
- this.adapter.log.error(`[GHOME] ${error.stack}`);
2630
- }
2631
- }
2632
-
2633
- const url = `${URL_STATUS}?user=${encodeURIComponent(this.adapter.config.login)}&urlKey=${encodeURIComponent(this.urlKey.key)}&p=${PROTOCOL_VERSION}&v=${version}`;
2634
- const sendRequest = () => {
2635
- axios
2636
- .post(url, json, { validateStatus: status => status === 200 })
2637
- .then(response => {
2638
- Object.keys(this.unknownDevices).forEach(id => {
2639
- if (this.unknownDevices[id]) {
2640
- delete this.unknownDevices[id];
2641
- }
2642
- });
2643
-
2644
- this.adapter.log.debug(`[GHOME] Status reported: ${JSON.stringify(response.data)}`);
2645
- })
2646
- .catch(error => {
2647
- if (error.response && error.response.status === 404) {
2648
- this.adapter.log.error(`[GHOME] devices are unknown to google home`);
2649
- Object.keys(this.unknownDevices).forEach(id => (this.unknownDevices[id] = Date.now()));
2650
- } else if (error.response && error.response.status === 401) {
2651
- this.adapter.log.error(`[GHOME] auth error: ${JSON.stringify(error.response.data)}`);
2652
- this.urlKeyOk = false; // invalidate urlKey
2653
- } else if (error.response && error.response.status === 410) {
2654
- this.adapter.log.error(
2655
- `[GHOME] invalid protocol version: ${JSON.stringify(error.response.data)}`,
2656
- );
2657
- this.urlKeyOk = false; // invalidate urlKey
2658
- } else {
2659
- let errorMessage;
2660
- if (error.response) {
2661
- errorMessage = error.response.data || error.response.status;
2662
- } else if (error.request) {
2663
- errorMessage = 'No answer';
2664
- } else {
2665
- errorMessage = error.message;
2666
- }
2667
- this.adapter.log.error(`[GHOME] Cannot updateStates: ${errorMessage}`);
2668
- this.adapter.log.debug(`[GHOME] ${JSON.stringify(json)}`);
2669
- }
2670
- });
2671
- };
2672
- setTimeout(() => sendRequest(), 100);
2673
- }
2674
-
2675
- // https://developers.google.com/actions/smarthome/create#request
2676
- sync(requestId) {
2677
- this.smartDevicesSentToGoogle = {};
2678
- let devicesArray = [];
2679
- Object.keys(this.smartDevices).map(id => {
2680
- if (!this.smartDevices[id].merged) {
2681
- if (
2682
- this.smartDevices[id].name &&
2683
- this.smartDevices[id].name.name &&
2684
- this.smartDevices[id].type &&
2685
- this.smartDevices[id].traits &&
2686
- this.smartDevices[id].traits.length > 0
2687
- ) {
2688
- const dev = JSON.parse(JSON.stringify(this.smartDevices[id]));
2689
- delete dev.displayTraits;
2690
- delete dev.displayAttributes;
2691
- delete dev.smartEnum;
2692
- delete dev.ioType;
2693
- delete dev.parentId;
2694
- delete dev.conv2GH;
2695
- delete dev.displayConv2GH;
2696
- delete dev.conv2iob;
2697
- delete dev.displayConv2iob;
2698
- // not yet active
2699
- // dev.willReportState = this.urlKeyOk;
2700
- devicesArray.push(dev);
2701
- return dev;
2702
- } else if (!this.smartDevices[id].parentId) {
2703
- this.adapter.log.warn(`[GHOME] Missing name, type or treat for: ${id}. Not added to GoogleHome`);
2704
- this.adapter.log.debug(`[GHOME] ${JSON.stringify(this.smartDevices[id])}`);
2705
- }
2706
- }
2707
- return null;
2708
- });
2709
-
2710
- if (devicesArray.length === 0) {
2711
- this.adapter.log.warn(
2712
- '[GHOME] No devices defined. Did you add no sensors or indicate states to rooms and enums?',
2713
- );
2714
- }
2715
-
2716
- devicesArray.forEach(element => (this.smartDevicesSentToGoogle[element.id] = element));
2717
-
2718
- this.tasksTimer && clearTimeout(this.tasksTimer);
2719
- this.tasksTimer = setTimeout(() => this.updateStates(), 6000);
2720
-
2721
- return {
2722
- requestId,
2723
- payload: {
2724
- agentUserId: this.agentUserId,
2725
- devices: devicesArray,
2726
- },
2727
- };
2728
- }
2729
-
2730
- getStates(ids, callback, states) {
2731
- states = states || {};
2732
- if (!ids || !ids.length) {
2733
- callback(states);
2734
- } else {
2735
- const id = ids.shift();
2736
- if (id === undefined) {
2737
- setImmediate(() => this.getStates(ids, callback, states));
2738
- } else {
2739
- this.adapter.getForeignState(id, (err, state) => {
2740
- states[id] = state && state.val;
2741
- setImmediate(() => this.getStates(ids, callback, states));
2742
- });
2743
- }
2744
- }
2745
- }
2746
-
2747
- // possible responses
2748
- query(requestId, devices) {
2749
- return new Promise(resolve => {
2750
- const responseDev = {};
2751
- const ids = [];
2752
- try {
2753
- devices.forEach(dev => {
2754
- if (this.smartDevices[dev.id]) {
2755
- const attrs = this.smartDevices[dev.id].customData;
2756
- if (attrs) {
2757
- Object.keys(attrs).forEach(
2758
- attr =>
2759
- attr &&
2760
- attr.startsWith('get_') &&
2761
- attrs[attr] !== undefined &&
2762
- !ids.includes(attrs[attr]) &&
2763
- ids.push(attrs[attr]),
2764
- );
2765
- } else {
2766
- this.adapter.log.error(
2767
- `[GHOME] No Google Home customData for ${dev.id} cannot handle Google Request.`,
2768
- );
2769
- }
2770
- }
2771
- });
2772
-
2773
- this.getStates(ids, states => {
2774
- devices.forEach(dev => {
2775
- if (this.smartDevices[dev.id]) {
2776
- responseDev[dev.id] = {
2777
- online: true,
2778
- };
2779
- const attrs = this.smartDevices[dev.id].customData;
2780
- if (attrs) {
2781
- Object.keys(attrs).forEach(attr => {
2782
- if (attr && attr.startsWith('get_')) {
2783
- if (
2784
- this.smartDevices[dev.id].conv2GH &&
2785
- this.smartDevices[dev.id].conv2GH[attrs[attr]]
2786
- ) {
2787
- try {
2788
- const conv = new Function(
2789
- 'value',
2790
- this.smartDevices[dev.id].conv2GH[attrs[attr]],
2791
- );
2792
- states[attrs[attr]] = conv(states[attrs[attr]]);
2793
- } catch (e) {
2794
- this.adapter.log.error(
2795
- `Invalid convert function in ${dev.id}/${attrs[attr]}: ${this.smartDevices[dev.id].conv2GH[attrs[attr]]}`,
2796
- );
2797
- }
2798
- }
2799
- if (attr.substring(4).split('_').length > 1) {
2800
- const attrArray = attr.substring(4).split('_');
2801
- if (
2802
- attr === 'get_color_R' ||
2803
- attr === 'get_color_G' ||
2804
- attr === 'get_color_B'
2805
- ) {
2806
- const spectrumRgb =
2807
- (states[attrs.get_color_R] << 16) +
2808
- (states[attrs.get_color_G] << 8) +
2809
- states[attrs.get_color_B];
2810
- responseDev[dev.id].color = responseDev[dev.id].color
2811
- ? responseDev[dev.id].color
2812
- : {};
2813
- responseDev[dev.id].color.spectrumRgb = spectrumRgb;
2814
- } else if (attr === 'get_color_hue') {
2815
- responseDev[dev.id].color = responseDev[dev.id].color
2816
- ? responseDev[dev.id].color
2817
- : {};
2818
- const h = states[attrs.get_color_hue] / 360;
2819
- const s = states[attrs.get_color_saturation] / 255;
2820
- const v = states[attrs.get_brightness] / 100;
2821
- const i = Math.floor(h * 6);
2822
- const f = h * 6 - i;
2823
- const p = v * (1 - s);
2824
- const q = v * (1 - f * s);
2825
- const t = v * (1 - (1 - f) * s);
2826
- let r, g, b;
2827
- switch (i % 6) {
2828
- case 0:
2829
- r = v;
2830
- g = t;
2831
- b = p;
2832
- break;
2833
- case 1:
2834
- r = q;
2835
- g = v;
2836
- b = p;
2837
- break;
2838
- case 2:
2839
- r = p;
2840
- g = v;
2841
- b = t;
2842
- break;
2843
- case 3:
2844
- r = p;
2845
- g = q;
2846
- b = v;
2847
- break;
2848
- case 4:
2849
- r = t;
2850
- g = p;
2851
- b = v;
2852
- break;
2853
- case 5:
2854
- r = v;
2855
- g = p;
2856
- b = q;
2857
- break;
2858
- }
2859
- responseDev[dev.id].color.spectrumRgb = (r << (16 + g)) << (8 + b);
2860
- } else if (attr === 'get_color_spectrumRGB') {
2861
- const rgb = states[attrs.get_color_spectrumRGB];
2862
- responseDev[dev.id].color = responseDev[dev.id].color
2863
- ? responseDev[dev.id].color
2864
- : {};
2865
- if (rgb && rgb.substring) {
2866
- responseDev[dev.id].color.spectrumRgb =
2867
- parseInt(rgb.substring(1), 16) || 0;
2868
- } else {
2869
- responseDev[dev.id].color.spectrumRgb = rgb;
2870
- }
2871
- } else {
2872
- if (responseDev[dev.id][attrArray[0]]) {
2873
- responseDev[dev.id][attrArray[0]][attrArray[1]] =
2874
- states[attrs[attr]];
2875
- } else {
2876
- responseDev[dev.id][attrArray[0]] = {};
2877
- responseDev[dev.id][attrArray[0]][attrArray[1]] =
2878
- states[attrs[attr]];
2879
- }
2880
- }
2881
- } else {
2882
- if (
2883
- attr === 'get_isLocked' &&
2884
- states[attrs[attr]] !== true &&
2885
- states[attrs[attr]] !== false
2886
- ) {
2887
- responseDev[dev.id][attr.substring(4)] = states[attrs[attr]] === 0;
2888
- }
2889
- if (
2890
- attr === 'get_openPercent' &&
2891
- (states[attrs[attr]] === true || states[attrs[attr]] === false)
2892
- ) {
2893
- responseDev[dev.id][attr.substring(4)] =
2894
- states[attrs[attr]] === true ? 0 : 100;
2895
- } else {
2896
- responseDev[dev.id][attr.substring(4)] = states[attrs[attr]];
2897
- }
2898
- }
2899
- }
2900
- });
2901
- } else {
2902
- this.adapter.log.error(
2903
- `[GHOME] No Google Home customData for ${dev.id} cannot handle Google Request.`,
2904
- );
2905
- }
2906
- //Workaround for no thermostat mode available
2907
- if (responseDev[dev.id].thermostatTemperatureSetpoint) {
2908
- if (
2909
- responseDev[dev.id].thermostatTemperatureAmbient >
2910
- responseDev[dev.id].thermostatTemperatureSetpoint
2911
- ) {
2912
- responseDev[dev.id].thermostatMode = 'cool';
2913
- } else {
2914
- responseDev[dev.id].thermostatMode = 'heat';
2915
- }
2916
- }
2917
- } else {
2918
- responseDev[dev.id] = {
2919
- online: false,
2920
- };
2921
- }
2922
-
2923
- /*responseDev[dev.id] = {
2924
- on: true,
2925
- online: true,
2926
-
2927
- brightness: 44,
2928
- color: {
2929
- name: 'soft white',
2930
- temperature: 2700
2931
- }
2932
- }*/
2933
- });
2934
- resolve({
2935
- requestId,
2936
- payload: {
2937
- devices: responseDev,
2938
- },
2939
- });
2940
- });
2941
- } catch (error) {
2942
- this.adapter.log.error(`[GHOME] ${error.stack}`);
2943
- this.adapter.log.error(`[GHOME] ${JSON.stringify(devices)}`);
2944
- this.adapter.log.error(`[GHOME] ${(ids || []).toString()}`);
2945
- }
2946
- });
2947
- }
2948
-
2949
- setStates(tasks, callback, results) {
2950
- results = results || {};
2951
- if (!tasks || !tasks.length) {
2952
- callback(results);
2953
- } else {
2954
- const task = tasks.shift();
2955
- this.adapter.log.debug(`[GHOME] setState: ${JSON.stringify(task)}`);
2956
-
2957
- if (task.cmd === 'action.devices.commands.SetToggles') {
2958
- this.adapter.getForeignState(task.id, task.val, (error, state) => {
2959
- if (!error) {
2960
- const val = !(state && state.val);
2961
- this.adapter.setForeignState(task.id, val, error => {
2962
- results[task.devId] = results[task.devId] || {};
2963
- results[task.devId][task.param] = val;
2964
- if (error) {
2965
- results[task.devId].error = error;
2966
- }
2967
- setImmediate(() => this.setStates(tasks, callback, results));
2968
- });
2969
- } else {
2970
- results[task.devId] = {
2971
- error,
2972
- };
2973
- setImmediate(() => this.setStates(tasks, callback, results));
2974
- }
2975
- });
2976
- } else {
2977
- this.adapter.setForeignState(task.id, task.val, error => {
2978
- results[task.devId] = results[task.devId] || {};
2979
- results[task.devId][task.param] = task.val;
2980
-
2981
- if (error) {
2982
- results[task.devId].error = error;
2983
- }
2984
- setImmediate(() => this.setStates(tasks, callback, results));
2985
- });
2986
- }
2987
- }
2988
- }
2989
-
2990
- execute(requestId, commands) {
2991
- return new Promise(resolve => {
2992
- if (!commands) {
2993
- this.adapter.log.error('[GHOME] Invalid parameter commands - NULL');
2994
- resolve({
2995
- error: 'Invalid parameter',
2996
- });
2997
- }
2998
-
2999
- const tasks = [];
3000
- commands.forEach(command => {
3001
- command.execution.forEach(execute => {
3002
- this.adapter.log.debug(`[GHOME] execute ${execute.command} => ${JSON.stringify(execute.params)}`);
3003
-
3004
- command.devices.forEach(dev => {
3005
- if (this.smartDevices[dev.id]) {
3006
- const attrs = this.smartDevices[dev.id].customData;
3007
-
3008
- if (!attrs) {
3009
- return this.adapter.log.error(
3010
- `[GHOME] Try to control ${dev.id}, but the device is not configured for Google Home`,
3011
- );
3012
- }
3013
-
3014
- if (execute.command === 'action.devices.commands.SetToggles') {
3015
- if (attrs.set_on) {
3016
- tasks.push({
3017
- id: attrs.set_on,
3018
- cmd: execute.command,
3019
- param: 'on',
3020
- devId: dev.id,
3021
- });
3022
- }
3023
- } else {
3024
- if (
3025
- (typeof execute.params === 'undefined' ||
3026
- execute.command === 'action.devices.commands.ActivateScene') &&
3027
- execute.command
3028
- ) {
3029
- const command = execute.command.split('.').pop();
3030
- execute.params = {};
3031
- execute.params[command] = !execute.params.deactivate;
3032
- }
3033
-
3034
- Object.keys(execute.params).forEach(param => {
3035
- let paths = [];
3036
- if (typeof execute.params[param] === 'object') {
3037
- Object.keys(execute.params[param]).forEach(subElement => {
3038
- if (subElement === 'spectrumRGB' && attrs.set_color_R) {
3039
- const rgb = parseInt(execute.params.color.spectrumRGB) || 0;
3040
- paths.push({
3041
- path: 'color_R',
3042
- val: (rgb & 0xff0000) >> 16,
3043
- });
3044
- paths.push({
3045
- path: 'color_G',
3046
- val: (rgb & 0x00ff00) >> 8,
3047
- });
3048
- paths.push({
3049
- path: 'color_B',
3050
- val: rgb & 0x0000ff,
3051
- });
3052
- } else if (subElement === 'spectrumRGB' && attrs.set_color_hue) {
3053
- const rgb = parseInt(execute.params.color.spectrumRGB) || 0;
3054
- const r = ((rgb & 0xff0000) >> 16) / 255;
3055
- const g = ((rgb & 0x00ff00) >> 8) / 255;
3056
- const b = (rgb & 0x0000ff) / 255;
3057
-
3058
- const max = Math.max(r, g, b),
3059
- min = Math.min(r, g, b);
3060
- let h,
3061
- s,
3062
- v = max;
3063
-
3064
- let d = max - min;
3065
- s = max ? d / max : 0;
3066
-
3067
- if (max === min) {
3068
- h = 0; // achromatic
3069
- } else {
3070
- switch (max) {
3071
- case r:
3072
- h = (g - b) / d + (g < b ? 6 : 0);
3073
- break;
3074
- case g:
3075
- h = (b - r) / d + 2;
3076
- break;
3077
- case b:
3078
- h = (r - g) / d + 4;
3079
- break;
3080
- }
3081
-
3082
- h /= 6;
3083
- }
3084
- paths.push({
3085
- path: 'color_hue',
3086
- val: h,
3087
- });
3088
- paths.push({
3089
- path: 'color_saturation',
3090
- val: s,
3091
- });
3092
- paths.push({
3093
- path: 'brightness',
3094
- val: v,
3095
- });
3096
- } else if (subElement === 'spectrumRGB') {
3097
- const rgb = parseInt(execute.params.color.spectrumRGB) || 0;
3098
- paths.push({
3099
- path: 'color_spectrumRGB',
3100
- val: `#${('000000' + rgb.toString(16)).substr(-6)}`,
3101
- });
3102
- } else {
3103
- paths.push({
3104
- path: `${param}_${subElement}`,
3105
- val: execute.params[param][subElement],
3106
- });
3107
- }
3108
- });
3109
- } else {
3110
- // if there no dedicated onoff use onoff trait and translate it to 0 : 100
3111
- if (param === 'on' && attrs[`set_${param}`] === attrs.set_brightness) {
3112
- paths.push({
3113
- path: param,
3114
- val: execute.params[param] ? 100 : 0,
3115
- });
3116
- } else {
3117
- paths.push({
3118
- path: param,
3119
- val: execute.params[param],
3120
- });
3121
- }
3122
- }
3123
-
3124
- paths.forEach(element => {
3125
- if (attrs[`set_${element.path}`]) {
3126
- if (
3127
- this.smartDevices[dev.id].conv2iob &&
3128
- this.smartDevices[dev.id].conv2iob[attrs[`set_${element.path}`]]
3129
- ) {
3130
- try {
3131
- const conv = new Function(
3132
- 'value',
3133
- this.smartDevices[dev.id].conv2iob[
3134
- attrs[`set_${element.path}`]
3135
- ],
3136
- );
3137
- element.val = conv(element.val);
3138
- } catch (e) {
3139
- this.adapter.log.error(
3140
- `Invalid convert function in ${dev.id}/${attrs[`set_${element.path}`]}: ${this.smartDevices[dev.id].conv2iob[attrs[`set_${element.path}`]]}`,
3141
- );
3142
- }
3143
- }
3144
- tasks.push({
3145
- id: attrs[`set_${element.path}`],
3146
- val: element.val,
3147
- param,
3148
- devId: dev.id,
3149
- });
3150
- }
3151
- });
3152
- });
3153
- }
3154
- }
3155
- });
3156
- });
3157
- });
3158
-
3159
- this.setStates(tasks, results => {
3160
- const responseCommands = Object.keys(results).map(devId => {
3161
- if (results[devId].error) {
3162
- return {
3163
- ids: [devId],
3164
- status: 'ERROR',
3165
- errorCode: results[devId].error,
3166
- };
3167
- } else {
3168
- if (results[devId].online === undefined) {
3169
- results[devId].online = true;
3170
- }
3171
- return {
3172
- ids: [devId],
3173
- status: 'SUCCESS',
3174
- states: results[devId],
3175
- };
3176
- }
3177
- });
3178
-
3179
- resolve({
3180
- requestId,
3181
- payload: {
3182
- commands: responseCommands,
3183
- },
3184
- });
3185
- });
3186
- });
3187
- }
3188
-
3189
- async process(request, isEnabled) {
3190
- if (!request) {
3191
- this.adapter.log.error('[GHOME] Invalid request: no request!');
3192
- return;
3193
- }
3194
-
3195
- if (!isEnabled) {
3196
- return {
3197
- error: textsT(this.lang, 'The service deactivated'),
3198
- errorCode: 501,
3199
- };
3200
- }
3201
-
3202
- if (!request.inputs || !request.inputs.length) {
3203
- return {
3204
- error: textsT(this.lang, 'missing inputs'),
3205
- errorCode: 401,
3206
- };
3207
- }
3208
-
3209
- // actually we take only first input from request
3210
- for (let i = 0; i < request.inputs.length; i++) {
3211
- const input = request.inputs[i];
3212
- const intent = input.intent;
3213
- if (!intent) {
3214
- continue;
3215
- }
3216
-
3217
- this.adapter.log.debug(`[GHOME] Received ${intent}`);
3218
-
3219
- switch (intent) {
3220
- case 'action.devices.SYNC':
3221
- /**
3222
- * request:
3223
- * {
3224
- * "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
3225
- * "inputs": [{
3226
- * "intent": "action.devices.SYNC",
3227
- * }]
3228
- * }
3229
- */
3230
- // sync
3231
- return this.sync(request.requestId);
3232
-
3233
- case 'action.devices.QUERY':
3234
- /**
3235
- * request:
3236
- * {
3237
- * "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
3238
- * "inputs": [{
3239
- * "intent": "action.devices.QUERY",
3240
- * "payload": {
3241
- * "devices": [{
3242
- * "id": "123",
3243
- * "customData": {
3244
- * "fooValue": 12,
3245
- * "barValue": true,
3246
- * "bazValue": "alpaca sauce"
3247
- * }
3248
- * }, {
3249
- * "id": "234",
3250
- * "customData": {
3251
- * "fooValue": 74,
3252
- * "barValue": false,
3253
- * "bazValue": "sheep dip"
3254
- * }
3255
- * }]
3256
- * }
3257
- * }]
3258
- * }
3259
- */
3260
-
3261
- // async
3262
- return this.query(request.requestId, input.payload.devices);
3263
-
3264
- case 'action.devices.EXECUTE':
3265
- /**
3266
- * request:
3267
- * {
3268
- * "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
3269
- * "inputs": [{
3270
- * "intent": "action.devices.EXECUTE",
3271
- * "payload": {
3272
- * "commands": [{
3273
- * "devices": [{
3274
- * "id": "123",
3275
- * "customData": {
3276
- * "fooValue": 12,
3277
- * "barValue": true,
3278
- * "bazValue": "alpaca sauce"
3279
- * }
3280
- * }, {
3281
- * "id": "234",
3282
- * "customData": {
3283
- * "fooValue": 74,
3284
- * "barValue": false,
3285
- * "bazValue": "sheep dip"
3286
- * }
3287
- * }],
3288
- * "execution": [{
3289
- * "command": "action.devices.commands.OnOff",
3290
- * "params": {
3291
- * "on": true
3292
- * }
3293
- * }]
3294
- * }]
3295
- * }
3296
- * }]
3297
- * }
3298
- */
3299
-
3300
- // async
3301
- return this.execute(request.requestId, input.payload.commands);
3302
-
3303
- case 'action.devices.DISCONNECT':
3304
- this.adapter.log.info('[GHOME] Google home unlinked!');
3305
- // sync
3306
- return {};
3307
-
3308
- default:
3309
- return {
3310
- error: textsT(this.lang, 'missing intent'),
3311
- errorCode: 401,
3312
- };
3313
- }
3314
- }
3315
-
3316
- return {
3317
- error: textsT(this.lang, 'missing inputs'),
3318
- errorCode: 401,
3319
- };
3320
- }
3321
- }
3322
-
3323
- module.exports = GoogleHome;