@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,344 @@
|
|
|
1
|
+
import { describe, expect, it, beforeEach, afterEach, jest } from '@jest/globals';
|
|
2
|
+
import LocalDeviceManager from '../../src/local/LocalDeviceManager';
|
|
3
|
+
import { LocalConfig } from '../../src/local/config';
|
|
4
|
+
import TuyaDeviceManager from '../../src/cloud/device/TuyaDeviceManager';
|
|
5
|
+
import Logger from '../../src/shared/util/Logger';
|
|
6
|
+
|
|
7
|
+
// ── Logger mock ───────────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
function makeMockLog(): Logger {
|
|
10
|
+
return {
|
|
11
|
+
debug: jest.fn(),
|
|
12
|
+
info: jest.fn(),
|
|
13
|
+
warn: jest.fn(),
|
|
14
|
+
error: jest.fn(),
|
|
15
|
+
log: jest.fn(),
|
|
16
|
+
} as unknown as Logger;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ── Minimal config helpers ──────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
const GATEWAY_ID = 'gw_device_001';
|
|
22
|
+
const CHILD_ID_A = 'child_device_001';
|
|
23
|
+
const CHILD_ID_B = 'child_device_002';
|
|
24
|
+
const CHILD_CID_A = '00112233445566aa';
|
|
25
|
+
const CHILD_CID_B = '00112233445566bb';
|
|
26
|
+
const DEVICE_KEY = '0123456789abcdef'; // 16-char local key
|
|
27
|
+
const DEVICE_IP = '192.168.1.200';
|
|
28
|
+
|
|
29
|
+
function zigbeeConfig(): LocalConfig {
|
|
30
|
+
return {
|
|
31
|
+
autoDiscoverDevices: false,
|
|
32
|
+
devices: [
|
|
33
|
+
{
|
|
34
|
+
tuyaDeviceId: GATEWAY_ID,
|
|
35
|
+
name: 'Zigbee Gateway',
|
|
36
|
+
ip: DEVICE_IP,
|
|
37
|
+
tuyaKey: DEVICE_KEY,
|
|
38
|
+
protocolVersion: '3.3',
|
|
39
|
+
isZigbeeGateway: true,
|
|
40
|
+
switchCount: 1,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
tuyaDeviceId: CHILD_ID_A,
|
|
44
|
+
name: 'Switch Child A',
|
|
45
|
+
ip: DEVICE_IP,
|
|
46
|
+
tuyaKey: DEVICE_KEY,
|
|
47
|
+
protocolVersion: '3.3',
|
|
48
|
+
parentDeviceId: GATEWAY_ID,
|
|
49
|
+
zigbeeChildId: CHILD_CID_A,
|
|
50
|
+
switchCount: 1,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
tuyaDeviceId: CHILD_ID_B,
|
|
54
|
+
name: 'Switch Child B',
|
|
55
|
+
ip: DEVICE_IP,
|
|
56
|
+
tuyaKey: DEVICE_KEY,
|
|
57
|
+
protocolVersion: '3.3',
|
|
58
|
+
parentDeviceId: GATEWAY_ID,
|
|
59
|
+
zigbeeChildId: CHILD_CID_B,
|
|
60
|
+
switchCount: 1,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function standaloneConfig(): LocalConfig {
|
|
67
|
+
return {
|
|
68
|
+
autoDiscoverDevices: false,
|
|
69
|
+
devices: [
|
|
70
|
+
{
|
|
71
|
+
tuyaDeviceId: 'standalone_001',
|
|
72
|
+
name: 'Standalone Switch',
|
|
73
|
+
ip: '192.168.1.10',
|
|
74
|
+
tuyaKey: DEVICE_KEY,
|
|
75
|
+
protocolVersion: '3.3',
|
|
76
|
+
switchCount: 1,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ── Tests ──────────────────────────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
describe('LocalDeviceManager – Zigbee integration', () => {
|
|
85
|
+
let log: Logger;
|
|
86
|
+
let manager: LocalDeviceManager;
|
|
87
|
+
|
|
88
|
+
beforeEach(() => {
|
|
89
|
+
log = makeMockLog();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
afterEach(() => {
|
|
93
|
+
manager?.stopLocalDevices();
|
|
94
|
+
jest.clearAllMocks();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// ── initLocalDevices: child-skipping ------------------------------------------
|
|
98
|
+
|
|
99
|
+
describe('initLocalDevices() – child device handling', () => {
|
|
100
|
+
it('does not register child devices as TuyaDevices during first init pass', async () => {
|
|
101
|
+
manager = new LocalDeviceManager(zigbeeConfig(), log);
|
|
102
|
+
await manager.initLocalDevices();
|
|
103
|
+
|
|
104
|
+
// Only the gateway should be in the device list initially
|
|
105
|
+
// Children are registered lazily when the parent connects
|
|
106
|
+
const deviceIds = manager.devices.map(d => d.id);
|
|
107
|
+
expect(deviceIds).toContain(GATEWAY_ID);
|
|
108
|
+
expect(deviceIds).not.toContain(CHILD_ID_A);
|
|
109
|
+
expect(deviceIds).not.toContain(CHILD_ID_B);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('registers standalone devices normally', async () => {
|
|
113
|
+
manager = new LocalDeviceManager(standaloneConfig(), log);
|
|
114
|
+
await manager.initLocalDevices();
|
|
115
|
+
|
|
116
|
+
expect(manager.devices.map(d => d.id)).toContain('standalone_001');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('logs gateway relationships when detected', async () => {
|
|
120
|
+
manager = new LocalDeviceManager(zigbeeConfig(), log);
|
|
121
|
+
await manager.initLocalDevices();
|
|
122
|
+
|
|
123
|
+
const infoSpy = log.info as jest.MockedFunction<typeof log.info>;
|
|
124
|
+
const infoCalls = infoSpy.mock.calls.map(c => String(c[0]));
|
|
125
|
+
const gatewayLine = infoCalls.find(s => s.includes('Zigbee gateway'));
|
|
126
|
+
expect(gatewayLine).toBeDefined();
|
|
127
|
+
expect(gatewayLine).toContain(GATEWAY_ID);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('proceeds without fatal errors when no Zigbee devices in config', async () => {
|
|
131
|
+
manager = new LocalDeviceManager(standaloneConfig(), log);
|
|
132
|
+
await expect(manager.initLocalDevices()).resolves.not.toThrow();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// ── Zigbee config error handling ──────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
describe('initLocalDevices() – Zigbee config error handling', () => {
|
|
139
|
+
it('logs an error but continues for non-Zigbee devices when config is invalid', async () => {
|
|
140
|
+
const badConfig: LocalConfig = {
|
|
141
|
+
autoDiscoverDevices: false,
|
|
142
|
+
devices: [
|
|
143
|
+
// An orphaned child (no matching parent in config)
|
|
144
|
+
{
|
|
145
|
+
tuyaDeviceId: 'orphan_child',
|
|
146
|
+
name: 'Orphan',
|
|
147
|
+
ip: DEVICE_IP,
|
|
148
|
+
tuyaKey: DEVICE_KEY,
|
|
149
|
+
parentDeviceId: 'nonexistent_parent',
|
|
150
|
+
zigbeeChildId: '0011223344556601',
|
|
151
|
+
switchCount: 1,
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
tuyaDeviceId: 'standalone_ok',
|
|
155
|
+
name: 'Standalone OK',
|
|
156
|
+
ip: '192.168.1.11',
|
|
157
|
+
tuyaKey: DEVICE_KEY,
|
|
158
|
+
switchCount: 1,
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
manager = new LocalDeviceManager(badConfig, log);
|
|
164
|
+
await expect(manager.initLocalDevices()).resolves.not.toThrow();
|
|
165
|
+
|
|
166
|
+
const errorSpy = log.error as jest.MockedFunction<typeof log.error>;
|
|
167
|
+
const errorCalls = errorSpy.mock.calls.map(c => String(c[0]));
|
|
168
|
+
const zigbeeErrorLine = errorCalls.find(s => s.includes('Zigbee'));
|
|
169
|
+
expect(zigbeeErrorLine).toBeDefined();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// ── sendCommands: Zigbee child routing ─────────────────────────────────────
|
|
174
|
+
|
|
175
|
+
describe('sendCommands() – Zigbee child routing', () => {
|
|
176
|
+
it('returns without acting when device has no dpMapping (unknown device)', async () => {
|
|
177
|
+
manager = new LocalDeviceManager(zigbeeConfig(), log);
|
|
178
|
+
await manager.initLocalDevices();
|
|
179
|
+
|
|
180
|
+
// CHILD_ID_A is not yet registered in the first pass
|
|
181
|
+
const result = await manager.sendCommands('nonexistent_device', [{ code: 'switch_1', value: true }]);
|
|
182
|
+
expect(result).toBeUndefined();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('handles sendCommands for a known device that has a dpMapping', async () => {
|
|
186
|
+
manager = new LocalDeviceManager(standaloneConfig(), log);
|
|
187
|
+
await manager.initLocalDevices();
|
|
188
|
+
|
|
189
|
+
// 'standalone_001' is in the device list but has no IP connection (autoDiscover=false, no connect called)
|
|
190
|
+
// sendCommands should log a warning about no connection, not throw
|
|
191
|
+
await expect(
|
|
192
|
+
manager.sendCommands('standalone_001', [{ code: 'switch_1', value: true }]),
|
|
193
|
+
).resolves.not.toThrow();
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// ── stopLocalDevices: gateway cleanup ─────────────────────────────────────
|
|
198
|
+
|
|
199
|
+
describe('stopLocalDevices()', () => {
|
|
200
|
+
it('does not throw when called with Zigbee gateway config and no active connections', async () => {
|
|
201
|
+
manager = new LocalDeviceManager(zigbeeConfig(), log);
|
|
202
|
+
await manager.initLocalDevices();
|
|
203
|
+
|
|
204
|
+
expect(() => manager.stopLocalDevices()).not.toThrow();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('can be called multiple times without error', async () => {
|
|
208
|
+
manager = new LocalDeviceManager(zigbeeConfig(), log);
|
|
209
|
+
await manager.initLocalDevices();
|
|
210
|
+
|
|
211
|
+
expect(() => {
|
|
212
|
+
manager.stopLocalDevices();
|
|
213
|
+
manager.stopLocalDevices();
|
|
214
|
+
}).not.toThrow();
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// ── _setupZigbeeChildren: event-driven child setup ─────────────────────────
|
|
219
|
+
|
|
220
|
+
describe('_setupZigbeeChildren() – via gateway connect event', () => {
|
|
221
|
+
it('emits DEVICE_ADD for child when gateway connects', async () => {
|
|
222
|
+
const EventEmitter = (await import('events')).default;
|
|
223
|
+
manager = new LocalDeviceManager(zigbeeConfig(), log);
|
|
224
|
+
await manager.initLocalDevices();
|
|
225
|
+
|
|
226
|
+
const deviceAddEvents: string[] = [];
|
|
227
|
+
manager.on(TuyaDeviceManager.Events.DEVICE_ADD, (device: any) => {
|
|
228
|
+
deviceAddEvents.push(device.id);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Access the internal gateway map to simulate a connect event
|
|
232
|
+
// We do this by calling _setupZigbeeChildren via the gateway's connect event
|
|
233
|
+
// The gatewayRelationships map is private but we can test the observable side effect
|
|
234
|
+
|
|
235
|
+
// Force the manager to think the gateway connected by accessing private via bracket notation
|
|
236
|
+
const gatewayRelationships = (manager as any).gatewayRelationships as Map<string, any>;
|
|
237
|
+
if (gatewayRelationships.size > 0) {
|
|
238
|
+
// Gateway relationships were detected
|
|
239
|
+
expect(gatewayRelationships.has(GATEWAY_ID)).toBe(true);
|
|
240
|
+
|
|
241
|
+
const rel = gatewayRelationships.get(GATEWAY_ID);
|
|
242
|
+
expect(rel).toBeDefined();
|
|
243
|
+
expect(rel.children.length).toBe(2);
|
|
244
|
+
|
|
245
|
+
const cids = rel.children.map((c: any) => c.cid);
|
|
246
|
+
expect(cids).toContain(CHILD_CID_A);
|
|
247
|
+
expect(cids).toContain(CHILD_CID_B);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('correctly maps child deviceId <-> cid in the relationship', async () => {
|
|
252
|
+
manager = new LocalDeviceManager(zigbeeConfig(), log);
|
|
253
|
+
await manager.initLocalDevices();
|
|
254
|
+
|
|
255
|
+
const gatewayRelationships = (manager as any).gatewayRelationships as Map<string, any>;
|
|
256
|
+
const rel = gatewayRelationships.get(GATEWAY_ID);
|
|
257
|
+
|
|
258
|
+
expect(rel).toBeDefined();
|
|
259
|
+
const childA = rel.children.find((c: any) => c.cid === CHILD_CID_A);
|
|
260
|
+
expect(childA).toBeDefined();
|
|
261
|
+
expect(childA.deviceId).toBe(CHILD_ID_A);
|
|
262
|
+
expect(childA.name).toBe('Switch Child A');
|
|
263
|
+
|
|
264
|
+
const childB = rel.children.find((c: any) => c.cid === CHILD_CID_B);
|
|
265
|
+
expect(childB).toBeDefined();
|
|
266
|
+
expect(childB.deviceId).toBe(CHILD_ID_B);
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// ── getDevice ─────────────────────────────────────────────────────────────
|
|
271
|
+
|
|
272
|
+
describe('getDevice()', () => {
|
|
273
|
+
it('returns the gateway TuyaDevice by ID', async () => {
|
|
274
|
+
manager = new LocalDeviceManager(zigbeeConfig(), log);
|
|
275
|
+
await manager.initLocalDevices();
|
|
276
|
+
|
|
277
|
+
const gw = manager.getDevice(GATEWAY_ID);
|
|
278
|
+
expect(gw).toBeDefined();
|
|
279
|
+
expect(gw?.id).toBe(GATEWAY_ID);
|
|
280
|
+
expect(gw?.name).toBe('Zigbee Gateway');
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('returns undefined for a child device before parent connects', async () => {
|
|
284
|
+
manager = new LocalDeviceManager(zigbeeConfig(), log);
|
|
285
|
+
await manager.initLocalDevices();
|
|
286
|
+
|
|
287
|
+
// Children not yet registered (lazy registration happens on parent connect)
|
|
288
|
+
const child = manager.getDevice(CHILD_ID_A);
|
|
289
|
+
expect(child).toBeUndefined();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('returns undefined for a completely unknown device', async () => {
|
|
293
|
+
manager = new LocalDeviceManager(zigbeeConfig(), log);
|
|
294
|
+
await manager.initLocalDevices();
|
|
295
|
+
|
|
296
|
+
expect(manager.getDevice('no_such_device')).toBeUndefined();
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// ── Mixed Zigbee + standalone config ─────────────────────────────────────
|
|
301
|
+
|
|
302
|
+
describe('Mixed Zigbee and standalone devices', () => {
|
|
303
|
+
it('registers standalone devices alongside gateways', async () => {
|
|
304
|
+
const mixedConfig: LocalConfig = {
|
|
305
|
+
autoDiscoverDevices: false,
|
|
306
|
+
devices: [
|
|
307
|
+
...zigbeeConfig().devices!,
|
|
308
|
+
{
|
|
309
|
+
tuyaDeviceId: 'standalone_001',
|
|
310
|
+
name: 'Standalone Switch',
|
|
311
|
+
ip: '192.168.1.10',
|
|
312
|
+
tuyaKey: DEVICE_KEY,
|
|
313
|
+
switchCount: 1,
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
manager = new LocalDeviceManager(mixedConfig, log);
|
|
319
|
+
await manager.initLocalDevices();
|
|
320
|
+
|
|
321
|
+
const ids = manager.devices.map(d => d.id);
|
|
322
|
+
expect(ids).toContain(GATEWAY_ID);
|
|
323
|
+
expect(ids).toContain('standalone_001');
|
|
324
|
+
expect(ids).not.toContain(CHILD_ID_A);
|
|
325
|
+
expect(ids).not.toContain(CHILD_ID_B);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('detects the correct number of gateway relationships', async () => {
|
|
329
|
+
manager = new LocalDeviceManager(zigbeeConfig(), log);
|
|
330
|
+
await manager.initLocalDevices();
|
|
331
|
+
|
|
332
|
+
const gatewayRelationships = (manager as any).gatewayRelationships as Map<string, any>;
|
|
333
|
+
expect(gatewayRelationships.size).toBe(1);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it('has no gateway relationships for purely standalone config', async () => {
|
|
337
|
+
manager = new LocalDeviceManager(standaloneConfig(), log);
|
|
338
|
+
await manager.initLocalDevices();
|
|
339
|
+
|
|
340
|
+
const gatewayRelationships = (manager as any).gatewayRelationships as Map<string, any>;
|
|
341
|
+
expect(gatewayRelationships.size).toBe(0);
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
});
|