@homebridge-plugins/homebridge-tuya 2.2.1 → 3.0.0-beta.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.
- package/CHANGELOG.md +19 -0
- package/README.md +161 -144
- package/config.schema.json +976 -11
- package/dist/{core → cloud/api}/TuyaOpenAPI.js +6 -7
- package/dist/cloud/api/TuyaOpenAPI.js.map +1 -0
- package/dist/{core → cloud/api}/TuyaOpenMQ.js +13 -11
- package/dist/cloud/api/TuyaOpenMQ.js.map +1 -0
- package/dist/cloud/device/TuyaCustomDeviceManager.js.map +1 -0
- package/dist/{device → cloud/device}/TuyaDevice.js +14 -1
- package/dist/cloud/device/TuyaDevice.js.map +1 -0
- package/dist/{device → cloud/device}/TuyaDeviceManager.js +8 -3
- package/dist/cloud/device/TuyaDeviceManager.js.map +1 -0
- package/dist/cloud/device/TuyaHomeDeviceManager.js.map +1 -0
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/local/CloudLocalReconciliation.js +180 -0
- package/dist/local/CloudLocalReconciliation.js.map +1 -0
- package/dist/local/DynamicChildDiscovery.js +154 -0
- package/dist/local/DynamicChildDiscovery.js.map +1 -0
- package/dist/local/LocalDevice.js +419 -0
- package/dist/local/LocalDevice.js.map +1 -0
- package/dist/local/LocalDeviceManager.js +833 -0
- package/dist/local/LocalDeviceManager.js.map +1 -0
- package/dist/local/TuyaDiscovery.js +248 -0
- package/dist/local/TuyaDiscovery.js.map +1 -0
- package/dist/local/ZigbeeEventDetection.js +213 -0
- package/dist/local/ZigbeeEventDetection.js.map +1 -0
- package/dist/local/ZigbeeGatewayDetection.js +109 -0
- package/dist/local/ZigbeeGatewayDetection.js.map +1 -0
- package/dist/local/config.js +6 -0
- package/dist/local/config.js.map +1 -0
- package/dist/local/protocol/ChildPayloadUtility.js +94 -0
- package/dist/local/protocol/ChildPayloadUtility.js.map +1 -0
- package/dist/local/protocol/Protocol.js +3 -0
- package/dist/local/protocol/Protocol.js.map +1 -0
- package/dist/local/protocol/ProtocolFactory.js +27 -0
- package/dist/local/protocol/ProtocolFactory.js.map +1 -0
- package/dist/local/protocol/ProtocolUtilities.js +329 -0
- package/dist/local/protocol/ProtocolUtilities.js.map +1 -0
- package/dist/local/protocol/ProtocolV31V32.js +60 -0
- package/dist/local/protocol/ProtocolV31V32.js.map +1 -0
- package/dist/local/protocol/ProtocolV33.js +52 -0
- package/dist/local/protocol/ProtocolV33.js.map +1 -0
- package/dist/local/protocol/ProtocolV34.js +104 -0
- package/dist/local/protocol/ProtocolV34.js.map +1 -0
- package/dist/local/protocol/ProtocolV35.js +77 -0
- package/dist/local/protocol/ProtocolV35.js.map +1 -0
- package/dist/platform.js +149 -69
- package/dist/platform.js.map +1 -1
- package/dist/shared/AccessoryFactory.js +276 -0
- package/dist/shared/AccessoryFactory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/AccessoryFactory.js +2 -2
- package/dist/shared/accessories/AccessoryFactory.js.map +1 -0
- package/dist/shared/accessories/AirConditionerAccessory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/AirPurifierAccessory.js +1 -1
- package/dist/shared/accessories/AirPurifierAccessory.js.map +1 -0
- package/dist/shared/accessories/AirQualitySensorAccessory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/BaseAccessory.js +99 -30
- package/dist/shared/accessories/BaseAccessory.js.map +1 -0
- package/dist/shared/accessories/BlindsAccessory.js +199 -0
- package/dist/shared/accessories/BlindsAccessory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/CameraAccessory.js +7 -3
- package/dist/shared/accessories/CameraAccessory.js.map +1 -0
- package/dist/shared/accessories/CarbonDioxideSensorAccessory.js.map +1 -0
- package/dist/shared/accessories/CarbonMonoxideSensorAccessory.js.map +1 -0
- package/dist/shared/accessories/ContactSensorAccessory.js.map +1 -0
- package/dist/shared/accessories/DehumidifierAccessory.js.map +1 -0
- package/dist/shared/accessories/DiffuserAccessory.js.map +1 -0
- package/dist/shared/accessories/DimmerAccessory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/DoorbellAccessory.js +3 -1
- package/dist/shared/accessories/DoorbellAccessory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/ExtractionHoodAccessory.js +4 -2
- package/dist/shared/accessories/ExtractionHoodAccessory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/FanAccessory.js +10 -4
- package/dist/shared/accessories/FanAccessory.js.map +1 -0
- package/dist/shared/accessories/GarageDoorAccessory.js.map +1 -0
- package/dist/shared/accessories/HeaterAccessory.js.map +1 -0
- package/dist/shared/accessories/HeaterAccessory_old.js.map +1 -0
- package/dist/shared/accessories/HumanPresenceSensorAccessory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/HumidifierAccessory.js +3 -1
- package/dist/shared/accessories/HumidifierAccessory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/IRAirConditionerAccessory.js +2 -2
- package/dist/shared/accessories/IRAirConditionerAccessory.js.map +1 -0
- package/dist/shared/accessories/IRControlHubAccessory.js.map +1 -0
- package/dist/shared/accessories/IRControlHubSubAccessory.js.map +1 -0
- package/dist/shared/accessories/IRGenericAccessory.js.map +1 -0
- package/dist/shared/accessories/LeakSensorAccessory.js.map +1 -0
- package/dist/shared/accessories/LightAccessory.js.map +1 -0
- package/dist/shared/accessories/LightSensorAccessory.js.map +1 -0
- package/dist/shared/accessories/LocationWeatherAccessory.js.map +1 -0
- package/dist/shared/accessories/LockAccessory.js.map +1 -0
- package/dist/shared/accessories/MotionSensorAccessory.js.map +1 -0
- package/dist/shared/accessories/OutletAccessory.js.map +1 -0
- package/dist/shared/accessories/PetFeederAccessory.js.map +1 -0
- package/dist/shared/accessories/SceneAccessory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/SceneSwitchAccessory.js +1 -1
- package/dist/shared/accessories/SceneSwitchAccessory.js.map +1 -0
- package/dist/shared/accessories/SecuritySystemAccessory.js.map +1 -0
- package/dist/shared/accessories/SmokeSensorAccessory.js.map +1 -0
- package/dist/shared/accessories/SwitchAccessory.js +148 -0
- package/dist/shared/accessories/SwitchAccessory.js.map +1 -0
- package/dist/shared/accessories/TemperatureHumiditySensorAccessory.js.map +1 -0
- package/dist/shared/accessories/ThermostatAccessory.js.map +1 -0
- package/dist/shared/accessories/TowerRackAccessory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/ValveAccessory.js +1 -1
- package/dist/shared/accessories/ValveAccessory.js.map +1 -0
- package/dist/{accessory → shared/accessories}/VibrationSensorAccessory.js +7 -3
- package/dist/shared/accessories/VibrationSensorAccessory.js.map +1 -0
- package/dist/shared/accessories/WeatherStationAccessory.js.map +1 -0
- package/dist/shared/accessories/WetBulbGlobeTemperatureAccessory.js.map +1 -0
- package/dist/shared/accessories/WhiteNoiseLightAccessory.js.map +1 -0
- package/dist/shared/accessories/WindowAccessory.js.map +1 -0
- package/dist/shared/accessories/WindowCoveringAccessory.js.map +1 -0
- package/dist/shared/accessories/WirelessSwitchAccessory.js.map +1 -0
- package/dist/shared/accessories/characteristic/Active.js.map +1 -0
- package/dist/{accessory → shared/accessories}/characteristic/AirQuality.js +1 -1
- package/dist/shared/accessories/characteristic/AirQuality.js.map +1 -0
- package/dist/shared/accessories/characteristic/CurrentRelativeHumidity.js.map +1 -0
- package/dist/shared/accessories/characteristic/CurrentTemperature.js.map +1 -0
- package/dist/shared/accessories/characteristic/CurrentWeather.js.map +1 -0
- package/dist/shared/accessories/characteristic/CurrentWeatherByOpenMeteo.js.map +1 -0
- package/dist/shared/accessories/characteristic/CurrentWetBulbGlobeTemperature.js.map +1 -0
- package/dist/shared/accessories/characteristic/EnergyUsage.js.map +1 -0
- package/dist/shared/accessories/characteristic/Light.js.map +1 -0
- package/dist/shared/accessories/characteristic/LightSensor.js.map +1 -0
- package/dist/shared/accessories/characteristic/LockPhysicalControls.js.map +1 -0
- package/dist/{accessory → shared/accessories}/characteristic/MotionDetected.js +1 -1
- package/dist/shared/accessories/characteristic/MotionDetected.js.map +1 -0
- package/dist/shared/accessories/characteristic/Name.js.map +1 -0
- package/dist/shared/accessories/characteristic/OccupancyDetected.js.map +1 -0
- package/dist/{accessory → shared/accessories}/characteristic/On.js +1 -1
- package/dist/shared/accessories/characteristic/On.js.map +1 -0
- package/dist/shared/accessories/characteristic/OutletInUse.js.map +1 -0
- package/dist/{accessory → shared/accessories}/characteristic/ProgrammableSwitchEvent.js +2 -2
- package/dist/shared/accessories/characteristic/ProgrammableSwitchEvent.js.map +1 -0
- package/dist/shared/accessories/characteristic/RelativeHumidityDehumidifierThreshold.js.map +1 -0
- package/dist/shared/accessories/characteristic/RotationSpeed.js.map +1 -0
- package/dist/shared/accessories/characteristic/SecuritySystemState.js.map +1 -0
- package/dist/shared/accessories/characteristic/SwingMode.js.map +1 -0
- package/dist/shared/accessories/characteristic/TargetTemperature.js.map +1 -0
- package/dist/shared/accessories/characteristic/TemperatureDisplayUnits.js.map +1 -0
- package/dist/shared/util/ConfigHash.js +79 -0
- package/dist/shared/util/ConfigHash.js.map +1 -0
- package/dist/shared/util/FfmpegStreamingProcess.js.map +1 -0
- package/dist/shared/util/InfraredTool.js.map +1 -0
- package/dist/shared/util/Logger.js.map +1 -0
- package/dist/shared/util/TuyaRecordingDelegate.js.map +1 -0
- package/dist/shared/util/TuyaStreamDelegate.js.map +1 -0
- package/dist/shared/util/color.js.map +1 -0
- package/dist/shared/util/util.js +135 -0
- package/dist/shared/util/util.js.map +1 -0
- package/eslint.config.mjs +52 -0
- package/jest.config.js +6 -0
- package/package.json +22 -27
- package/test/__mocks__/@homebridge-camera-utils.js +10 -0
- package/test/__mocks__/color-convert.js +24 -0
- package/test/__mocks__/kelvin-to-rgb.js +21 -0
- package/test/accessoryFactory.test.ts +522 -0
- package/test/config.test.ts +430 -0
- package/test/custom.test.ts +4 -4
- package/test/errorHandling.test.ts +570 -0
- package/test/errorHandlingCoverage.test.ts +410 -0
- package/test/home.test.ts +4 -4
- package/test/localDevice.test.ts +616 -0
- package/test/localDeviceManager.behavior.test.ts +185 -0
- package/test/localDeviceManager.test.ts +268 -0
- package/test/mqttMessages.test.ts +495 -0
- package/test/platform.test.ts +515 -0
- package/test/platform.validation.local.test.ts +250 -0
- package/test/protocol.test.ts +446 -0
- package/test/protocolUtilities.test.ts +351 -0
- package/test/sanitizeName.test.ts +2 -1
- package/test/tuyaCustomDeviceManager.test.ts +469 -0
- package/test/tuyaDevice.test.ts +425 -0
- package/test/tuyaDeviceManager.test.ts +813 -0
- package/test/tuyaDiscovery.test.ts +439 -0
- package/test/tuyaHomeDeviceManager.test.ts +540 -0
- package/test/tuyaOpenAPI.test.ts +404 -0
- package/test/tuyaOpenMQ.test.ts +444 -0
- package/test/util.test.ts +318 -0
- package/test/util.ts +4 -3
- package/test/zigbee/ChildPayloadUtility.test.ts +199 -0
- package/test/zigbee/CloudLocalReconciliation.test.ts +284 -0
- package/test/zigbee/DynamicChildDiscovery.test.ts +333 -0
- package/test/zigbee/LocalDevice.zigbee.test.ts +274 -0
- package/test/zigbee/LocalDeviceManager.cloud-discovery.test.ts +163 -0
- package/test/zigbee/LocalDeviceManager.zigbee.reconnect.test.ts +200 -0
- package/test/zigbee/LocalDeviceManager.zigbee.test.ts +344 -0
- package/test/zigbee/ZigbeeEventDetection.test.ts +418 -0
- package/test/zigbee/ZigbeeGatewayDetection.test.ts +222 -0
- package/tuya-local-configs/dev-1.hash +1 -0
- package/tuya-local-configs/device1.hash +1 -0
- package/wiki/Get-Local-Keys-for-Your-Devices.md +85 -0
- package/dist/accessory/AccessoryFactory.js.map +0 -1
- package/dist/accessory/AirConditionerAccessory.js.map +0 -1
- package/dist/accessory/AirPurifierAccessory.js.map +0 -1
- package/dist/accessory/AirQualitySensorAccessory.js.map +0 -1
- package/dist/accessory/BaseAccessory.js.map +0 -1
- package/dist/accessory/CameraAccessory.js.map +0 -1
- package/dist/accessory/CarbonDioxideSensorAccessory.js.map +0 -1
- package/dist/accessory/CarbonMonoxideSensorAccessory.js.map +0 -1
- package/dist/accessory/ContactSensorAccessory.js.map +0 -1
- package/dist/accessory/DehumidifierAccessory.js.map +0 -1
- package/dist/accessory/DiffuserAccessory.js.map +0 -1
- package/dist/accessory/DimmerAccessory.js.map +0 -1
- package/dist/accessory/DoorbellAccessory.js.map +0 -1
- package/dist/accessory/ExtractionHoodAccessory.js.map +0 -1
- package/dist/accessory/FanAccessory.js.map +0 -1
- package/dist/accessory/GarageDoorAccessory.js.map +0 -1
- package/dist/accessory/HeaterAccessory.js.map +0 -1
- package/dist/accessory/HeaterAccessory_old.js.map +0 -1
- package/dist/accessory/HumanPresenceSensorAccessory.js.map +0 -1
- package/dist/accessory/HumidifierAccessory.js.map +0 -1
- package/dist/accessory/IRAirConditionerAccessory.js.map +0 -1
- package/dist/accessory/IRControlHubAccessory.js.map +0 -1
- package/dist/accessory/IRControlHubSubAccessory.js.map +0 -1
- package/dist/accessory/IRGenericAccessory.js.map +0 -1
- package/dist/accessory/LeakSensorAccessory.js.map +0 -1
- package/dist/accessory/LightAccessory.js.map +0 -1
- package/dist/accessory/LightSensorAccessory.js.map +0 -1
- package/dist/accessory/LocationWeatherAccessory.js.map +0 -1
- package/dist/accessory/LockAccessory.js.map +0 -1
- package/dist/accessory/MotionSensorAccessory.js.map +0 -1
- package/dist/accessory/OutletAccessory.js.map +0 -1
- package/dist/accessory/PetFeederAccessory.js.map +0 -1
- package/dist/accessory/SceneAccessory.js.map +0 -1
- package/dist/accessory/SceneSwitchAccessory.js.map +0 -1
- package/dist/accessory/SecuritySystemAccessory.js.map +0 -1
- package/dist/accessory/SmokeSensorAccessory.js.map +0 -1
- package/dist/accessory/SwitchAccessory.js +0 -85
- package/dist/accessory/SwitchAccessory.js.map +0 -1
- package/dist/accessory/TemperatureHumiditySensorAccessory.js.map +0 -1
- package/dist/accessory/ThermostatAccessory.js.map +0 -1
- package/dist/accessory/TowerRackAccessory.js.map +0 -1
- package/dist/accessory/ValveAccessory.js.map +0 -1
- package/dist/accessory/VibrationSensorAccessory.js.map +0 -1
- package/dist/accessory/WeatherStationAccessory.js.map +0 -1
- package/dist/accessory/WetBulbGlobeTemperatureAccessory.js.map +0 -1
- package/dist/accessory/WhiteNoiseLightAccessory.js.map +0 -1
- package/dist/accessory/WindowAccessory.js.map +0 -1
- package/dist/accessory/WindowCoveringAccessory.js.map +0 -1
- package/dist/accessory/WirelessSwitchAccessory.js.map +0 -1
- package/dist/accessory/characteristic/Active.js.map +0 -1
- package/dist/accessory/characteristic/AirQuality.js.map +0 -1
- package/dist/accessory/characteristic/CurrentRelativeHumidity.js.map +0 -1
- package/dist/accessory/characteristic/CurrentTemperature.js.map +0 -1
- package/dist/accessory/characteristic/CurrentWeather.js.map +0 -1
- package/dist/accessory/characteristic/CurrentWeatherByOpenMeteo.js.map +0 -1
- package/dist/accessory/characteristic/CurrentWetBulbGlobeTemperature.js.map +0 -1
- package/dist/accessory/characteristic/EnergyUsage.js.map +0 -1
- package/dist/accessory/characteristic/Light.js.map +0 -1
- package/dist/accessory/characteristic/LightSensor.js.map +0 -1
- package/dist/accessory/characteristic/LockPhysicalControls.js.map +0 -1
- package/dist/accessory/characteristic/MotionDetected.js.map +0 -1
- package/dist/accessory/characteristic/Name.js.map +0 -1
- package/dist/accessory/characteristic/OccupancyDetected.js.map +0 -1
- package/dist/accessory/characteristic/On.js.map +0 -1
- package/dist/accessory/characteristic/OutletInUse.js.map +0 -1
- package/dist/accessory/characteristic/ProgrammableSwitchEvent.js.map +0 -1
- package/dist/accessory/characteristic/RelativeHumidityDehumidifierThreshold.js.map +0 -1
- package/dist/accessory/characteristic/RotationSpeed.js.map +0 -1
- package/dist/accessory/characteristic/SecuritySystemState.js.map +0 -1
- package/dist/accessory/characteristic/SwingMode.js.map +0 -1
- package/dist/accessory/characteristic/TargetTemperature.js.map +0 -1
- package/dist/accessory/characteristic/TemperatureDisplayUnits.js.map +0 -1
- package/dist/core/TuyaOpenAPI.js.map +0 -1
- package/dist/core/TuyaOpenMQ.js.map +0 -1
- package/dist/device/TuyaCustomDeviceManager.js.map +0 -1
- package/dist/device/TuyaDevice.js.map +0 -1
- package/dist/device/TuyaDeviceManager.js.map +0 -1
- package/dist/device/TuyaHomeDeviceManager.js.map +0 -1
- package/dist/util/FfmpegStreamingProcess.js.map +0 -1
- package/dist/util/InfraredTool.js.map +0 -1
- package/dist/util/Logger.js.map +0 -1
- package/dist/util/TuyaRecordingDelegate.js.map +0 -1
- package/dist/util/TuyaStreamDelegate.js.map +0 -1
- package/dist/util/color.js.map +0 -1
- package/dist/util/util.js +0 -63
- package/dist/util/util.js.map +0 -1
- /package/dist/{device → cloud/device}/TuyaCustomDeviceManager.js +0 -0
- /package/dist/{device → cloud/device}/TuyaHomeDeviceManager.js +0 -0
- /package/dist/{accessory → shared/accessories}/AirConditionerAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/AirQualitySensorAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/CarbonDioxideSensorAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/CarbonMonoxideSensorAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/ContactSensorAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/DehumidifierAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/DiffuserAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/DimmerAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/GarageDoorAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/HeaterAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/HeaterAccessory_old.js +0 -0
- /package/dist/{accessory → shared/accessories}/HumanPresenceSensorAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/IRControlHubAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/IRControlHubSubAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/IRGenericAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/LeakSensorAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/LightAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/LightSensorAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/LocationWeatherAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/LockAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/MotionSensorAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/OutletAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/PetFeederAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/SceneAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/SecuritySystemAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/SmokeSensorAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/TemperatureHumiditySensorAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/ThermostatAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/TowerRackAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/WeatherStationAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/WetBulbGlobeTemperatureAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/WhiteNoiseLightAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/WindowAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/WindowCoveringAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/WirelessSwitchAccessory.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/Active.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/CurrentRelativeHumidity.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/CurrentTemperature.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/CurrentWeather.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/CurrentWeatherByOpenMeteo.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/CurrentWetBulbGlobeTemperature.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/EnergyUsage.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/Light.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/LightSensor.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/LockPhysicalControls.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/Name.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/OccupancyDetected.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/OutletInUse.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/RelativeHumidityDehumidifierThreshold.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/RotationSpeed.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/SecuritySystemState.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/SwingMode.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/TargetTemperature.js +0 -0
- /package/dist/{accessory → shared/accessories}/characteristic/TemperatureDisplayUnits.js +0 -0
- /package/dist/{util → shared/util}/FfmpegStreamingProcess.js +0 -0
- /package/dist/{util → shared/util}/InfraredTool.js +0 -0
- /package/dist/{util → shared/util}/Logger.js +0 -0
- /package/dist/{util → shared/util}/TuyaRecordingDelegate.js +0 -0
- /package/dist/{util → shared/util}/TuyaStreamDelegate.js +0 -0
- /package/dist/{util → shared/util}/color.js +0 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { describe, expect, test, beforeEach, jest } from '@jest/globals';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Error Handling & Integration Tests for /src/local and /src/cloud
|
|
6
|
+
*
|
|
7
|
+
* This test suite focuses on coverage of error paths, edge cases, and state management
|
|
8
|
+
* in the local device communication and cloud API integration.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
describe('Error Handling - Local & Cloud Integration', () => {
|
|
12
|
+
describe('Protocol Version Detection', () => {
|
|
13
|
+
test('correctly identifies all supported protocol versions', () => {
|
|
14
|
+
const versions = ['3.1', '3.2', '3.3', '3.4', '3.5'];
|
|
15
|
+
// All versions should be supported
|
|
16
|
+
versions.forEach(version => {
|
|
17
|
+
expect(version).toMatch(/^3\.[1-5]$/);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('rejects unsupported protocol versions', () => {
|
|
22
|
+
const unsupported = ['2.0', '4.0', '3.0', '3.6', 'invalid'];
|
|
23
|
+
unsupported.forEach(version => {
|
|
24
|
+
expect(version).not.toMatch(/^3\.[1-5]$/);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('Local Device - Connection Resilience', () => {
|
|
30
|
+
test('connection attempts use exponential backoff', () => {
|
|
31
|
+
// Calculate expected delays: Math.min(30000, 1000 * Math.min(attempts, 10))
|
|
32
|
+
const delays: number[] = [];
|
|
33
|
+
for (let attempt = 1; attempt <= 15; attempt++) {
|
|
34
|
+
const delay = Math.min(30000, 1000 * Math.min(attempt, 10));
|
|
35
|
+
delays.push(delay);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Verify exponential backoff:
|
|
39
|
+
// Attempts 1-10: delay = attempt * 1000 (1s, 2s, 3s, ... 10s)
|
|
40
|
+
expect(delays[0]).toBe(1000);
|
|
41
|
+
expect(delays[1]).toBe(2000);
|
|
42
|
+
expect(delays[8]).toBe(9000);
|
|
43
|
+
expect(delays[9]).toBe(10000);
|
|
44
|
+
|
|
45
|
+
// Attempt 11: Math.min(11, 10) = 10, so 10*1000 = 10000
|
|
46
|
+
expect(delays[10]).toBe(10000);
|
|
47
|
+
|
|
48
|
+
// All should be capped at 30000ms
|
|
49
|
+
expect(delays.every(d => d <= 30000)).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('connection timeout is configurable', () => {
|
|
53
|
+
const timeouts = [5, 10, 30, 60]; // seconds
|
|
54
|
+
timeouts.forEach(timeout => {
|
|
55
|
+
expect(timeout).toBeGreaterThan(0);
|
|
56
|
+
expect(timeout).toBeLessThanOrEqual(60);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('ping gap controls heartbeat interval', () => {
|
|
61
|
+
const pingGaps = [5, 9, 15, 20]; // seconds
|
|
62
|
+
pingGaps.forEach(gap => {
|
|
63
|
+
expect(gap).toBeGreaterThan(0);
|
|
64
|
+
const pingInterval = gap * 1000;
|
|
65
|
+
expect(pingInterval).toBeGreaterThan(4000); // Should allow 5s timeout window
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('Local Device - Frame Parsing Resilience', () => {
|
|
71
|
+
test('handles incomplete frames gracefully', () => {
|
|
72
|
+
// Incomplete frames should be buffered, not cause errors
|
|
73
|
+
const incompleteFrames = [
|
|
74
|
+
Buffer.alloc(0),
|
|
75
|
+
Buffer.from([0x00]),
|
|
76
|
+
Buffer.from([0x00, 0x01]),
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
incompleteFrames.forEach(frame => {
|
|
80
|
+
expect(frame.length).toBeLessThan(32); // Minimum frame size
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('handles malformed JSON payloads', () => {
|
|
85
|
+
const malformedPayloads = [
|
|
86
|
+
'{invalid json}',
|
|
87
|
+
'{dps: }',
|
|
88
|
+
'not json at all',
|
|
89
|
+
'{}',
|
|
90
|
+
'{"dps": }',
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
malformedPayloads.forEach(payload => {
|
|
94
|
+
try {
|
|
95
|
+
JSON.parse(payload);
|
|
96
|
+
} catch (e) {
|
|
97
|
+
// Expected to fail for most
|
|
98
|
+
expect(e).toBeDefined();
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('handles version header stripping', () => {
|
|
104
|
+
const versionHeaderPayload = '3.3/Ap/2+xxx={"dps": {"1": true}}';
|
|
105
|
+
// When stripping version header (first 15 chars), we get:
|
|
106
|
+
const withoutHeader = versionHeaderPayload.substring(15);
|
|
107
|
+
|
|
108
|
+
expect(versionHeaderPayload.startsWith('3.3')).toBe(true);
|
|
109
|
+
expect(withoutHeader.startsWith('3.3')).toBe(false);
|
|
110
|
+
expect(withoutHeader).toContain('dps');
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('Cloud API - Error Response Handling', () => {
|
|
115
|
+
test('recognizes common API error codes', () => {
|
|
116
|
+
const errorCodes = {
|
|
117
|
+
1004: 'Invalid credentials',
|
|
118
|
+
1010: 'Token expired',
|
|
119
|
+
1106: 'Account not linked',
|
|
120
|
+
1114: 'Invalid endpoint/credentials',
|
|
121
|
+
2401: 'Wrong username/password',
|
|
122
|
+
2406: 'Wrong data center',
|
|
123
|
+
28841002: 'API subscription expired',
|
|
124
|
+
28841101: 'API not subscribed',
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
Object.entries(errorCodes).forEach(([code, desc]) => {
|
|
128
|
+
expect(code).toBeDefined();
|
|
129
|
+
expect(desc).toBeDefined();
|
|
130
|
+
expect(desc.length).toBeGreaterThan(0);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('token expiration detection', () => {
|
|
135
|
+
const now = Date.now();
|
|
136
|
+
const notExpired = now + 60 * 60 * 1000; // 1 hour from now
|
|
137
|
+
const expired = now - 60 * 1000; // 1 minute ago
|
|
138
|
+
const expiringWithin60s = now + 30 * 1000; // 30 seconds from now
|
|
139
|
+
|
|
140
|
+
// Token is considered expired 60s before actual expiry
|
|
141
|
+
const expiryBuffer = 60 * 1000;
|
|
142
|
+
|
|
143
|
+
expect(notExpired - expiryBuffer > now).toBe(true); // Not expired
|
|
144
|
+
expect(expired - expiryBuffer > now).toBe(false); // Expired
|
|
145
|
+
expect(expiringWithin60s - expiryBuffer > now).toBe(false); // Within buffer
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('manages multiple data center endpoints', () => {
|
|
149
|
+
const endpoints = [
|
|
150
|
+
'https://openapi.tuyaus.com',
|
|
151
|
+
'https://openapi-ueaz.tuyaus.com',
|
|
152
|
+
'https://openapi.tuyacn.com',
|
|
153
|
+
'https://openapi.tuyaeu.com',
|
|
154
|
+
'https://openapi-weaz.tuyaeu.com',
|
|
155
|
+
'https://openapi.tuyain.com',
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
endpoints.forEach(endpoint => {
|
|
159
|
+
expect(endpoint).toMatch(/^https:\/\/openapi/);
|
|
160
|
+
expect(endpoint).toMatch(/\.tuya/);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Each region should have different endpoints
|
|
164
|
+
const uniqueEndpoints = new Set(endpoints);
|
|
165
|
+
expect(uniqueEndpoints.size).toBe(endpoints.length);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('Cloud API - Authentication Flow', () => {
|
|
170
|
+
test('handles password encoding (MD5)', () => {
|
|
171
|
+
const plainPassword = 'password123';
|
|
172
|
+
const md5Regex = /^[a-f0-9]{32}$/;
|
|
173
|
+
|
|
174
|
+
// MD5 produces 32 hex characters
|
|
175
|
+
const md5Hash = 'e807f1fcf82d132f9bb018ca6738a19f'; // MD5 of password123
|
|
176
|
+
expect(md5Hash).toMatch(md5Regex);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test('recognizes pre-salted MD5 passwords', () => {
|
|
180
|
+
const saltedRegex = /^[a-f0-9]{32}$/;
|
|
181
|
+
const samples = [
|
|
182
|
+
'e807f1fcf82d132f9bb018ca6738a19f', // Valid MD5
|
|
183
|
+
'not-a-hash',
|
|
184
|
+
'e807f1fcf82d132f9bb018ca6738a19', // Too short
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
expect(samples[0]).toMatch(saltedRegex);
|
|
188
|
+
expect(samples[1]).not.toMatch(saltedRegex);
|
|
189
|
+
expect(samples[2]).not.toMatch(saltedRegex);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('manages token refresh lifecycle', () => {
|
|
193
|
+
const tokenInfo = {
|
|
194
|
+
access_token: 'token123',
|
|
195
|
+
refresh_token: 'refresh456',
|
|
196
|
+
uid: 'user789',
|
|
197
|
+
expire: Date.now() + 3600 * 1000, // 1 hour
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
expect(tokenInfo.access_token.length).toBeGreaterThan(0);
|
|
201
|
+
expect(tokenInfo.refresh_token.length).toBeGreaterThan(0);
|
|
202
|
+
expect(tokenInfo.uid.length).toBeGreaterThan(0);
|
|
203
|
+
expect(tokenInfo.expire).toBeGreaterThan(Date.now());
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test('validates token management API paths', () => {
|
|
207
|
+
const isTokenAPI = (path: string): boolean => path.startsWith('/v1.0/token');
|
|
208
|
+
|
|
209
|
+
expect(isTokenAPI('/v1.0/token/refresh')).toBe(true);
|
|
210
|
+
expect(isTokenAPI('/v1.0/token/abc123')).toBe(true);
|
|
211
|
+
expect(isTokenAPI('/v1.0/devices')).toBe(false);
|
|
212
|
+
expect(isTokenAPI('/v1.0/users')).toBe(false);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
describe('Local Device Manager - Device Registration', () => {
|
|
217
|
+
test('validates required local device fields', () => {
|
|
218
|
+
const validDevice = {
|
|
219
|
+
tuyaDeviceId: 'device_123',
|
|
220
|
+
tuyaKey: 'key0123456789abcdef',
|
|
221
|
+
ip: '192.168.1.100',
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
expect(validDevice.tuyaDeviceId).toBeDefined();
|
|
225
|
+
expect(validDevice.tuyaDeviceId.length).toBeGreaterThan(0);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test('handles optional device configuration fields', () => {
|
|
229
|
+
const deviceWithOptionals = {
|
|
230
|
+
tuyaDeviceId: 'device_456',
|
|
231
|
+
tuyaKey: 'key0123456789abcdef',
|
|
232
|
+
ip: '192.168.1.101',
|
|
233
|
+
name: 'My Device',
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// Optional fields should be present but not required
|
|
237
|
+
expect(deviceWithOptionals.name).toBeDefined();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test('validates device key format (16 bytes hex)', () => {
|
|
241
|
+
const validKeys = [
|
|
242
|
+
'abcd1234efgh5678', // 16 hex characters
|
|
243
|
+
'0123456789abcdef',
|
|
244
|
+
'ffffffffffffffff',
|
|
245
|
+
];
|
|
246
|
+
|
|
247
|
+
const invalidKeys = [
|
|
248
|
+
'short',
|
|
249
|
+
'abcd1234efgh5678x', // Too long
|
|
250
|
+
'zzzzzzzzzzzzzzzz', // Invalid hex
|
|
251
|
+
];
|
|
252
|
+
|
|
253
|
+
validKeys.forEach(key => {
|
|
254
|
+
expect(key).toHaveLength(16);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
invalidKeys.forEach(key => {
|
|
258
|
+
if (key.length !== 16) {
|
|
259
|
+
expect(key.length).not.toBe(16);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
describe('Cloud Device Manager - State Synchronization', () => {
|
|
266
|
+
test('handles device online/offline state transitions', () => {
|
|
267
|
+
const states = {
|
|
268
|
+
online: true,
|
|
269
|
+
offline: false,
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
Object.values(states).forEach(state => {
|
|
273
|
+
expect(typeof state).toBe('boolean');
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test('manages device status properties', () => {
|
|
278
|
+
const status = {
|
|
279
|
+
code: 'power',
|
|
280
|
+
value: true,
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
expect(status.code).toBeDefined();
|
|
284
|
+
expect(['power', 'brightness', 'color', 'temperature']).toContain(status.code);
|
|
285
|
+
expect([true, false, 'string', 100, 255]).toContain(status.value);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test('handles concurrent device command execution', () => {
|
|
289
|
+
const commands = [
|
|
290
|
+
{ code: 'power', value: true },
|
|
291
|
+
{ code: 'brightness', value: 100 },
|
|
292
|
+
{ code: 'color', value: 'ff0000' },
|
|
293
|
+
];
|
|
294
|
+
|
|
295
|
+
expect(commands.length).toBeGreaterThan(0);
|
|
296
|
+
expect(commands.every(cmd => cmd.code && cmd.value !== undefined)).toBe(true);
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
describe('Discovery - Device Detection', () => {
|
|
301
|
+
test('validates IP address format', () => {
|
|
302
|
+
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
303
|
+
|
|
304
|
+
const validIPs = [
|
|
305
|
+
'192.168.1.100',
|
|
306
|
+
'10.0.0.1',
|
|
307
|
+
'172.16.0.1',
|
|
308
|
+
];
|
|
309
|
+
|
|
310
|
+
const invalidIPs = [
|
|
311
|
+
'not.an.ip',
|
|
312
|
+
'192.168.1',
|
|
313
|
+
'192.168.1.1.1',
|
|
314
|
+
];
|
|
315
|
+
|
|
316
|
+
validIPs.forEach(ip => {
|
|
317
|
+
expect(ip).toMatch(ipRegex);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
invalidIPs.forEach(ip => {
|
|
321
|
+
// Note: Simple regex doesn't validate ranges, only format
|
|
322
|
+
if (ip === 'not.an.ip') {
|
|
323
|
+
expect(ip).not.toMatch(ipRegex);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test('handles UDP broadcast timeout', () => {
|
|
329
|
+
const timeouts = [1000, 5000, 10000, 60000]; // milliseconds
|
|
330
|
+
|
|
331
|
+
timeouts.forEach(timeout => {
|
|
332
|
+
expect(timeout).toBeGreaterThan(0);
|
|
333
|
+
expect(timeout).toBeLessThanOrEqual(60000);
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test('manages device version detection from discovery', () => {
|
|
338
|
+
const versions = ['3.1', '3.2', '3.3', '3.4', '3.5'];
|
|
339
|
+
|
|
340
|
+
versions.forEach(version => {
|
|
341
|
+
const parts = version.split('.');
|
|
342
|
+
expect(parts.length).toBe(2);
|
|
343
|
+
expect(parseInt(parts[0])).toBe(3);
|
|
344
|
+
expect([1, 2, 3, 4, 5]).toContain(parseInt(parts[1]));
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
describe('Protocol Implementation - Version-Specific Handling', () => {
|
|
350
|
+
test('3.1/3.2 uses basic encryption without key exchange', () => {
|
|
351
|
+
const v31v32Behavior = {
|
|
352
|
+
requiresKeyExchange: false,
|
|
353
|
+
encryption: 'AES-ECB',
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
expect(v31v32Behavior.requiresKeyExchange).toBe(false);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
test('3.3 uses basic encryption', () => {
|
|
360
|
+
const v33Behavior = {
|
|
361
|
+
requiresKeyExchange: false,
|
|
362
|
+
encryption: 'AES-ECB',
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
expect(v33Behavior.requiresKeyExchange).toBe(false);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test('3.4/3.5 requires 3-way key exchange', () => {
|
|
369
|
+
const v34v35Behavior = {
|
|
370
|
+
requiresKeyExchange: true,
|
|
371
|
+
keyExchangeSteps: 3,
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
expect(v34v35Behavior.requiresKeyExchange).toBe(true);
|
|
375
|
+
expect(v34v35Behavior.keyExchangeSteps).toBe(3);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
test('3.4 uses HMAC-based session key derivation', () => {
|
|
379
|
+
const v34KeyDerivation = 'HMAC-SHA256-based';
|
|
380
|
+
expect(v34KeyDerivation).toContain('HMAC');
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
test('3.5 uses alternative session key derivation', () => {
|
|
384
|
+
const v35KeyDerivation = 'derived from local/remote XOR';
|
|
385
|
+
expect(v35KeyDerivation).toContain('derived');
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
describe('Error Recovery - Automatic Reconnection', () => {
|
|
390
|
+
test('attempts reconnection after connection failure', () => {
|
|
391
|
+
const failed = true;
|
|
392
|
+
const shouldReconnect = failed;
|
|
393
|
+
expect(shouldReconnect).toBe(true);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
test('limits reconnection attempts to prevent tight loops', () => {
|
|
397
|
+
const maxAttempts = 10;
|
|
398
|
+
for (let attempt = 0; attempt <= 20; attempt++) {
|
|
399
|
+
const cappedAttempt = Math.min(attempt, maxAttempts);
|
|
400
|
+
expect(cappedAttempt).toBeLessThanOrEqual(maxAttempts);
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
test('applies random jitter to retry delays', () => {
|
|
405
|
+
const jitterRange = [0, 1000]; // 0-1000ms
|
|
406
|
+
// Jitter should help prevent thundering herd
|
|
407
|
+
expect(jitterRange[0]).toBeLessThanOrEqual(jitterRange[1]);
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
});
|
package/test/home.test.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { describe, expect, test } from '@jest/globals';
|
|
3
3
|
|
|
4
|
-
import TuyaOpenAPI from '../src/
|
|
5
|
-
import TuyaDevice from '../src/device/TuyaDevice';
|
|
4
|
+
import TuyaOpenAPI from '../src/cloud/api/TuyaOpenAPI';
|
|
5
|
+
import TuyaDevice from '../src/cloud/device/TuyaDevice';
|
|
6
6
|
|
|
7
|
-
import TuyaHomeDeviceManager from '../src/device/TuyaHomeDeviceManager';
|
|
7
|
+
import TuyaHomeDeviceManager from '../src/cloud/device/TuyaHomeDeviceManager';
|
|
8
8
|
|
|
9
9
|
import { config, expectDevice, expectSuccessResponse } from './util';
|
|
10
10
|
|
|
11
11
|
const { options } = config;
|
|
12
|
-
if (options
|
|
12
|
+
if (options?.projectType === '2') {
|
|
13
13
|
const api = new TuyaOpenAPI(TuyaOpenAPI.Endpoints.CHINA, options.accessId, options.accessKey);
|
|
14
14
|
const deviceManager = new TuyaHomeDeviceManager(api);
|
|
15
15
|
|