iobroker.iot 3.6.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/admin/assets/index-5zouxn2w.js +680 -0
- package/admin/index_m.html +1 -1
- package/admin/rules/assets/{index-BRdNnGcA.js → index-DwYdaT5M.js} +80 -81
- package/admin/rules/customRuleBlocks.js +2 -2
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Alexa/AlexaResponse.js +101 -95
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/AlexaResponse.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Alexa/Capabilities/Base.js +22 -36
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/Base.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/BrightnessController.js +19 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/BrightnessController.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/ColorController.js +14 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/ColorController.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/ColorTemperatureController.js +19 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/ColorTemperatureController.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/ContactSensor.js +16 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/ContactSensor.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/LockController.js +14 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/LockController.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Alexa/Capabilities/ModeController.js +27 -28
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/ModeController.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/MotionSensor.js +14 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/MotionSensor.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/PercentageController.js +14 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/PercentageController.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/PowerController.js +19 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/PowerController.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/Speaker.js +25 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/Speaker.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/TemperatureSensor.js +14 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/TemperatureSensor.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/ThermostatController.js +37 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/ThermostatController.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/index.js +32 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Capabilities/index.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Directives/Base.js +29 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Directives/Base.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Alexa/Directives/ChangeReport.js +34 -27
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Directives/ChangeReport.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Directives/Discovery.js +39 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Directives/Discovery.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Alexa/Directives/ReportState.js +19 -22
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Directives/ReportState.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Directives/index.js +14 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Directives/index.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/ModeValues/Base.js +36 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/ModeValues/Base.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/ModeValues/Closed.js +57 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/ModeValues/Closed.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/ModeValues/Open.js +57 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/ModeValues/Open.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/ModeValues/index.js +12 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/ModeValues/index.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/AdjustableProperty.js +16 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/AdjustableProperty.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Base.js +127 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Base.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Brightness.js +18 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Brightness.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Color.js +38 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Color.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Alexa/Properties/ColorTemperatureInKelvin.js +20 -29
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/ColorTemperatureInKelvin.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/DetectionState.js +23 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/DetectionState.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Alexa/Properties/LockState.js +9 -12
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/LockState.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Mode.js +34 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Mode.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Muted.js +19 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Muted.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Percentage.js +18 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Percentage.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Alexa/Properties/PowerState.js +9 -9
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/PowerState.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/TargetSetpoint.js +31 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/TargetSetpoint.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Temperature.js +22 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Temperature.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/ThermostatMode.js +49 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/ThermostatMode.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Volume.js +21 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/Volume.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/index.js +38 -0
- package/build-backend/lib/AlexaSmartHomeV3/Alexa/Properties/index.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/AdjustableControl.js +20 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/AdjustableControl.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/AdjustablePercentageControl.js +26 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/AdjustablePercentageControl.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/AirCondition.js +148 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/AirCondition.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Blind.js +13 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Blind.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/ContactSensor.js +17 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/ContactSensor.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Controls/Control.js +73 -104
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Control.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Ct.js +182 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Ct.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Dimmer.js +127 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Dimmer.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Door.js +10 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Door.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Gate.js +38 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Gate.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Hue.js +208 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Hue.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Controls/Light.js +15 -22
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Light.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Lock.js +35 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Lock.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Motion.js +17 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Motion.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/ReadOnlyDetector.js +26 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/ReadOnlyDetector.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Slider.js +10 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Slider.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Socket.js +21 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Socket.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Temperature.js +21 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Temperature.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Thermostat.js +85 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Thermostat.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/VacuumCleaner.js +27 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/VacuumCleaner.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Volume.js +116 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Volume.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/VolumeGroup.js +10 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/VolumeGroup.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Window.js +10 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/Window.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/index.js +121 -0
- package/build-backend/lib/AlexaSmartHomeV3/Controls/index.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Device.js +29 -30
- package/build-backend/lib/AlexaSmartHomeV3/Device.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/DeviceManager.js +392 -0
- package/build-backend/lib/AlexaSmartHomeV3/DeviceManager.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Exceptions/AlexaV3Exception.js +10 -0
- package/build-backend/lib/AlexaSmartHomeV3/Exceptions/AlexaV3Exception.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Exceptions/HourlyDeviceRateLimitExceeded.js +10 -0
- package/build-backend/lib/AlexaSmartHomeV3/Exceptions/HourlyDeviceRateLimitExceeded.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Exceptions/OverallDailyRateLimitExceeded.js +10 -0
- package/build-backend/lib/AlexaSmartHomeV3/Exceptions/OverallDailyRateLimitExceeded.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Helpers/AdapterProvider.js +12 -21
- package/build-backend/lib/AlexaSmartHomeV3/Helpers/AdapterProvider.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Helpers/FileHelper.js +53 -0
- package/build-backend/lib/AlexaSmartHomeV3/Helpers/FileHelper.js.map +1 -0
- package/{lib → build-backend/lib}/AlexaSmartHomeV3/Helpers/IotProxy.js +9 -26
- package/build-backend/lib/AlexaSmartHomeV3/Helpers/IotProxy.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Helpers/Logger.js +93 -0
- package/build-backend/lib/AlexaSmartHomeV3/Helpers/Logger.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Helpers/RateLimiter.js +112 -0
- package/build-backend/lib/AlexaSmartHomeV3/Helpers/RateLimiter.js.map +1 -0
- package/build-backend/lib/AlexaSmartHomeV3/Helpers/Utils.js +625 -0
- package/build-backend/lib/AlexaSmartHomeV3/Helpers/Utils.js.map +1 -0
- package/build-backend/lib/Utils.js +96 -0
- package/build-backend/lib/Utils.js.map +1 -0
- package/build-backend/lib/adminCommonSocket.js +715 -0
- package/build-backend/lib/adminCommonSocket.js.map +1 -0
- package/build-backend/lib/alexaCustom.js +542 -0
- package/build-backend/lib/alexaCustom.js.map +1 -0
- package/{lib → build-backend/lib}/alexaSmartHomeV2.js +4 -8
- package/{lib → build-backend/lib}/alexaSmartHomeV3.js +25 -45
- package/build-backend/lib/alexaSmartHomeV3.js.map +1 -0
- package/{lib → build-backend/lib}/alisa.js +41 -44
- package/{lib → build-backend/lib}/devices.js +11 -8
- package/build-backend/lib/devices.js.map +1 -0
- package/{lib → build-backend/lib}/functions.js +11 -8
- package/build-backend/lib/functions.js.map +1 -0
- package/{lib → build-backend/lib}/googleHome.js +25 -26
- package/{lib → build-backend/lib}/notifications.js +15 -22
- package/build-backend/lib/notifications.js.map +1 -0
- package/{lib → build-backend/lib}/remote.js +615 -636
- package/build-backend/lib/remote.js.map +1 -0
- package/{lib → build-backend/lib}/rooms.js +11 -8
- package/build-backend/lib/rooms.js.map +1 -0
- package/{lib → build-backend/lib}/texts.js +6 -4
- package/build-backend/lib/texts.js.map +1 -0
- package/build-backend/lib/translate.js +21 -0
- package/build-backend/lib/translate.js.map +1 -0
- package/{lib → build-backend/lib}/visuApp.js +45 -65
- package/build-backend/lib/visuApp.js.map +1 -0
- package/build-backend/main.js +1361 -0
- package/build-backend/main.js.map +1 -0
- package/io-package.json +14 -14
- package/package.json +18 -15
- package/admin/assets/index-DCbOB3g_.js +0 -681
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/BrightnessController.js +0 -15
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/ColorController.js +0 -10
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/ColorTemperatureController.js +0 -15
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/ContactSensor.js +0 -10
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/LockController.js +0 -10
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/MotionSensor.js +0 -10
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/PercentageController.js +0 -10
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/PowerController.js +0 -15
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/Speaker.js +0 -20
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/TemperatureSensor.js +0 -10
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/ThermostatController.js +0 -34
- package/lib/AlexaSmartHomeV3/Alexa/Capabilities/index.js +0 -14
- package/lib/AlexaSmartHomeV3/Alexa/Directives/Base.js +0 -27
- package/lib/AlexaSmartHomeV3/Alexa/Directives/Discovery.js +0 -39
- package/lib/AlexaSmartHomeV3/Alexa/Directives/index.js +0 -13
- package/lib/AlexaSmartHomeV3/Alexa/ModeValues/Base.js +0 -38
- package/lib/AlexaSmartHomeV3/Alexa/ModeValues/Closed.js +0 -55
- package/lib/AlexaSmartHomeV3/Alexa/ModeValues/Open.js +0 -56
- package/lib/AlexaSmartHomeV3/Alexa/ModeValues/index.js +0 -14
- package/lib/AlexaSmartHomeV3/Alexa/Properties/AdjustableProperty.js +0 -11
- package/lib/AlexaSmartHomeV3/Alexa/Properties/Base.js +0 -108
- package/lib/AlexaSmartHomeV3/Alexa/Properties/Brightness.js +0 -14
- package/lib/AlexaSmartHomeV3/Alexa/Properties/Color.js +0 -40
- package/lib/AlexaSmartHomeV3/Alexa/Properties/DetectionState.js +0 -22
- package/lib/AlexaSmartHomeV3/Alexa/Properties/Mode.js +0 -32
- package/lib/AlexaSmartHomeV3/Alexa/Properties/Muted.js +0 -17
- package/lib/AlexaSmartHomeV3/Alexa/Properties/Percentage.js +0 -14
- package/lib/AlexaSmartHomeV3/Alexa/Properties/TargetSetpoint.js +0 -28
- package/lib/AlexaSmartHomeV3/Alexa/Properties/Temperature.js +0 -20
- package/lib/AlexaSmartHomeV3/Alexa/Properties/ThermostatMode.js +0 -52
- package/lib/AlexaSmartHomeV3/Alexa/Properties/Volume.js +0 -19
- package/lib/AlexaSmartHomeV3/Alexa/Properties/index.js +0 -14
- package/lib/AlexaSmartHomeV3/Controls/AdjustableControl.js +0 -22
- package/lib/AlexaSmartHomeV3/Controls/AdjustablePercentageControl.js +0 -28
- package/lib/AlexaSmartHomeV3/Controls/AirCondition.js +0 -144
- package/lib/AlexaSmartHomeV3/Controls/Blind.js +0 -12
- package/lib/AlexaSmartHomeV3/Controls/ContactSensor.js +0 -17
- package/lib/AlexaSmartHomeV3/Controls/Ct.js +0 -172
- package/lib/AlexaSmartHomeV3/Controls/Dimmer.js +0 -124
- package/lib/AlexaSmartHomeV3/Controls/Door.js +0 -9
- package/lib/AlexaSmartHomeV3/Controls/Gate.js +0 -42
- package/lib/AlexaSmartHomeV3/Controls/Hue.js +0 -207
- package/lib/AlexaSmartHomeV3/Controls/Lock.js +0 -36
- package/lib/AlexaSmartHomeV3/Controls/Motion.js +0 -17
- package/lib/AlexaSmartHomeV3/Controls/ReadOnlyDetector.js +0 -25
- package/lib/AlexaSmartHomeV3/Controls/Slider.js +0 -10
- package/lib/AlexaSmartHomeV3/Controls/Socket.js +0 -21
- package/lib/AlexaSmartHomeV3/Controls/Temperature.js +0 -22
- package/lib/AlexaSmartHomeV3/Controls/Thermostat.js +0 -86
- package/lib/AlexaSmartHomeV3/Controls/VacuumCleaner.js +0 -28
- package/lib/AlexaSmartHomeV3/Controls/Volume.js +0 -109
- package/lib/AlexaSmartHomeV3/Controls/VolumeGroup.js +0 -9
- package/lib/AlexaSmartHomeV3/Controls/Window.js +0 -9
- package/lib/AlexaSmartHomeV3/Controls/index.js +0 -14
- package/lib/AlexaSmartHomeV3/DeviceManager.js +0 -415
- package/lib/AlexaSmartHomeV3/Exceptions/AlexaV3Exception.js +0 -8
- package/lib/AlexaSmartHomeV3/Exceptions/HourlyDeviceRateLimitExceeded.js +0 -5
- package/lib/AlexaSmartHomeV3/Exceptions/OverallDailyRateLimitExceeded.js +0 -5
- package/lib/AlexaSmartHomeV3/Helpers/FileHelper.js +0 -70
- package/lib/AlexaSmartHomeV3/Helpers/Logger.js +0 -95
- package/lib/AlexaSmartHomeV3/Helpers/RateLimiter.js +0 -82
- package/lib/AlexaSmartHomeV3/Helpers/Utils.js +0 -583
- package/lib/Utils.js +0 -608
- package/lib/adminCommonSocket.js +0 -781
- package/lib/alexaCustom.js +0 -622
- package/lib/translate.js +0 -19
- package/main.js +0 -1454
|
@@ -0,0 +1,1361 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.IotAdapter = void 0;
|
|
7
|
+
const aws_iot_device_sdk_1 = require("aws-iot-device-sdk");
|
|
8
|
+
const adapter_core_1 = require("@iobroker/adapter-core"); // Get common adapter utils
|
|
9
|
+
const node_fs_1 = require("node:fs");
|
|
10
|
+
const axios_1 = __importDefault(require("axios"));
|
|
11
|
+
const node_zlib_1 = require("node:zlib");
|
|
12
|
+
// @ts-expect-error no types
|
|
13
|
+
const alexaSmartHomeV2_1 = __importDefault(require("./lib/alexaSmartHomeV2"));
|
|
14
|
+
const alexaSmartHomeV3_1 = __importDefault(require("./lib/alexaSmartHomeV3"));
|
|
15
|
+
const alexaCustom_1 = __importDefault(require("./lib/alexaCustom"));
|
|
16
|
+
// @ts-expect-error no types
|
|
17
|
+
const googleHome_1 = __importDefault(require("./lib/googleHome"));
|
|
18
|
+
// @ts-expect-error no types
|
|
19
|
+
const alisa_1 = __importDefault(require("./lib/alisa"));
|
|
20
|
+
const remote_1 = __importDefault(require("./lib/remote"));
|
|
21
|
+
const visuApp_1 = require("./lib/visuApp");
|
|
22
|
+
const notifications_1 = require("./lib/notifications");
|
|
23
|
+
const NONE = '___none___';
|
|
24
|
+
const MAX_IOT_MESSAGE_LENGTH = 127 * 1024;
|
|
25
|
+
const SPECIAL_ADAPTERS = ['netatmo'];
|
|
26
|
+
const ALLOWED_SERVICES = SPECIAL_ADAPTERS.concat(['text2command']);
|
|
27
|
+
class IotAdapter extends adapter_core_1.Adapter {
|
|
28
|
+
recalcTimeout = null;
|
|
29
|
+
lang = 'de';
|
|
30
|
+
translate = false;
|
|
31
|
+
alexaSH2 = null;
|
|
32
|
+
alexaSH3 = null;
|
|
33
|
+
googleHome = null;
|
|
34
|
+
alexaCustom = null;
|
|
35
|
+
yandexAlisa = null;
|
|
36
|
+
remote = null;
|
|
37
|
+
device = null;
|
|
38
|
+
urlKey = null;
|
|
39
|
+
connectedOwn = false;
|
|
40
|
+
secret = '';
|
|
41
|
+
connectStarted = 0;
|
|
42
|
+
constructor(options = {}) {
|
|
43
|
+
super({
|
|
44
|
+
...options,
|
|
45
|
+
name: 'iot',
|
|
46
|
+
objectChange: (id, obj) => {
|
|
47
|
+
if (id === 'system.config' && obj && !this.translate) {
|
|
48
|
+
const systemObj = obj;
|
|
49
|
+
this.lang = systemObj.common.language;
|
|
50
|
+
if (this.lang !== 'en' && this.lang !== 'de' && this.lang !== 'ru') {
|
|
51
|
+
this.lang = 'en';
|
|
52
|
+
}
|
|
53
|
+
this.alexaSH2?.setLanguage(this.lang);
|
|
54
|
+
this.alexaSH3?.setLanguage(this.lang);
|
|
55
|
+
this.yandexAlisa?.setLanguage(this.lang);
|
|
56
|
+
this.alexaCustom?.setLanguage(this.lang);
|
|
57
|
+
this.googleHome?.setLanguage(this.lang);
|
|
58
|
+
this.remote?.setLanguage(this.lang);
|
|
59
|
+
}
|
|
60
|
+
// if it is an instance
|
|
61
|
+
if (id.startsWith('system.adapter.')) {
|
|
62
|
+
// try to find it in special adapters
|
|
63
|
+
const adpr = SPECIAL_ADAPTERS.find(a => id.startsWith(`system.adapter.${a}.`));
|
|
64
|
+
// if found and it is really instance
|
|
65
|
+
if (adpr && id.match(/\.\d+$/)) {
|
|
66
|
+
// update state
|
|
67
|
+
setTimeout(async () => await this.createStateForAdapter(adpr), 1000);
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
void this.alexaSH3?.handleObjectChange(id, obj);
|
|
72
|
+
if (id) {
|
|
73
|
+
this.remote?.updateObject(id, obj);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
stateChange: async (id, state) => {
|
|
77
|
+
if (id === `${this.namespace}.app.message` && state && !state.ack) {
|
|
78
|
+
try {
|
|
79
|
+
await this.sendMessageToApp(state.val);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
this.log.error(`Cannot send message to app: ${e}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (state) {
|
|
86
|
+
if (this.config.googleHome) {
|
|
87
|
+
void this.googleHome?.updateState(id, state);
|
|
88
|
+
}
|
|
89
|
+
if (this.config.amazonAlexa) {
|
|
90
|
+
void this.alexaSH3?.handleStateUpdate(id, state);
|
|
91
|
+
}
|
|
92
|
+
if (this.config.yandexAlisa) {
|
|
93
|
+
void this.yandexAlisa?.updateState?.(id, state);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (id) {
|
|
97
|
+
this.remote?.updateState(id, state);
|
|
98
|
+
}
|
|
99
|
+
if (id === `${this.namespace}.smart.lastResponse` && state && !state.ack) {
|
|
100
|
+
this.alexaCustom?.setResponse(state.val);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
unload: async (callback) => {
|
|
104
|
+
try {
|
|
105
|
+
if (this.device) {
|
|
106
|
+
this.device.end();
|
|
107
|
+
this.device = null;
|
|
108
|
+
}
|
|
109
|
+
if (this.remote) {
|
|
110
|
+
this.remote.destroy();
|
|
111
|
+
this.remote = null;
|
|
112
|
+
}
|
|
113
|
+
if (this.alexaSH3) {
|
|
114
|
+
await this.alexaSH3.destroy();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// ignore
|
|
119
|
+
}
|
|
120
|
+
callback();
|
|
121
|
+
},
|
|
122
|
+
message: async (obj) => {
|
|
123
|
+
if (obj) {
|
|
124
|
+
switch (obj.command) {
|
|
125
|
+
case 'update':
|
|
126
|
+
if (this.recalcTimeout) {
|
|
127
|
+
clearTimeout(this.recalcTimeout);
|
|
128
|
+
}
|
|
129
|
+
this.recalcTimeout = setTimeout(async () => {
|
|
130
|
+
this.recalcTimeout = null;
|
|
131
|
+
this.alexaSH2?.updateDevices(obj.message, async (analyseAddedId) => {
|
|
132
|
+
await this.setStateAsync('smart.updatesResult', analyseAddedId || '', true);
|
|
133
|
+
this.log.debug('Devices updated!');
|
|
134
|
+
await this.setStateAsync('smart.updates', true, true);
|
|
135
|
+
});
|
|
136
|
+
// this.alexaSH3 && this.alexaSH3.updateDevices(obj.message, async analyseAddedId => {
|
|
137
|
+
// await this.setStateAsync('smart.updatesResult', analyseAddedId || '', true);
|
|
138
|
+
// await this.setStateAsync('smart.updates3', true, true);
|
|
139
|
+
// });
|
|
140
|
+
if (this.alexaSH3) {
|
|
141
|
+
await this.alexaSH3.updateDevices();
|
|
142
|
+
await this.setStateAsync('smart.updates3', true, true);
|
|
143
|
+
}
|
|
144
|
+
this.googleHome?.updateDevices(async (analyseAddedId) => {
|
|
145
|
+
await this.setStateAsync('smart.updatesResult', analyseAddedId || '', true);
|
|
146
|
+
this.log.debug('GH Devices updated!');
|
|
147
|
+
await this.setStateAsync('smart.updatesGH', true, true);
|
|
148
|
+
});
|
|
149
|
+
}, 1000);
|
|
150
|
+
break;
|
|
151
|
+
case 'browse':
|
|
152
|
+
if (obj.callback) {
|
|
153
|
+
this.log.info('Request devices');
|
|
154
|
+
if (this.alexaSH2) {
|
|
155
|
+
this.alexaSH2.updateDevices(() => {
|
|
156
|
+
this.sendTo(obj.from, obj.command, this.alexaSH2.getDevices(), obj.callback);
|
|
157
|
+
void this.setState('smart.updates', false, true);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
this.sendTo(obj.from, obj.command, { error: 'not activated' }, obj.callback);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
break;
|
|
165
|
+
case 'browse3':
|
|
166
|
+
if (obj.callback) {
|
|
167
|
+
this.log.info('Request V3 devices');
|
|
168
|
+
if (this.alexaSH3) {
|
|
169
|
+
const devices = await this.alexaSH3.getDevices();
|
|
170
|
+
this.sendTo(obj.from, obj.command, devices, obj.callback);
|
|
171
|
+
await this.setStateAsync('smart.updates3', false, true);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
this.sendTo(obj.from, obj.command, { error: 'not activated' }, obj.callback);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
case 'browseGH':
|
|
179
|
+
if (obj.callback) {
|
|
180
|
+
this.log.info('Request google home devices');
|
|
181
|
+
if (this.googleHome) {
|
|
182
|
+
this.googleHome.updateDevices(() => {
|
|
183
|
+
this.sendTo(obj.from, obj.command, this.googleHome.getDevices(), obj.callback);
|
|
184
|
+
void this.setStateAsync('smart.updatesGH', false, true);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
this.sendTo(obj.from, obj.command, { error: 'not activated' }, obj.callback);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
case 'browseAlisa':
|
|
193
|
+
if (obj.callback) {
|
|
194
|
+
this.log.info('Request Yandex Alice devices');
|
|
195
|
+
if (this.yandexAlisa) {
|
|
196
|
+
this.yandexAlisa.updateDevices(() => {
|
|
197
|
+
this.sendTo(obj.from, obj.command, this.yandexAlisa.getDevices(), obj.callback);
|
|
198
|
+
void this.setStateAsync('smart.updatesYA', false, true);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
this.sendTo(obj.from, obj.command, { error: 'not activated' }, obj.callback);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
case 'alexaCustomKnownDevices':
|
|
207
|
+
// Admin UI can request the known/discoveredAlexa devices used via Custom skill
|
|
208
|
+
// Allow setting the rooms of the devices and store in adapter config
|
|
209
|
+
// Restart adapter after change - or we also add a set message to the config
|
|
210
|
+
if (obj.callback) {
|
|
211
|
+
this.log.info('Request Alexa Custom known devices');
|
|
212
|
+
if (this.alexaCustom) {
|
|
213
|
+
const devices = this.alexaCustom.getKnownDevices();
|
|
214
|
+
this.sendTo(obj.from, obj.command, devices, obj.callback);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
this.sendTo(obj.from, obj.command, { error: 'not activated' }, obj.callback);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
221
|
+
case 'alexaCustomKnownUsers':
|
|
222
|
+
// Admin UI can request the known/discoveredAlexa users used via Custom skill
|
|
223
|
+
// Allow setting the names of the users and store in adapter config
|
|
224
|
+
// Restart adapter after change - or we also add a set message to the config
|
|
225
|
+
if (obj.callback) {
|
|
226
|
+
this.log.info('Request Alexa Custom known users');
|
|
227
|
+
if (this.alexaCustom) {
|
|
228
|
+
const users = this.alexaCustom.getKnownUsers();
|
|
229
|
+
this.sendTo(obj.from, obj.command, users, obj.callback);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
this.sendTo(obj.from, obj.command, { error: 'not activated' }, obj.callback);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
break;
|
|
236
|
+
case 'private': {
|
|
237
|
+
if (typeof obj.message !== 'object') {
|
|
238
|
+
try {
|
|
239
|
+
obj.message = JSON.parse(obj.message);
|
|
240
|
+
}
|
|
241
|
+
catch (e) {
|
|
242
|
+
this.log.error(`Cannot parse object: ${e}`);
|
|
243
|
+
obj.callback &&
|
|
244
|
+
this.sendTo(obj.from, obj.command, { error: 'Invalid message format: cannot parse object' }, obj.callback);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const response = await this.processMessage(obj.message.type, obj.message.request);
|
|
249
|
+
if (obj.callback) {
|
|
250
|
+
this.sendTo(obj.from, obj.command, response, obj.callback);
|
|
251
|
+
}
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
case 'ifttt':
|
|
255
|
+
this.sendDataToIFTTT(obj.message);
|
|
256
|
+
break;
|
|
257
|
+
case 'alexaCustomResponse':
|
|
258
|
+
this.alexaCustom?.setResponse(obj.message);
|
|
259
|
+
break;
|
|
260
|
+
case 'debug':
|
|
261
|
+
this.alexaSH2?.getDebug((data) => this.sendTo(obj.from, obj.command, data, obj.callback));
|
|
262
|
+
break;
|
|
263
|
+
case 'getServiceEndpoint':
|
|
264
|
+
if (obj.callback) {
|
|
265
|
+
if (!this.urlKey) {
|
|
266
|
+
try {
|
|
267
|
+
this.urlKey = await this.readUrlKey();
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
try {
|
|
271
|
+
this.urlKey = await this.createUrlKey(this.config.login, this.config.pass);
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
return (obj.callback &&
|
|
275
|
+
this.sendTo(obj.from, obj.command, { error: `Cannot get urlKey: ${err.toString()}` }, obj.callback));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const result = {
|
|
280
|
+
url: `https://service.iobroker.in/v1/iotService?key=${this.urlKey.key}&user=${encodeURIComponent(this.config.login)}`,
|
|
281
|
+
};
|
|
282
|
+
const serviceName = typeof obj.message === 'string' ? obj.message : obj.message?.serviceName;
|
|
283
|
+
if (serviceName) {
|
|
284
|
+
result.url += `&service=${encodeURIComponent(serviceName)}`;
|
|
285
|
+
result.stateID = `${this.namespace}.services.${serviceName}`;
|
|
286
|
+
}
|
|
287
|
+
if (obj.message?.data) {
|
|
288
|
+
result.data += `&data=${typeof obj.message.data === 'object' ? JSON.stringify(obj.message.data) : obj.message.data}`;
|
|
289
|
+
}
|
|
290
|
+
// check if the service name is in the white list
|
|
291
|
+
if (serviceName &&
|
|
292
|
+
this.config.allowedServices[0] !== '*' &&
|
|
293
|
+
!this.config.allowedServices.includes(serviceName.replace(/^custom_/, '')) &&
|
|
294
|
+
!ALLOWED_SERVICES.includes(serviceName)) {
|
|
295
|
+
result.warning = 'Service name is not in white list';
|
|
296
|
+
this.log.warn(`Service "${serviceName}" is not in allowed services list`);
|
|
297
|
+
}
|
|
298
|
+
if (obj.callback) {
|
|
299
|
+
this.sendTo(obj.from, obj.command, result, obj.callback);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
303
|
+
case 'sendNotification':
|
|
304
|
+
try {
|
|
305
|
+
const { message, title } = (0, notifications_1.buildMessageFromNotification)(obj.message);
|
|
306
|
+
await this.sendMessageToApp(JSON.stringify({ message, title }));
|
|
307
|
+
if (obj.callback) {
|
|
308
|
+
this.sendTo(obj.from, 'sendNotification', { sent: true }, obj.callback);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
if (obj.callback) {
|
|
313
|
+
this.sendTo(obj.from, 'sendNotification', { sent: false }, obj.callback);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
break;
|
|
317
|
+
default:
|
|
318
|
+
this.log.warn(`Unknown command: ${obj.command}`);
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
ready: () => this.main()
|
|
324
|
+
.then(() => { })
|
|
325
|
+
.catch(error => {
|
|
326
|
+
this.log.error(`Error in main: ${error.toString()}`);
|
|
327
|
+
}),
|
|
328
|
+
});
|
|
329
|
+
// warning: `this.log = obj => console.log(obj)` does not implemented. Only this.on('log', obj => console.log(obj))
|
|
330
|
+
this.on('log', obj => this.remote?.onLog(obj));
|
|
331
|
+
}
|
|
332
|
+
sendDataToIFTTT(obj) {
|
|
333
|
+
if (!obj) {
|
|
334
|
+
this.log.warn('No data to send to IFTTT');
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (!this.config.iftttKey && (typeof obj !== 'object' || !obj.key)) {
|
|
338
|
+
this.log.warn('No IFTTT key is defined');
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
let url;
|
|
342
|
+
let data;
|
|
343
|
+
if (typeof obj !== 'object') {
|
|
344
|
+
url = `https://maker.ifttt.com/trigger/state/with/key/${this.config.iftttKey}`;
|
|
345
|
+
data = {
|
|
346
|
+
value1: `${this.namespace}.services.ifttt`,
|
|
347
|
+
value2: obj,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
else if (obj.event) {
|
|
351
|
+
const event = obj.event;
|
|
352
|
+
const key = obj.key;
|
|
353
|
+
delete obj.event;
|
|
354
|
+
delete obj.key;
|
|
355
|
+
url = `https://maker.ifttt.com/trigger/${event}/with/key/${key || this.config.iftttKey}`;
|
|
356
|
+
data = obj;
|
|
357
|
+
}
|
|
358
|
+
else if (obj.val === undefined) {
|
|
359
|
+
return this.log.warn('No value is defined');
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
obj.id = obj.id || `${this.namespace}.services.ifttt`;
|
|
363
|
+
url = `https://maker.ifttt.com/trigger/state/with/key/${this.config.iftttKey}`;
|
|
364
|
+
data = {
|
|
365
|
+
value1: obj.id,
|
|
366
|
+
value2: obj.val,
|
|
367
|
+
value3: obj.ack,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
if (url) {
|
|
371
|
+
axios_1.default
|
|
372
|
+
.post(url, data, {
|
|
373
|
+
timeout: 15000,
|
|
374
|
+
validateStatus: status => status < 400,
|
|
375
|
+
})
|
|
376
|
+
.then(response => this.log.debug(`Response from IFTTT: ${JSON.stringify(response.data)}`))
|
|
377
|
+
.catch(error => {
|
|
378
|
+
if (error.response) {
|
|
379
|
+
this.log.warn(`Response from IFTTT: ${error.response.data ? JSON.stringify(error.response.data) : error.response.status}`);
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
this.log.warn(`Response from IFTTT: ${error.code}`);
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
this.log.warn(`Invalid request to IFTTT: ${JSON.stringify(obj)}`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Send a message to the ioBroker Visu App by using the app-message endpoint (which then forwards it to the app via FCM)
|
|
392
|
+
*
|
|
393
|
+
* @param message either a json string or the message itself, if the message itself the other props will be taken from the adapter states
|
|
394
|
+
*/
|
|
395
|
+
async sendMessageToApp(message) {
|
|
396
|
+
if (!message) {
|
|
397
|
+
throw new Error('Empty message');
|
|
398
|
+
}
|
|
399
|
+
const trimmedMessage = message.toString().trim();
|
|
400
|
+
let json;
|
|
401
|
+
if (trimmedMessage.startsWith('{') && trimmedMessage.endsWith('}')) {
|
|
402
|
+
try {
|
|
403
|
+
json = JSON.parse(trimmedMessage);
|
|
404
|
+
}
|
|
405
|
+
catch {
|
|
406
|
+
this.log.warn(`Cannot parse message: ${trimmedMessage}`);
|
|
407
|
+
json = null;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
json = null;
|
|
412
|
+
}
|
|
413
|
+
if (!json) {
|
|
414
|
+
// take expires
|
|
415
|
+
const ttlSecondsState = await this.getStateAsync(`${this.namespace}.app.expire`);
|
|
416
|
+
const priorityState = await this.getStateAsync(`${this.namespace}.app.priority`);
|
|
417
|
+
const titleState = await this.getStateAsync(`${this.namespace}.app.title`);
|
|
418
|
+
const priorityVal = priorityState?.val;
|
|
419
|
+
json = {
|
|
420
|
+
message: message.toString(),
|
|
421
|
+
priority: priorityVal === '1' || priorityVal === 'high' || priorityVal === true ? 'high' : undefined,
|
|
422
|
+
ttlSeconds: parseInt(ttlSecondsState?.val, 0) || undefined,
|
|
423
|
+
title: (titleState?.val || 'ioBroker').toString(),
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
427
|
+
if (json.expire) {
|
|
428
|
+
json.ttlSeconds = json.expire;
|
|
429
|
+
delete json.expire;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
json.ttlSeconds = parseInt(json.ttlSeconds, 0) || undefined;
|
|
433
|
+
if (json.ttlSeconds && json.ttlSeconds > 3_600 * 48) {
|
|
434
|
+
json.ttlSeconds = 3_600 * 48;
|
|
435
|
+
}
|
|
436
|
+
if (!json.message) {
|
|
437
|
+
throw new Error('Empty message');
|
|
438
|
+
}
|
|
439
|
+
const response = await axios_1.default.post('https://app-message.iobroker.in/', json, {
|
|
440
|
+
headers: {
|
|
441
|
+
'Content-Type': 'application/json',
|
|
442
|
+
Authorization: `Bearer ${Buffer.from(`${this.config.login}:${this.config.pass}`).toString('base64')}`,
|
|
443
|
+
},
|
|
444
|
+
timeout: 5_000,
|
|
445
|
+
validateStatus: status => status < 400,
|
|
446
|
+
});
|
|
447
|
+
await this.setState('app.message', message, true);
|
|
448
|
+
this.log.debug(`Message sent: ${JSON.stringify(response.data)}`);
|
|
449
|
+
}
|
|
450
|
+
async controlState(id, data) {
|
|
451
|
+
id ||= 'services.ifttt';
|
|
452
|
+
if (typeof data === 'object') {
|
|
453
|
+
if (data.id) {
|
|
454
|
+
if (data.id === `${this.namespace}.services.ifttt`) {
|
|
455
|
+
data.ack = true;
|
|
456
|
+
}
|
|
457
|
+
if (data.val === undefined) {
|
|
458
|
+
throw new Error('No value set');
|
|
459
|
+
}
|
|
460
|
+
const obj = await this.getForeignObjectAsync(data.id);
|
|
461
|
+
if (!obj || !obj.common) {
|
|
462
|
+
throw new Error(`Unknown ID: ${data.id}`);
|
|
463
|
+
}
|
|
464
|
+
else {
|
|
465
|
+
if (typeof data.val === 'string') {
|
|
466
|
+
data.val = data.val.replace(/^@ifttt\s?/, '');
|
|
467
|
+
}
|
|
468
|
+
if (obj.common.type === 'boolean') {
|
|
469
|
+
data.val =
|
|
470
|
+
data.val === true ||
|
|
471
|
+
data.val === 'true' ||
|
|
472
|
+
data.val === 'on' ||
|
|
473
|
+
data.val === 'ON' ||
|
|
474
|
+
data.val === 1 ||
|
|
475
|
+
data.val === '1';
|
|
476
|
+
}
|
|
477
|
+
else if (obj.common.type === 'number') {
|
|
478
|
+
data.val = parseFloat(data.val);
|
|
479
|
+
}
|
|
480
|
+
await this.setForeignStateAsync(data.id, data.val, data.ack);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
else if (data.val !== undefined) {
|
|
484
|
+
if (typeof data.val === 'string') {
|
|
485
|
+
data.val = data.val.replace(/^@ifttt\s?/, '');
|
|
486
|
+
}
|
|
487
|
+
await this.setStateAsync(id, data.val, data.ack !== undefined ? data.ack : true);
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
await this.setStateAsync(id, JSON.stringify(data), true);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
if (typeof data === 'string') {
|
|
495
|
+
data = data.replace(/^@ifttt\s?/, '');
|
|
496
|
+
}
|
|
497
|
+
await this.setStateAsync(id, data, true);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
async processIfttt(data) {
|
|
501
|
+
this.log.debug(`Received IFTTT object: ${JSON.stringify(data)}`);
|
|
502
|
+
let id;
|
|
503
|
+
let dataObj = null;
|
|
504
|
+
// >If data is object with id and data property
|
|
505
|
+
if (typeof data === 'object' && data.id && data.data !== undefined) {
|
|
506
|
+
id = data.id;
|
|
507
|
+
if (typeof data.data === 'string' && data.data[0] === '{') {
|
|
508
|
+
try {
|
|
509
|
+
dataObj = JSON.parse(data.data);
|
|
510
|
+
}
|
|
511
|
+
catch {
|
|
512
|
+
this.log.debug(`Cannot parse: ${data.data}`);
|
|
513
|
+
dataObj = data;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
dataObj = data.data;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
else if (typeof data === 'string' && data[0] === '{') {
|
|
521
|
+
// If data is string and starts with {
|
|
522
|
+
try {
|
|
523
|
+
dataObj = JSON.parse(data);
|
|
524
|
+
if (typeof dataObj.id === 'string') {
|
|
525
|
+
id = dataObj.id;
|
|
526
|
+
if (dataObj.data) {
|
|
527
|
+
dataObj = dataObj.data;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
catch {
|
|
532
|
+
this.log.debug(`Cannot parse: ${JSON.stringify(data)}`);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
dataObj = data;
|
|
537
|
+
}
|
|
538
|
+
if (id) {
|
|
539
|
+
let obj = await this.getForeignObjectAsync(id);
|
|
540
|
+
if (!obj) {
|
|
541
|
+
const newId = `${this.namespace}.services.${id}`;
|
|
542
|
+
obj = await this.getForeignObjectAsync(newId);
|
|
543
|
+
if (!obj) {
|
|
544
|
+
// create state
|
|
545
|
+
await this.setObjectNotExistsAsync(`services.${id}`, {
|
|
546
|
+
type: 'state',
|
|
547
|
+
common: {
|
|
548
|
+
name: 'IFTTT value',
|
|
549
|
+
write: false,
|
|
550
|
+
role: 'state',
|
|
551
|
+
read: true,
|
|
552
|
+
type: 'mixed',
|
|
553
|
+
desc: 'Custom state',
|
|
554
|
+
},
|
|
555
|
+
native: {},
|
|
556
|
+
});
|
|
557
|
+
id = newId;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
await this.controlState(id || null, dataObj || data);
|
|
562
|
+
}
|
|
563
|
+
onDisconnect(event) {
|
|
564
|
+
const now = Date.now();
|
|
565
|
+
if (now - this.connectStarted < 500) {
|
|
566
|
+
this.log.warn('Looks like your connection certificates are invalid. Please renew them via configuration dialog.');
|
|
567
|
+
}
|
|
568
|
+
if (typeof event === 'string') {
|
|
569
|
+
if (event.toLowerCase().includes('duplicate')) {
|
|
570
|
+
// disable adapter
|
|
571
|
+
this.log.error(`Two devices are trying to connect with the same iot account. This is not allowed. Stopping`);
|
|
572
|
+
void this.getForeignObjectAsync(`system.adapter.${this.namespace}`).then(obj => {
|
|
573
|
+
if (obj) {
|
|
574
|
+
obj.common.enabled = false;
|
|
575
|
+
return this.setForeignObjectAsync(obj._id, obj);
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
this.log.info(`Connection changed: ${event}`);
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
this.log.info('Connection changed: disconnect');
|
|
583
|
+
}
|
|
584
|
+
if (this.connectedOwn) {
|
|
585
|
+
this.log.info('Connection lost');
|
|
586
|
+
this.connectedOwn = false;
|
|
587
|
+
void this.setState('info.connection', false, true);
|
|
588
|
+
}
|
|
589
|
+
this.remote?.onCloudDisconnect();
|
|
590
|
+
}
|
|
591
|
+
onConnect(clientId) {
|
|
592
|
+
if (!this.connectedOwn) {
|
|
593
|
+
this.log.info(`Connection changed: connect "${clientId}"`);
|
|
594
|
+
this.connectedOwn = true;
|
|
595
|
+
void this.setState('info.connection', this.connectedOwn, true);
|
|
596
|
+
// setTimeout(() => {
|
|
597
|
+
// device.publish(`response/${clientId}/stateChange`, JSON.stringify({alive: true}), {qos: 0}, (error, result) => {
|
|
598
|
+
// console.log(`Published alive: ${result}, ${error}`);
|
|
599
|
+
// });
|
|
600
|
+
// }, 2000);
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
this.log.info('Connection not changed: was connected');
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
encryptOwn(secret, value) {
|
|
607
|
+
let result = '';
|
|
608
|
+
for (let i = 0; i < value.length; i++) {
|
|
609
|
+
result += String.fromCharCode(secret[i % secret.length].charCodeAt(0) ^ value.charCodeAt(i));
|
|
610
|
+
}
|
|
611
|
+
return `base64:${Buffer.from(result).toString('base64')}`;
|
|
612
|
+
}
|
|
613
|
+
decryptOwn(secret, value) {
|
|
614
|
+
if (value.startsWith('base64:')) {
|
|
615
|
+
try {
|
|
616
|
+
value = Buffer.from(value.substring(7), 'base64').toString('ascii');
|
|
617
|
+
}
|
|
618
|
+
catch (e) {
|
|
619
|
+
this.log.error(`Cannot decrypt key: ${e}`);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
let result = '';
|
|
623
|
+
for (let i = 0; i < value.length; i++) {
|
|
624
|
+
result += String.fromCharCode(secret[i % secret.length].charCodeAt(0) ^ value.charCodeAt(i));
|
|
625
|
+
}
|
|
626
|
+
return result;
|
|
627
|
+
}
|
|
628
|
+
async readUrlKey() {
|
|
629
|
+
const key = await this.getStateAsync('certs.urlKey');
|
|
630
|
+
if (!key?.val) {
|
|
631
|
+
throw new Error('Not exists');
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
return { key: key.val };
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
async createUrlKey(login, pass) {
|
|
638
|
+
this.log.debug('Fetching URL key...');
|
|
639
|
+
let response;
|
|
640
|
+
try {
|
|
641
|
+
response = await axios_1.default.get(`https://generate-key.iobroker.in/v1/generateUrlKey?user=${encodeURIComponent(login)}&pass=${encodeURIComponent(pass)}&version=${this.version}`, {
|
|
642
|
+
timeout: 15000,
|
|
643
|
+
validateStatus: status => status < 400,
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
catch (error) {
|
|
647
|
+
if (error.response) {
|
|
648
|
+
if (error.response.status === 401) {
|
|
649
|
+
this.log.error(`Cannot create URL key because of invalid user or password`);
|
|
650
|
+
}
|
|
651
|
+
throw new Error(error.response.data);
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
throw error;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (response.data && response.data.error) {
|
|
658
|
+
this.log.error(`Cannot fetch URL key: ${JSON.stringify(response.data.error)}`);
|
|
659
|
+
throw new Error(response.data);
|
|
660
|
+
}
|
|
661
|
+
else if (response.data && response.data.key) {
|
|
662
|
+
await this.setStateAsync('certs.urlKey', response.data.key, true);
|
|
663
|
+
return { key: response.data.key };
|
|
664
|
+
}
|
|
665
|
+
else {
|
|
666
|
+
this.log.error(`Cannot fetch URL key: ${JSON.stringify(response.data)}`);
|
|
667
|
+
throw new Error(response.data);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
async readCertificates() {
|
|
671
|
+
let privateKey;
|
|
672
|
+
let certificate;
|
|
673
|
+
try {
|
|
674
|
+
privateKey = await this.getStateAsync('certs.private');
|
|
675
|
+
certificate = await this.getStateAsync('certs.certificate');
|
|
676
|
+
}
|
|
677
|
+
catch {
|
|
678
|
+
throw new Error('Not exists');
|
|
679
|
+
}
|
|
680
|
+
if (!certificate?.val || !privateKey?.val) {
|
|
681
|
+
throw new Error('Not exists');
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
return {
|
|
685
|
+
private: this.decryptOwn(this.secret, privateKey.val),
|
|
686
|
+
certificate: this.decryptOwn(this.secret, certificate.val),
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
async writeKeys(data) {
|
|
691
|
+
await this.setStateAsync('certs.private', this.encryptOwn(this.secret, data.keyPair.PrivateKey), true);
|
|
692
|
+
await this.setStateAsync('certs.public', this.encryptOwn(this.secret, data.keyPair.PublicKey), true);
|
|
693
|
+
await this.setStateAsync('certs.certificate', this.encryptOwn(this.secret, data.certificatePem), true);
|
|
694
|
+
await this.setStateAsync('certs.id', data.certificateId, true);
|
|
695
|
+
}
|
|
696
|
+
async fetchCertificates(login, pass, _forceUserCreation) {
|
|
697
|
+
const state = await this.getStateAsync('certs.forceUserCreate');
|
|
698
|
+
const forceUserCreation = state?.val;
|
|
699
|
+
if (forceUserCreation) {
|
|
700
|
+
await this.setStateAsync('certs.forceUserCreate', false, true);
|
|
701
|
+
}
|
|
702
|
+
this.log.debug('Fetching certificates...');
|
|
703
|
+
let response;
|
|
704
|
+
try {
|
|
705
|
+
response = await axios_1.default.get(`https://create-user.iobroker.in/v1/createUser?user=${encodeURIComponent(login)}&pass=${encodeURIComponent(pass)}&forceRecreate=${forceUserCreation}&version=${this.version}`, {
|
|
706
|
+
timeout: 15000,
|
|
707
|
+
validateStatus: status => status < 400,
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
catch (error) {
|
|
711
|
+
if (error.response) {
|
|
712
|
+
if (error.response.status === 401) {
|
|
713
|
+
this.log.error(`Cannot fetch connection certificates because of invalid user or password`);
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
this.log.error(`Cannot fetch connection certificates: ${JSON.stringify(error.response.data)}`);
|
|
717
|
+
}
|
|
718
|
+
throw new Error(error.response.data);
|
|
719
|
+
}
|
|
720
|
+
else {
|
|
721
|
+
this.log.error(`Cannot fetch connection certificates: ${JSON.stringify(error.code)}`);
|
|
722
|
+
throw error;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if (response?.data?.certificates) {
|
|
726
|
+
const awsCertificates = response.data.certificates;
|
|
727
|
+
await this.writeKeys(awsCertificates);
|
|
728
|
+
return {
|
|
729
|
+
private: awsCertificates.keyPair.PrivateKey,
|
|
730
|
+
certificate: awsCertificates.certificatePem,
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
this.log.error(`Cannot fetch connection certificates: ${JSON.stringify(response.data)}`);
|
|
734
|
+
throw new Error(response.data);
|
|
735
|
+
}
|
|
736
|
+
async processMessage(type, request) {
|
|
737
|
+
if (request instanceof Buffer) {
|
|
738
|
+
request = request.toString();
|
|
739
|
+
}
|
|
740
|
+
this.log.debug(`Data: ${JSON.stringify(request)}`);
|
|
741
|
+
if (!request || !type) {
|
|
742
|
+
return { error: 'invalid request' };
|
|
743
|
+
}
|
|
744
|
+
if (type.startsWith('remote')) {
|
|
745
|
+
const start = Date.now();
|
|
746
|
+
if (this.remote) {
|
|
747
|
+
return this.remote
|
|
748
|
+
.process(request, type)
|
|
749
|
+
.then(response => {
|
|
750
|
+
if (response !== NONE) {
|
|
751
|
+
this.log.debug(`[REMOTE] Response in: ${Date.now() - start}ms (Length: ${Array.isArray(response) ? `A ${response.length}` : JSON.stringify(response).length}) for ${request}`);
|
|
752
|
+
}
|
|
753
|
+
return response;
|
|
754
|
+
})
|
|
755
|
+
.catch(err => {
|
|
756
|
+
this.log.error(`Error in processing of remote request: ${err.toString()}`);
|
|
757
|
+
return NONE;
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
this.log.error(`Received command, but remote already closed.`);
|
|
761
|
+
}
|
|
762
|
+
else if (type.startsWith('nightscout')) {
|
|
763
|
+
if (this.config.nightscout) {
|
|
764
|
+
const state = await this.getForeignStateAsync(`system.adapter.nightscout.${this.config.nightscout}.alive`);
|
|
765
|
+
if (state?.val) {
|
|
766
|
+
return this.sendToAsync(`nightscout.${this.config.nightscout}`, 'send', request);
|
|
767
|
+
}
|
|
768
|
+
return { error: `nightscout.${this.config.nightscout} is offline` };
|
|
769
|
+
}
|
|
770
|
+
return { error: 'Service is disabled' };
|
|
771
|
+
}
|
|
772
|
+
else if (type.startsWith('alexa')) {
|
|
773
|
+
if (typeof request === 'string') {
|
|
774
|
+
try {
|
|
775
|
+
request = JSON.parse(request);
|
|
776
|
+
}
|
|
777
|
+
catch {
|
|
778
|
+
this.log.error(`Cannot parse request: ${JSON.stringify(request)}`);
|
|
779
|
+
return { error: 'Cannot parse request' };
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
this.log.debug(`${Date.now()} ALEXA: ${JSON.stringify(request)}`);
|
|
783
|
+
if (request?.directive) {
|
|
784
|
+
if (this.alexaSH3) {
|
|
785
|
+
try {
|
|
786
|
+
const response = await this.alexaSH3.process(request);
|
|
787
|
+
if (request.directive.header.messageId != response.event.header.messageId) {
|
|
788
|
+
throw new Error('Incoming and outgoing header message IDs are not equal!');
|
|
789
|
+
}
|
|
790
|
+
return response;
|
|
791
|
+
}
|
|
792
|
+
catch {
|
|
793
|
+
this.log.error(`Cannot parse request: ${request}`);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return { error: 'Service is disabled' };
|
|
797
|
+
}
|
|
798
|
+
else if (request?.error) {
|
|
799
|
+
// answer from alexa3 events cloud actually just show it in log
|
|
800
|
+
if (request.error.includes('You have no iobroker.iot license')) {
|
|
801
|
+
// pause for 30 minutes send of the events
|
|
802
|
+
this.alexaSH3?.pauseEvents();
|
|
803
|
+
}
|
|
804
|
+
this.log.error(`Error from Alexa events cloud: ${request.error}`);
|
|
805
|
+
}
|
|
806
|
+
else if (request && !request.header) {
|
|
807
|
+
if (this.alexaCustom) {
|
|
808
|
+
return this.alexaCustom.process(request, this.config.amazonAlexa);
|
|
809
|
+
}
|
|
810
|
+
return { error: 'Service is disabled' };
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
if (this.alexaSH2) {
|
|
814
|
+
return this.alexaSH2.process(request, this.config.amazonAlexa);
|
|
815
|
+
}
|
|
816
|
+
return { error: 'Service is disabled' };
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
else if (type.startsWith('ifttt')) {
|
|
820
|
+
try {
|
|
821
|
+
if (typeof request === 'object') {
|
|
822
|
+
request = JSON.stringify(request);
|
|
823
|
+
}
|
|
824
|
+
else {
|
|
825
|
+
request = request.toString();
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
catch {
|
|
829
|
+
this.log.error(`Cannot parse request: ${request}`);
|
|
830
|
+
return { error: 'Cannot parse request' };
|
|
831
|
+
}
|
|
832
|
+
await this.processIfttt(request);
|
|
833
|
+
return NONE;
|
|
834
|
+
}
|
|
835
|
+
else if (type.startsWith('ghome')) {
|
|
836
|
+
if (typeof request === 'string') {
|
|
837
|
+
try {
|
|
838
|
+
request = JSON.parse(request);
|
|
839
|
+
}
|
|
840
|
+
catch {
|
|
841
|
+
this.log.error(`Cannot parse request: ${request}`);
|
|
842
|
+
return { error: 'Cannot parse request' };
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
if (this.googleHome) {
|
|
846
|
+
return this.googleHome.process(request, this.config.googleHome);
|
|
847
|
+
}
|
|
848
|
+
return { error: 'Service is disabled' };
|
|
849
|
+
}
|
|
850
|
+
else if (type.startsWith('alisa')) {
|
|
851
|
+
if (typeof request === 'string') {
|
|
852
|
+
try {
|
|
853
|
+
request = JSON.parse(request);
|
|
854
|
+
}
|
|
855
|
+
catch {
|
|
856
|
+
this.log.error(`Cannot parse request: ${request}`);
|
|
857
|
+
return { error: 'Cannot parse request' };
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
this.log.debug(`${Date.now()} ALISA: ${JSON.stringify(request)}`);
|
|
861
|
+
if (this.yandexAlisa) {
|
|
862
|
+
return this.yandexAlisa.process(request, this.config.yandexAlisa);
|
|
863
|
+
}
|
|
864
|
+
return { error: 'Service is disabled' };
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
let isCustom = false;
|
|
868
|
+
let _type = type;
|
|
869
|
+
if (_type.match(/^custom_/)) {
|
|
870
|
+
_type = _type.substring(7);
|
|
871
|
+
isCustom = true;
|
|
872
|
+
}
|
|
873
|
+
if (_type === 'visu') {
|
|
874
|
+
this.log.debug(`Received visu command: ${JSON.stringify(request)}`);
|
|
875
|
+
if (typeof request === 'object') {
|
|
876
|
+
request = JSON.stringify(request);
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
request = request.toString();
|
|
880
|
+
}
|
|
881
|
+
try {
|
|
882
|
+
const visuData = JSON.parse(request);
|
|
883
|
+
if (visuData.presence) {
|
|
884
|
+
await (0, visuApp_1.handleGeofenceData)(visuData, this);
|
|
885
|
+
}
|
|
886
|
+
if (visuData.devices) {
|
|
887
|
+
await (0, visuApp_1.handleDevicesData)(visuData, this);
|
|
888
|
+
}
|
|
889
|
+
if (visuData.command === 'getInstances') {
|
|
890
|
+
const res = await (0, visuApp_1.handleGetInstances)(visuData, this);
|
|
891
|
+
return { result: 'Ok', ...res };
|
|
892
|
+
}
|
|
893
|
+
if (visuData.command === 'sendToAdapter') {
|
|
894
|
+
return await (0, visuApp_1.handleSendToAdapter)(visuData, this);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
catch (e) {
|
|
898
|
+
this.log.error(`Could not handle data "${request}" by Visu App: ${e.message}`);
|
|
899
|
+
return { error: e.message };
|
|
900
|
+
}
|
|
901
|
+
return { result: 'Ok' };
|
|
902
|
+
}
|
|
903
|
+
else if (this.config.allowedServices[0] === '*' ||
|
|
904
|
+
this.config.allowedServices.includes(_type) ||
|
|
905
|
+
ALLOWED_SERVICES.includes(_type)) {
|
|
906
|
+
if (typeof request === 'object') {
|
|
907
|
+
request = JSON.stringify(request);
|
|
908
|
+
}
|
|
909
|
+
else {
|
|
910
|
+
request = request.toString();
|
|
911
|
+
}
|
|
912
|
+
if (SPECIAL_ADAPTERS.includes(_type)) {
|
|
913
|
+
try {
|
|
914
|
+
await this.setStateAsync(`services.${_type}`, request, true);
|
|
915
|
+
}
|
|
916
|
+
catch (err) {
|
|
917
|
+
return { result: err };
|
|
918
|
+
}
|
|
919
|
+
return { result: 'Ok' };
|
|
920
|
+
}
|
|
921
|
+
else if (type.startsWith('text2command')) {
|
|
922
|
+
if (this.config.text2command !== undefined && this.config.text2command !== '') {
|
|
923
|
+
try {
|
|
924
|
+
await this.setForeignStateAsync(`text2command.${this.config.text2command}.text`, request);
|
|
925
|
+
}
|
|
926
|
+
catch (err) {
|
|
927
|
+
return { result: err };
|
|
928
|
+
}
|
|
929
|
+
return { result: 'Ok' };
|
|
930
|
+
}
|
|
931
|
+
this.log.warn('Received service text2command, but instance is not defined');
|
|
932
|
+
return { result: 'but instance is not defined' };
|
|
933
|
+
}
|
|
934
|
+
else if (type.startsWith('simpleApi')) {
|
|
935
|
+
return { result: 'not implemented' };
|
|
936
|
+
}
|
|
937
|
+
else if (isCustom) {
|
|
938
|
+
let obj;
|
|
939
|
+
try {
|
|
940
|
+
obj = await this.getObjectAsync(`services.custom_${_type}`);
|
|
941
|
+
}
|
|
942
|
+
catch (e) {
|
|
943
|
+
this.log.error(`Cannot get object services.custom_${_type}: ${e}`);
|
|
944
|
+
}
|
|
945
|
+
if (!obj) {
|
|
946
|
+
try {
|
|
947
|
+
await this.setObjectNotExistsAsync(`services.custom_${_type}`, {
|
|
948
|
+
_id: `${this.namespace}.services.custom_${_type}`,
|
|
949
|
+
type: 'state',
|
|
950
|
+
common: {
|
|
951
|
+
name: `Service for ${_type}`,
|
|
952
|
+
write: false,
|
|
953
|
+
read: true,
|
|
954
|
+
type: 'mixed',
|
|
955
|
+
role: 'value',
|
|
956
|
+
},
|
|
957
|
+
native: {},
|
|
958
|
+
});
|
|
959
|
+
await this.setStateAsync(`services.custom_${_type}`, request, true);
|
|
960
|
+
}
|
|
961
|
+
catch (err) {
|
|
962
|
+
this.log.error(`Cannot control .services.custom_${_type}: ${JSON.stringify(err)}`);
|
|
963
|
+
return { error: err };
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
else {
|
|
967
|
+
await this.setStateAsync(`services.custom_${_type}`, request, true);
|
|
968
|
+
return { result: 'Ok' };
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
this.log.warn(`Received service "${type}", but it is not allowed`);
|
|
973
|
+
return { error: 'not allowed' };
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
this.log.warn(`Received service "${type}", but it is not found in whitelist`);
|
|
978
|
+
return { error: 'Unknown service' };
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
this.log.warn(`Received message of unknown type: ${type}`);
|
|
982
|
+
return { error: 'Unknown message type' };
|
|
983
|
+
}
|
|
984
|
+
closeDevice() {
|
|
985
|
+
return new Promise(resolve => {
|
|
986
|
+
if (this.device) {
|
|
987
|
+
try {
|
|
988
|
+
this.device.end(true, () => {
|
|
989
|
+
this.device = null;
|
|
990
|
+
resolve();
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
catch {
|
|
994
|
+
this.device = null;
|
|
995
|
+
resolve();
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
else {
|
|
999
|
+
resolve();
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
async startDevice(clientId, login, password, retry) {
|
|
1004
|
+
retry ||= 0;
|
|
1005
|
+
let certs;
|
|
1006
|
+
try {
|
|
1007
|
+
certs = await this.readCertificates();
|
|
1008
|
+
}
|
|
1009
|
+
catch (error) {
|
|
1010
|
+
if (error.message === 'Not exists') {
|
|
1011
|
+
try {
|
|
1012
|
+
certs = await this.fetchCertificates(login, password);
|
|
1013
|
+
}
|
|
1014
|
+
catch {
|
|
1015
|
+
// ignore
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
throw error;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
// destroy the old device
|
|
1023
|
+
await this.closeDevice();
|
|
1024
|
+
if (!certs) {
|
|
1025
|
+
return this.log.error(`Cannot read connection certificates`);
|
|
1026
|
+
}
|
|
1027
|
+
try {
|
|
1028
|
+
this.connectStarted = Date.now();
|
|
1029
|
+
this.device = new aws_iot_device_sdk_1.device({
|
|
1030
|
+
privateKey: Buffer.from(certs.private),
|
|
1031
|
+
clientCert: Buffer.from(certs.certificate),
|
|
1032
|
+
caCert: (0, node_fs_1.readFileSync)(`${__dirname}/../keys/root-CA.crt`),
|
|
1033
|
+
clientId,
|
|
1034
|
+
username: 'ioBroker',
|
|
1035
|
+
host: this.config.cloudUrl,
|
|
1036
|
+
debug: !!this.config.debug,
|
|
1037
|
+
baseReconnectTimeMs: 5000,
|
|
1038
|
+
keepalive: 60,
|
|
1039
|
+
});
|
|
1040
|
+
this.remote?.registerDevice(this.device);
|
|
1041
|
+
this.device.subscribe(`command/${clientId}/#`);
|
|
1042
|
+
this.device.on('connect', () => this.onConnect(clientId));
|
|
1043
|
+
this.device.on('close', () => this.onDisconnect());
|
|
1044
|
+
this.device.on('reconnect', () => this.log.debug('reconnect'));
|
|
1045
|
+
this.device.on('offline', () => this.log.debug('offline'));
|
|
1046
|
+
this.device.on('error', error => {
|
|
1047
|
+
const errorTxt = (error?.message && JSON.stringify(error.message)) || JSON.stringify(error);
|
|
1048
|
+
this.log.error(`Error by device connection: ${errorTxt}`);
|
|
1049
|
+
// restart the iot device if DNS cannot be resolved
|
|
1050
|
+
if (errorTxt.includes('EAI_AGAIN')) {
|
|
1051
|
+
this.log.error(`DNS name of ${this.config.cloudUrl} cannot be resolved: connection will be retried in 10 seconds.`);
|
|
1052
|
+
setTimeout(() => this.startDevice(clientId, login, password), 10000);
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
this.device.on('message', async (topic, request) => {
|
|
1056
|
+
this.log.debug(`Request ${topic}`);
|
|
1057
|
+
if (topic.startsWith(`command/${clientId}/`)) {
|
|
1058
|
+
const type = topic.substring(clientId.length + 9); // 9 === 'command//'.length
|
|
1059
|
+
try {
|
|
1060
|
+
const response = await this.processMessage(type, request);
|
|
1061
|
+
if (this.common.loglevel === 'debug' && !type.startsWith('remote')) {
|
|
1062
|
+
this.log.debug(`Response: ${JSON.stringify(response)}`);
|
|
1063
|
+
}
|
|
1064
|
+
if (this.device && response !== NONE) {
|
|
1065
|
+
// It is a big file - send in trunks
|
|
1066
|
+
if (Array.isArray(response)) {
|
|
1067
|
+
try {
|
|
1068
|
+
for (let m = 0; m < response.length; m++) {
|
|
1069
|
+
const trunk = response[m];
|
|
1070
|
+
await new Promise((resolve, reject) => this.device.publish(`response/${clientId}/${type}`, typeof trunk !== 'string' ? JSON.stringify(trunk) : trunk, { qos: 1 }, error => {
|
|
1071
|
+
if (error) {
|
|
1072
|
+
reject(error);
|
|
1073
|
+
}
|
|
1074
|
+
else {
|
|
1075
|
+
resolve();
|
|
1076
|
+
}
|
|
1077
|
+
}));
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
catch (err) {
|
|
1081
|
+
this.log.error(`[REMOTE] Cannot send packet: ${err}`);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
else {
|
|
1085
|
+
this.log.debug(`[REMOTE] Send response to 'response/${clientId}/${type}: ${JSON.stringify(response)}`);
|
|
1086
|
+
const msg = JSON.stringify(response);
|
|
1087
|
+
if (msg && msg.length > MAX_IOT_MESSAGE_LENGTH) {
|
|
1088
|
+
const packed = (0, node_zlib_1.deflateSync)(msg).toString('base64');
|
|
1089
|
+
this.log.debug(`[REMOTE] Content was packed from ${msg.length} bytes to ${packed.length} bytes`);
|
|
1090
|
+
if (packed.length > MAX_IOT_MESSAGE_LENGTH) {
|
|
1091
|
+
this.log.warn(`[REMOTE] Content was packed to ${packed.length} bytes which is still near/over the message limit!`);
|
|
1092
|
+
}
|
|
1093
|
+
this.device.publish(`response/${clientId}/${type}`, packed);
|
|
1094
|
+
}
|
|
1095
|
+
else {
|
|
1096
|
+
// console.log(`Publish to "response/${clientId}/${type}": ${msg}`);
|
|
1097
|
+
this.device.publish(`response/${clientId}/${type}`, msg);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
catch (error) {
|
|
1103
|
+
this.log.debug(`Error processing request ${topic}`);
|
|
1104
|
+
this.log.debug(`${error}`);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
catch (error) {
|
|
1110
|
+
if (error && typeof error === 'object' && error.message) {
|
|
1111
|
+
this.log.error(`Cannot read connection certificates: ${error.message}`);
|
|
1112
|
+
}
|
|
1113
|
+
else {
|
|
1114
|
+
this.log.error(`Cannot read connection certificates: ${JSON.stringify(error)} / ${error && error.toString()}`);
|
|
1115
|
+
}
|
|
1116
|
+
if ((error === 'timeout' || error.message?.includes('timeout')) && retry < 10) {
|
|
1117
|
+
setTimeout(() => this.startDevice(clientId, login, password, retry + 1), 10000);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
async updateNightscoutSecret() {
|
|
1122
|
+
if (!this.config.nightscout) {
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
const email = this.config.login.replace(/[^\w\d-_]/g, '_');
|
|
1126
|
+
const secret = this.config.nightscoutPass;
|
|
1127
|
+
const apiSecret = email + (secret ? `-${secret}` : '');
|
|
1128
|
+
const URL = `https://generate-key.iobroker.in/v1/generateUrlKey?user=${encodeURIComponent(this.config.login)}&pass=${encodeURIComponent(this.config.pass)}&apisecret=${encodeURIComponent(apiSecret)}`;
|
|
1129
|
+
let response;
|
|
1130
|
+
try {
|
|
1131
|
+
response = await axios_1.default.get(URL, {
|
|
1132
|
+
timeout: 15000,
|
|
1133
|
+
validateStatus: status => status < 400,
|
|
1134
|
+
});
|
|
1135
|
+
if (response.data.error) {
|
|
1136
|
+
this.log.error(`Api-Secret cannot be updated: ${response.data.error}`);
|
|
1137
|
+
}
|
|
1138
|
+
else {
|
|
1139
|
+
this.log.debug(`Api-Secret updated: ${JSON.stringify(response.data)}`);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
catch (error) {
|
|
1143
|
+
if (error.response) {
|
|
1144
|
+
this.log.warn(`Cannot update api-secret: ${error.response.data ? JSON.stringify(error.response.data) : error.response.status}`);
|
|
1145
|
+
}
|
|
1146
|
+
else {
|
|
1147
|
+
this.log.warn(`Cannot update api-secret: ${error.code}`);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
async createStateForAdapter(adapterName) {
|
|
1152
|
+
// find any instance of this adapter
|
|
1153
|
+
const instances = await this.getObjectViewAsync('system', 'instance', {
|
|
1154
|
+
startkey: `system.adapter.${adapterName}.`,
|
|
1155
|
+
endkey: `system.adapter.${adapterName}.\u9999`,
|
|
1156
|
+
});
|
|
1157
|
+
if (instances?.rows?.length) {
|
|
1158
|
+
let obj;
|
|
1159
|
+
try {
|
|
1160
|
+
obj = await this.getObjectAsync(`service.${adapterName}`);
|
|
1161
|
+
}
|
|
1162
|
+
catch {
|
|
1163
|
+
// ignore
|
|
1164
|
+
}
|
|
1165
|
+
if (!obj) {
|
|
1166
|
+
try {
|
|
1167
|
+
await this.setForeignObjectAsync(`${this.namespace}.services.${adapterName}`, {
|
|
1168
|
+
type: 'state',
|
|
1169
|
+
common: {
|
|
1170
|
+
name: `Service for ${adapterName}`,
|
|
1171
|
+
write: false,
|
|
1172
|
+
read: true,
|
|
1173
|
+
type: 'mixed',
|
|
1174
|
+
role: 'value',
|
|
1175
|
+
},
|
|
1176
|
+
native: {},
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
catch {
|
|
1180
|
+
// ignore
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
else {
|
|
1185
|
+
try {
|
|
1186
|
+
// delete if object exists
|
|
1187
|
+
const obj = await this.getObjectAsync(`service.${adapterName}`);
|
|
1188
|
+
if (obj) {
|
|
1189
|
+
await this.delObjectAsync(`service.${adapterName}`);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
catch {
|
|
1193
|
+
// ignore
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
async main() {
|
|
1198
|
+
if (this.config.googleHome === undefined) {
|
|
1199
|
+
this.config.googleHome = false;
|
|
1200
|
+
}
|
|
1201
|
+
if (this.config.amazonAlexa === undefined) {
|
|
1202
|
+
this.config.amazonAlexa = true;
|
|
1203
|
+
}
|
|
1204
|
+
if (this.config.yandexAlisa === undefined) {
|
|
1205
|
+
this.config.yandexAlisa = false;
|
|
1206
|
+
}
|
|
1207
|
+
this.config.pingTimeout = parseInt(this.config.pingTimeout, 10) || 5000;
|
|
1208
|
+
if (this.config.pingTimeout < 3000) {
|
|
1209
|
+
this.config.pingTimeout = 3000;
|
|
1210
|
+
}
|
|
1211
|
+
if (this.config.deviceOffLevel === undefined) {
|
|
1212
|
+
this.config.deviceOffLevel = 30;
|
|
1213
|
+
}
|
|
1214
|
+
if (this.config.login !== (this.config.login || '').trim().toLowerCase()) {
|
|
1215
|
+
this.log.error('Please write your login only in lowercase!');
|
|
1216
|
+
}
|
|
1217
|
+
if (!this.config.login || !this.config.pass) {
|
|
1218
|
+
return this.log.error('No cloud credentials found. Please get one on https://iobroker.pro');
|
|
1219
|
+
}
|
|
1220
|
+
let systemConfig = await this.getForeignObjectAsync('system.config');
|
|
1221
|
+
if (!systemConfig) {
|
|
1222
|
+
this.log.warn('Object system.config not found. Please check your installation!');
|
|
1223
|
+
systemConfig = { common: {} };
|
|
1224
|
+
}
|
|
1225
|
+
// create service state for netatmo if any instance exists
|
|
1226
|
+
for (let a = 0; a < SPECIAL_ADAPTERS.length; a++) {
|
|
1227
|
+
await this.createStateForAdapter(SPECIAL_ADAPTERS[a]);
|
|
1228
|
+
}
|
|
1229
|
+
this.secret = systemConfig?.native?.secret || 'Zgfr56gFe87jJOM';
|
|
1230
|
+
this.config.pass = this.decryptOwn(this.secret, this.config.pass);
|
|
1231
|
+
this.config.deviceOffLevel = parseFloat(this.config.deviceOffLevel) || 0;
|
|
1232
|
+
this.config.concatWord = (this.config.concatWord || '').toString().trim();
|
|
1233
|
+
this.config.apikey = (this.config.apikey || '').trim();
|
|
1234
|
+
this.config.replaces = this.config.replaces ? this.config.replaces.split(',') : null;
|
|
1235
|
+
this.config.cloudUrl = (this.config.cloudUrl || '').toString();
|
|
1236
|
+
this.config.nightscout = this.config.nightscout || '';
|
|
1237
|
+
if (this.config.replaces) {
|
|
1238
|
+
const text = [];
|
|
1239
|
+
for (let r = 0; r < this.config.replaces.length; r++) {
|
|
1240
|
+
text.push(`"${this.config.replaces[r]}"`);
|
|
1241
|
+
}
|
|
1242
|
+
this.log.debug(`Following strings will be replaced in names: ${text.join(', ')}`);
|
|
1243
|
+
}
|
|
1244
|
+
if (this.config.amazonAlexa) {
|
|
1245
|
+
this.alexaSH2 = new alexaSmartHomeV2_1.default(this);
|
|
1246
|
+
this.alexaCustom = new alexaCustom_1.default(this);
|
|
1247
|
+
}
|
|
1248
|
+
if (this.config.yandexAlisa) {
|
|
1249
|
+
this.yandexAlisa = new alisa_1.default(this);
|
|
1250
|
+
}
|
|
1251
|
+
this.remote = new remote_1.default(this, this.config.login.replace(/[^-_:a-zA-Z1-9]/g, '_'));
|
|
1252
|
+
this.config.allowedServices = (this.config.allowedServices || '')
|
|
1253
|
+
.split(/[,\s]+/)
|
|
1254
|
+
.map(s => s.trim())
|
|
1255
|
+
.filter(s => s);
|
|
1256
|
+
await this.setStateAsync('info.connection', false, true);
|
|
1257
|
+
this.config.cloudUrl = this.config.cloudUrl || 'a18wym7vjdl22g.iot.eu-west-1.amazonaws.com';
|
|
1258
|
+
if (!this.config.login || !this.config.pass) {
|
|
1259
|
+
return this.log.error('No cloud credentials found. Please get one on https://iobroker.pro');
|
|
1260
|
+
}
|
|
1261
|
+
if (this.config.iftttKey) {
|
|
1262
|
+
await this.subscribeStatesAsync('services.ifttt');
|
|
1263
|
+
// create ifttt object
|
|
1264
|
+
const iftttObj = await this.getObjectAsync('.services.ifttt');
|
|
1265
|
+
if (!iftttObj) {
|
|
1266
|
+
await this.setObjectNotExistsAsync('services.ifttt', {
|
|
1267
|
+
_id: `${this.namespace}.services.ifttt`,
|
|
1268
|
+
type: 'state',
|
|
1269
|
+
common: {
|
|
1270
|
+
name: 'IFTTT value',
|
|
1271
|
+
write: true,
|
|
1272
|
+
role: 'state',
|
|
1273
|
+
read: true,
|
|
1274
|
+
type: 'mixed',
|
|
1275
|
+
desc: 'All written data will be sent to IFTTT. If no state specified all requests from IFTTT will be saved here',
|
|
1276
|
+
},
|
|
1277
|
+
native: {},
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
// detect netatmo creation
|
|
1282
|
+
await this.subscribeForeignObjectsAsync('system.adapter.*');
|
|
1283
|
+
await this.subscribeStatesAsync('smart.*');
|
|
1284
|
+
this.log.info(`Connecting with ${this.config.cloudUrl}`);
|
|
1285
|
+
if (this.config.language) {
|
|
1286
|
+
this.translate = true;
|
|
1287
|
+
this.lang = this.config.language;
|
|
1288
|
+
}
|
|
1289
|
+
else {
|
|
1290
|
+
this.lang = systemConfig.common.language;
|
|
1291
|
+
}
|
|
1292
|
+
if (this.lang !== 'en' && this.lang !== 'de' && this.lang !== 'ru') {
|
|
1293
|
+
this.lang = 'en';
|
|
1294
|
+
}
|
|
1295
|
+
if (this.alexaSH2) {
|
|
1296
|
+
this.alexaSH2.setLanguage(this.lang, this.translate);
|
|
1297
|
+
this.alexaSH2.updateDevices();
|
|
1298
|
+
}
|
|
1299
|
+
this.alexaCustom?.setLanguage(this.lang);
|
|
1300
|
+
this.remote?.setLanguage(this.lang);
|
|
1301
|
+
// check password
|
|
1302
|
+
if (this.config.pass.length < 8 ||
|
|
1303
|
+
!this.config.pass.match(/[a-z]/) ||
|
|
1304
|
+
!this.config.pass.match(/[A-Z]/) ||
|
|
1305
|
+
!this.config.pass.match(/\d/)) {
|
|
1306
|
+
return this.log.error('The password must be at least 8 characters long and have numbers, upper and lower case letters. Please change the password in the profile https://iobroker.pro/accountProfile.');
|
|
1307
|
+
}
|
|
1308
|
+
await this.updateNightscoutSecret();
|
|
1309
|
+
const iotClientId = this.config.login.replace(/[^-_:a-zA-Z1-9]/g, '_');
|
|
1310
|
+
// user will be created here
|
|
1311
|
+
await this.startDevice(iotClientId, this.config.login, this.config.pass);
|
|
1312
|
+
// after the user created, we can try to generate URL key
|
|
1313
|
+
// read URL keys from server
|
|
1314
|
+
try {
|
|
1315
|
+
this.urlKey = await this.readUrlKey();
|
|
1316
|
+
}
|
|
1317
|
+
catch {
|
|
1318
|
+
if (this.config.googleHome ||
|
|
1319
|
+
this.config.yandexAlisa ||
|
|
1320
|
+
this.config.allowedServices.length ||
|
|
1321
|
+
this.config.iftttKey) {
|
|
1322
|
+
try {
|
|
1323
|
+
this.urlKey = await this.createUrlKey(this.config.login, this.config.pass);
|
|
1324
|
+
}
|
|
1325
|
+
catch (err) {
|
|
1326
|
+
return this.log.error(`Cannot read URL key: ${typeof err === 'object' ? JSON.stringify(err) : err}`);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
if (this.config.amazonAlexaV3) {
|
|
1331
|
+
this.alexaSH3 = new alexaSmartHomeV3_1.default({
|
|
1332
|
+
adapter: this,
|
|
1333
|
+
iotClientId,
|
|
1334
|
+
iotDevice: this.device,
|
|
1335
|
+
});
|
|
1336
|
+
this.alexaSH3.setLanguage(this.lang);
|
|
1337
|
+
await this.alexaSH3.updateDevices();
|
|
1338
|
+
}
|
|
1339
|
+
if (this.config.googleHome) {
|
|
1340
|
+
this.googleHome = new googleHome_1.default(this, this.urlKey);
|
|
1341
|
+
} // no else
|
|
1342
|
+
if (this.config.yandexAlisa) {
|
|
1343
|
+
this.yandexAlisa = new alisa_1.default(this, this.urlKey);
|
|
1344
|
+
}
|
|
1345
|
+
this.googleHome?.setLanguage(this.lang);
|
|
1346
|
+
this.googleHome?.updateDevices();
|
|
1347
|
+
this.yandexAlisa?.setLanguage(this.lang);
|
|
1348
|
+
this.yandexAlisa?.updateDevices();
|
|
1349
|
+
await this.subscribeStatesAsync('app.message');
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
exports.IotAdapter = IotAdapter;
|
|
1353
|
+
if (require.main !== module) {
|
|
1354
|
+
// Export the constructor in compact mode
|
|
1355
|
+
module.exports = (options) => new IotAdapter(options);
|
|
1356
|
+
}
|
|
1357
|
+
else {
|
|
1358
|
+
// otherwise start the instance directly
|
|
1359
|
+
(() => new IotAdapter())();
|
|
1360
|
+
}
|
|
1361
|
+
//# sourceMappingURL=main.js.map
|