@homebridge-plugins/homebridge-tuya 3.0.0-beta.2 → 3.0.0-beta.21
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 +354 -142
- package/config.schema.json +1221 -893
- package/dist/cloud/api/TuyaOpenAPI.js +108 -60
- package/dist/cloud/api/TuyaOpenAPI.js.map +1 -1
- package/dist/cloud/api/TuyaOpenMQ.js +45 -22
- package/dist/cloud/api/TuyaOpenMQ.js.map +1 -1
- package/dist/cloud/device/{TuyaDeviceManager.js → TuyaCloudDeviceManager.js} +146 -96
- package/dist/cloud/device/TuyaCloudDeviceManager.js.map +1 -0
- package/dist/cloud/device/TuyaCustomDeviceManager.js +75 -5
- package/dist/cloud/device/TuyaCustomDeviceManager.js.map +1 -1
- package/dist/cloud/device/TuyaDevice.js.map +1 -1
- package/dist/cloud/device/TuyaHomeDeviceManager.js +81 -13
- package/dist/cloud/device/TuyaHomeDeviceManager.js.map +1 -1
- package/dist/config.js +26 -5
- package/dist/config.js.map +1 -1
- package/dist/local/DynamicChildDiscovery.js +2 -1
- package/dist/local/DynamicChildDiscovery.js.map +1 -1
- package/dist/local/LocalDevice.js +16 -3
- package/dist/local/LocalDevice.js.map +1 -1
- package/dist/local/LocalDeviceManager.js +361 -164
- package/dist/local/LocalDeviceManager.js.map +1 -1
- package/dist/local/TuyaDiscovery.js +16 -7
- package/dist/local/TuyaDiscovery.js.map +1 -1
- package/dist/local/ZigbeeGatewayDetection.js +7 -4
- package/dist/local/ZigbeeGatewayDetection.js.map +1 -1
- package/dist/local/protocol/ProtocolUtilities.js +34 -17
- package/dist/local/protocol/ProtocolUtilities.js.map +1 -1
- package/dist/local/protocol/ProtocolV31V32.js +4 -2
- package/dist/local/protocol/ProtocolV31V32.js.map +1 -1
- package/dist/local/protocol/ProtocolV33.js +4 -2
- package/dist/local/protocol/ProtocolV33.js.map +1 -1
- package/dist/local/protocol/ProtocolV34.js +10 -5
- package/dist/local/protocol/ProtocolV34.js.map +1 -1
- package/dist/local/protocol/ProtocolV35.js +8 -4
- package/dist/local/protocol/ProtocolV35.js.map +1 -1
- package/dist/platform.js +253 -493
- package/dist/platform.js.map +1 -1
- package/dist/settings.js +0 -2
- package/dist/settings.js.map +1 -1
- package/dist/shared/TuyaDeviceManager.js +147 -0
- package/dist/shared/TuyaDeviceManager.js.map +1 -0
- package/dist/shared/TuyaHybridDeviceManager.js +215 -0
- package/dist/shared/TuyaHybridDeviceManager.js.map +1 -0
- package/dist/shared/accessory/AccessoryFactory.js +350 -0
- package/dist/shared/accessory/AccessoryFactory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/AirConditionerAccessory.js +21 -15
- package/dist/shared/accessory/AirConditionerAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/AirPurifierAccessory.js.map +1 -1
- package/dist/shared/accessory/AirQualitySensorAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/BaseAccessory.js +16 -95
- package/dist/shared/accessory/BaseAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/BlindsAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/CameraAccessory.js +2 -2
- package/dist/shared/accessory/CameraAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/CarbonDioxideSensorAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/CarbonMonoxideSensorAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/ContactSensorAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/DehumidifierAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/DiffuserAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/DimmerAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/DoorbellAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/ExtractionHoodAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/FanAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/GarageDoorAccessory.js +19 -2
- package/dist/shared/accessory/GarageDoorAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/HeaterAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/HeaterAccessory_old.js.map +1 -1
- package/dist/shared/accessory/HumanPresenceSensorAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/HumidifierAccessory.js.map +1 -1
- package/dist/shared/accessory/IRAdapter.js +167 -0
- package/dist/shared/accessory/IRAdapter.js.map +1 -0
- package/dist/shared/accessory/IRAirConditionerAccessory.js.map +1 -0
- package/dist/shared/accessory/IRControlHubAccessory.js.map +1 -0
- package/dist/shared/accessory/IRControlHubSubAccessory.js.map +1 -0
- package/dist/shared/accessory/IRFanAccessory.js +90 -0
- package/dist/shared/accessory/IRFanAccessory.js.map +1 -0
- package/dist/shared/accessory/IRGenericAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/LeakSensorAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/LightAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/LightSensorAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/LocationWeatherAccessory.js +1 -1
- package/dist/shared/accessory/LocationWeatherAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/LockAccessory.js +3 -3
- package/dist/shared/{accessories → accessory}/LockAccessory.js.map +1 -1
- package/dist/shared/accessory/MotionSensorAccessory.js.map +1 -0
- package/dist/shared/accessory/OutletAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/PetFeederAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/SceneAccessory.js +1 -1
- package/dist/shared/accessory/SceneAccessory.js.map +1 -0
- package/dist/shared/accessory/SceneSwitchAccessory.js.map +1 -0
- package/dist/shared/accessory/SecuritySystemAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/SmokeSensorAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/SwitchAccessory.js +1 -45
- package/dist/shared/accessory/SwitchAccessory.js.map +1 -0
- package/dist/shared/accessory/TemperatureHumiditySensorAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/ThermostatAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/TowerRackAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/ValveAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/VibrationSensorAccessory.js.map +1 -1
- package/dist/shared/accessory/WeatherStationAccessory.js.map +1 -0
- package/dist/shared/accessory/WetBulbGlobeTemperatureAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/WhiteNoiseLightAccessory.js +1 -0
- package/dist/shared/accessory/WhiteNoiseLightAccessory.js.map +1 -0
- package/dist/shared/accessory/WindowAccessory.js.map +1 -0
- package/dist/shared/{accessories → accessory}/WindowCoveringAccessory.js.map +1 -1
- package/dist/shared/{accessories → accessory}/WirelessSwitchAccessory.js.map +1 -1
- package/dist/shared/accessory/characteristic/Active.js.map +1 -0
- package/dist/shared/accessory/characteristic/AirQuality.js.map +1 -0
- package/dist/shared/{accessories → accessory}/characteristic/CurrentRelativeHumidity.js +3 -0
- package/dist/shared/accessory/characteristic/CurrentRelativeHumidity.js.map +1 -0
- package/dist/shared/accessory/characteristic/CurrentTemperature.js.map +1 -0
- package/dist/shared/accessory/characteristic/CurrentWeather.js.map +1 -0
- package/dist/shared/accessory/characteristic/CurrentWeatherByOpenMeteo.js.map +1 -0
- package/dist/shared/{accessories → accessory}/characteristic/CurrentWetBulbGlobeTemperature.js +3 -2
- package/dist/shared/accessory/characteristic/CurrentWetBulbGlobeTemperature.js.map +1 -0
- package/dist/shared/{accessories → accessory}/characteristic/EnergyUsage.js +0 -5
- package/dist/shared/accessory/characteristic/EnergyUsage.js.map +1 -0
- package/dist/shared/{accessories → accessory}/characteristic/Light.js +28 -5
- package/dist/shared/accessory/characteristic/Light.js.map +1 -0
- package/dist/shared/accessory/characteristic/LightSensor.js.map +1 -0
- package/dist/shared/{accessories → accessory}/characteristic/LockPhysicalControls.js +3 -0
- package/dist/shared/accessory/characteristic/LockPhysicalControls.js.map +1 -0
- package/dist/shared/accessory/characteristic/MotionDetected.js.map +1 -0
- package/dist/shared/accessory/characteristic/Name.js.map +1 -0
- package/dist/shared/accessory/characteristic/OccupancyDetected.js.map +1 -0
- package/dist/shared/{accessories → accessory}/characteristic/On.js +1 -0
- package/dist/shared/accessory/characteristic/On.js.map +1 -0
- package/dist/shared/accessory/characteristic/OutletInUse.js.map +1 -0
- package/dist/shared/accessory/characteristic/ProgrammableSwitchEvent.js.map +1 -0
- package/dist/shared/{accessories → accessory}/characteristic/RelativeHumidityDehumidifierThreshold.js +3 -0
- package/dist/shared/accessory/characteristic/RelativeHumidityDehumidifierThreshold.js.map +1 -0
- package/dist/shared/accessory/characteristic/RotationSpeed.js.map +1 -0
- package/dist/shared/accessory/characteristic/SecuritySystemState.js.map +1 -0
- package/dist/shared/{accessories → accessory}/characteristic/SwingMode.js +3 -0
- package/dist/shared/accessory/characteristic/SwingMode.js.map +1 -0
- package/dist/shared/accessory/characteristic/TargetTemperature.js.map +1 -0
- package/dist/shared/accessory/characteristic/TemperatureDisplayUnits.js.map +1 -0
- package/dist/shared/util/ConfigHash.js +2 -2
- package/dist/shared/util/ConfigHash.js.map +1 -1
- package/dist/shared/util/ConfigMigrator.js +222 -0
- package/dist/shared/util/ConfigMigrator.js.map +1 -0
- package/dist/shared/util/FfmpegStreamingProcess.js +62 -0
- package/dist/shared/util/FfmpegStreamingProcess.js.map +1 -1
- package/dist/shared/util/InfraredTool.js +0 -2
- package/dist/shared/util/InfraredTool.js.map +1 -1
- package/dist/shared/util/Logger.js +85 -10
- package/dist/shared/util/Logger.js.map +1 -1
- package/dist/shared/util/TuyaStreamDelegate.js +194 -97
- package/dist/shared/util/TuyaStreamDelegate.js.map +1 -1
- package/dist/shared/util/util.js +59 -4
- package/dist/shared/util/util.js.map +1 -1
- package/docs/ADVANCED_OPTIONS.md +603 -0
- package/docs/CONFIG_GUIDE.md +616 -0
- package/docs/Get-Local-Keys-for-Your-Devices.md +246 -0
- package/{SUPPORTED_DEVICES.md → docs/SUPPORTED_DEVICES.md} +24 -3
- package/eslint.config.mjs +0 -1
- package/{jest.config.js → jest.config.ts} +5 -2
- package/package.json +12 -9
- package/test/ConfigMigrator.test.ts +1060 -0
- package/test/Logger.test.ts +482 -0
- package/test/accessoryFactory.data.test.ts +172 -0
- package/test/accessoryFactory.test.ts +64 -35
- package/test/airConditioner.test.ts +742 -0
- package/test/config.test.ts +17 -13
- package/test/custom.test.ts +2 -2
- package/test/errorHandling.test.ts +12 -12
- package/test/home.test.ts +1 -1
- package/test/hybridDeviceManager.test.ts +808 -0
- package/test/light.test.ts +250 -0
- package/test/localDevice.test.ts +21 -50
- package/test/localDeviceManager.behavior.test.ts +196 -31
- package/test/localDeviceManager.test.ts +124 -41
- package/test/mqttMessages.test.ts +33 -14
- package/test/platform.test.ts +337 -814
- package/test/platform.validation.local.test.ts +58 -119
- package/test/tuyaCustomDeviceManager.test.ts +106 -16
- package/test/tuyaDeviceManager.test.ts +636 -639
- package/test/tuyaDiscovery.test.ts +21 -33
- package/test/tuyaHomeDeviceManager.test.ts +109 -18
- package/test/tuyaOpenAPI.test.ts +25 -44
- package/test/tuyaOpenMQ.test.ts +15 -23
- package/test/util.test.ts +107 -7
- package/test/zigbee/LocalDevice.zigbee.test.ts +14 -18
- package/test/zigbee/LocalDeviceManager.cloud-discovery.test.ts +19 -20
- package/test/zigbee/LocalDeviceManager.zigbee.reconnect.test.ts +19 -20
- package/test/zigbee/LocalDeviceManager.zigbee.test.ts +73 -35
- package/test/zigbee/ZigbeeGatewayDetection.test.ts +2 -2
- package/ADVANCED_OPTIONS.md +0 -267
- package/dist/cloud/device/TuyaDeviceManager.js.map +0 -1
- package/dist/local/CloudLocalReconciliation.js +0 -180
- package/dist/local/CloudLocalReconciliation.js.map +0 -1
- package/dist/shared/AccessoryFactory.js +0 -276
- package/dist/shared/AccessoryFactory.js.map +0 -1
- package/dist/shared/accessories/AccessoryFactory.js +0 -305
- package/dist/shared/accessories/AccessoryFactory.js.map +0 -1
- package/dist/shared/accessories/AirConditionerAccessory.js.map +0 -1
- package/dist/shared/accessories/AirQualitySensorAccessory.js.map +0 -1
- package/dist/shared/accessories/BaseAccessory.js.map +0 -1
- package/dist/shared/accessories/CameraAccessory.js.map +0 -1
- package/dist/shared/accessories/GarageDoorAccessory.js.map +0 -1
- package/dist/shared/accessories/HumanPresenceSensorAccessory.js.map +0 -1
- package/dist/shared/accessories/IRAirConditionerAccessory.js.map +0 -1
- package/dist/shared/accessories/IRControlHubAccessory.js.map +0 -1
- package/dist/shared/accessories/IRControlHubSubAccessory.js.map +0 -1
- package/dist/shared/accessories/IRGenericAccessory.js.map +0 -1
- package/dist/shared/accessories/LocationWeatherAccessory.js.map +0 -1
- package/dist/shared/accessories/MotionSensorAccessory.js.map +0 -1
- package/dist/shared/accessories/OutletAccessory.js.map +0 -1
- package/dist/shared/accessories/SceneAccessory.js.map +0 -1
- package/dist/shared/accessories/SceneSwitchAccessory.js.map +0 -1
- package/dist/shared/accessories/SecuritySystemAccessory.js.map +0 -1
- package/dist/shared/accessories/SwitchAccessory.js.map +0 -1
- package/dist/shared/accessories/TemperatureHumiditySensorAccessory.js.map +0 -1
- package/dist/shared/accessories/WeatherStationAccessory.js.map +0 -1
- package/dist/shared/accessories/WetBulbGlobeTemperatureAccessory.js.map +0 -1
- package/dist/shared/accessories/WhiteNoiseLightAccessory.js.map +0 -1
- package/dist/shared/accessories/WindowAccessory.js.map +0 -1
- package/dist/shared/accessories/characteristic/Active.js.map +0 -1
- package/dist/shared/accessories/characteristic/AirQuality.js.map +0 -1
- package/dist/shared/accessories/characteristic/CurrentRelativeHumidity.js.map +0 -1
- package/dist/shared/accessories/characteristic/CurrentTemperature.js.map +0 -1
- package/dist/shared/accessories/characteristic/CurrentWeather.js.map +0 -1
- package/dist/shared/accessories/characteristic/CurrentWeatherByOpenMeteo.js.map +0 -1
- package/dist/shared/accessories/characteristic/CurrentWetBulbGlobeTemperature.js.map +0 -1
- package/dist/shared/accessories/characteristic/EnergyUsage.js.map +0 -1
- package/dist/shared/accessories/characteristic/Light.js.map +0 -1
- package/dist/shared/accessories/characteristic/LightSensor.js.map +0 -1
- package/dist/shared/accessories/characteristic/LockPhysicalControls.js.map +0 -1
- package/dist/shared/accessories/characteristic/MotionDetected.js.map +0 -1
- package/dist/shared/accessories/characteristic/Name.js.map +0 -1
- package/dist/shared/accessories/characteristic/OccupancyDetected.js.map +0 -1
- package/dist/shared/accessories/characteristic/On.js.map +0 -1
- package/dist/shared/accessories/characteristic/OutletInUse.js.map +0 -1
- package/dist/shared/accessories/characteristic/ProgrammableSwitchEvent.js.map +0 -1
- package/dist/shared/accessories/characteristic/RelativeHumidityDehumidifierThreshold.js.map +0 -1
- package/dist/shared/accessories/characteristic/RotationSpeed.js.map +0 -1
- package/dist/shared/accessories/characteristic/SecuritySystemState.js.map +0 -1
- package/dist/shared/accessories/characteristic/SwingMode.js.map +0 -1
- package/dist/shared/accessories/characteristic/TargetTemperature.js.map +0 -1
- package/dist/shared/accessories/characteristic/TemperatureDisplayUnits.js.map +0 -1
- package/test/zigbee/CloudLocalReconciliation.test.ts +0 -284
- package/tuya-local-configs/dev-1.hash +0 -1
- package/tuya-local-configs/device1.hash +0 -1
- package/wiki/Get-Local-Keys-for-Your-Devices.md +0 -85
- /package/dist/shared/{accessories → accessory}/AirPurifierAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/AirQualitySensorAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/BlindsAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/CarbonDioxideSensorAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/CarbonMonoxideSensorAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/ContactSensorAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/DehumidifierAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/DiffuserAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/DimmerAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/DoorbellAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/ExtractionHoodAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/FanAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/HeaterAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/HeaterAccessory_old.js +0 -0
- /package/dist/shared/{accessories → accessory}/HumanPresenceSensorAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/HumidifierAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/IRAirConditionerAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/IRControlHubAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/IRControlHubSubAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/IRGenericAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/LeakSensorAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/LightAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/LightSensorAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/MotionSensorAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/OutletAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/PetFeederAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/SceneSwitchAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/SecuritySystemAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/SmokeSensorAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/TemperatureHumiditySensorAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/ThermostatAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/TowerRackAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/ValveAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/VibrationSensorAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/WeatherStationAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/WetBulbGlobeTemperatureAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/WindowAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/WindowCoveringAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/WirelessSwitchAccessory.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/Active.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/AirQuality.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/CurrentTemperature.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/CurrentWeather.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/CurrentWeatherByOpenMeteo.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/LightSensor.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/MotionDetected.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/Name.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/OccupancyDetected.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/OutletInUse.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/ProgrammableSwitchEvent.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/RotationSpeed.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/SecuritySystemState.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/TargetTemperature.js +0 -0
- /package/dist/shared/{accessories → accessory}/characteristic/TemperatureDisplayUnits.js +0 -0
|
@@ -2,24 +2,17 @@
|
|
|
2
2
|
import { describe, expect, test, beforeEach, jest } from '@jest/globals';
|
|
3
3
|
import EventEmitter from 'events';
|
|
4
4
|
import TuyaDiscovery, { DiscoveryResult } from '../src/local/TuyaDiscovery';
|
|
5
|
+
import { ExLogger, initLogger } from '../src/shared/util/Logger';
|
|
5
6
|
|
|
6
7
|
// Mock Logger
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
},
|
|
16
|
-
PrefixLogger: class PrefixLogger {
|
|
17
|
-
constructor(public log: any, public name: string, public debug: boolean) {}
|
|
18
|
-
info() {}
|
|
19
|
-
warn() {}
|
|
20
|
-
error() {}
|
|
21
|
-
},
|
|
22
|
-
}));
|
|
8
|
+
const mockLog: ExLogger = {
|
|
9
|
+
debug: jest.fn(),
|
|
10
|
+
info: jest.fn(),
|
|
11
|
+
warn: jest.fn(),
|
|
12
|
+
error: jest.fn(),
|
|
13
|
+
log: jest.fn(),
|
|
14
|
+
success: jest.fn(),
|
|
15
|
+
} as unknown as ExLogger;
|
|
23
16
|
|
|
24
17
|
// Mock dgram
|
|
25
18
|
let mockServers: Record<number, EventEmitter> = {};
|
|
@@ -38,17 +31,12 @@ jest.mock('dgram', () => ({
|
|
|
38
31
|
|
|
39
32
|
describe('TuyaDiscovery', () => {
|
|
40
33
|
let discovery: TuyaDiscovery;
|
|
41
|
-
let mockLogger: any;
|
|
42
34
|
|
|
43
35
|
beforeEach(() => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
error: jest.fn(),
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
discovery = new TuyaDiscovery(mockLogger, false);
|
|
36
|
+
jest.clearAllMocks();
|
|
37
|
+
initLogger(mockLog);
|
|
38
|
+
|
|
39
|
+
discovery = new TuyaDiscovery(false);
|
|
52
40
|
});
|
|
53
41
|
|
|
54
42
|
describe('initialization', () => {
|
|
@@ -62,12 +50,12 @@ describe('TuyaDiscovery', () => {
|
|
|
62
50
|
});
|
|
63
51
|
|
|
64
52
|
test('initializes with debug disabled', () => {
|
|
65
|
-
const disc = new TuyaDiscovery(
|
|
53
|
+
const disc = new TuyaDiscovery(false);
|
|
66
54
|
expect(disc).toBeDefined();
|
|
67
55
|
});
|
|
68
56
|
|
|
69
57
|
test('initializes with debug enabled', () => {
|
|
70
|
-
const disc = new TuyaDiscovery(
|
|
58
|
+
const disc = new TuyaDiscovery(true);
|
|
71
59
|
expect(disc).toBeDefined();
|
|
72
60
|
});
|
|
73
61
|
|
|
@@ -361,20 +349,20 @@ describe('TuyaDiscovery', () => {
|
|
|
361
349
|
|
|
362
350
|
describe('logging and debugging', () => {
|
|
363
351
|
test('creates logger with debug disabled', () => {
|
|
364
|
-
const disc = new TuyaDiscovery(
|
|
352
|
+
const disc = new TuyaDiscovery(false);
|
|
365
353
|
expect(disc.log).toBeDefined();
|
|
366
354
|
});
|
|
367
355
|
|
|
368
356
|
test('creates logger with debug enabled', () => {
|
|
369
|
-
const disc = new TuyaDiscovery(
|
|
357
|
+
const disc = new TuyaDiscovery(true);
|
|
370
358
|
expect(disc.log).toBeDefined();
|
|
371
359
|
});
|
|
372
360
|
});
|
|
373
361
|
|
|
374
362
|
describe('multiple discovery instances', () => {
|
|
375
363
|
test('multiple instances maintain separate state', () => {
|
|
376
|
-
const disc1 = new TuyaDiscovery(
|
|
377
|
-
const disc2 = new TuyaDiscovery(
|
|
364
|
+
const disc1 = new TuyaDiscovery(false);
|
|
365
|
+
const disc2 = new TuyaDiscovery(false);
|
|
378
366
|
|
|
379
367
|
disc1['discovered'].set('device_1', '192.168.1.100');
|
|
380
368
|
disc2['discovered'].set('device_2', '192.168.1.101');
|
|
@@ -386,8 +374,8 @@ describe('TuyaDiscovery', () => {
|
|
|
386
374
|
});
|
|
387
375
|
|
|
388
376
|
test('multiple instances have separate servers', () => {
|
|
389
|
-
const disc1 = new TuyaDiscovery(
|
|
390
|
-
const disc2 = new TuyaDiscovery(
|
|
377
|
+
const disc1 = new TuyaDiscovery(false);
|
|
378
|
+
const disc2 = new TuyaDiscovery(false);
|
|
391
379
|
|
|
392
380
|
disc1.start();
|
|
393
381
|
disc2.start();
|
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { describe, expect, test, beforeEach, jest } from '@jest/globals';
|
|
3
3
|
import TuyaHomeDeviceManager from '../src/cloud/device/TuyaHomeDeviceManager';
|
|
4
|
-
import
|
|
4
|
+
import { TuyaPlatformHomeConfig, TuyaPluginMode } from '../src/config';
|
|
5
|
+
import { ExLogger, initLogger } from '../src/shared/util/Logger';
|
|
5
6
|
|
|
6
7
|
// Mock Logger
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
PrefixLogger: class PrefixLogger {
|
|
16
|
-
constructor(public log: any, public name: string, public debug: boolean) {}
|
|
17
|
-
info() {}
|
|
18
|
-
warn() {}
|
|
19
|
-
error() {}
|
|
20
|
-
},
|
|
21
|
-
}));
|
|
8
|
+
const mockLog: ExLogger = {
|
|
9
|
+
debug: jest.fn(),
|
|
10
|
+
info: jest.fn(),
|
|
11
|
+
warn: jest.fn(),
|
|
12
|
+
error: jest.fn(),
|
|
13
|
+
log: jest.fn(),
|
|
14
|
+
success: jest.fn(),
|
|
15
|
+
} as unknown as ExLogger;
|
|
22
16
|
|
|
23
17
|
// Mock TuyaOpenMQ
|
|
24
18
|
jest.mock('../src/cloud/api/TuyaOpenMQ', () => {
|
|
@@ -33,8 +27,11 @@ jest.mock('../src/cloud/api/TuyaOpenMQ', () => {
|
|
|
33
27
|
describe('TuyaHomeDeviceManager', () => {
|
|
34
28
|
let manager: TuyaHomeDeviceManager;
|
|
35
29
|
let mockAPI: any;
|
|
30
|
+
let mockConfig: any;
|
|
36
31
|
|
|
37
32
|
beforeEach(() => {
|
|
33
|
+
jest.clearAllMocks();
|
|
34
|
+
initLogger(mockLog);
|
|
38
35
|
mockAPI = {
|
|
39
36
|
log: { log: console.log } as any,
|
|
40
37
|
post: jest.fn(),
|
|
@@ -42,7 +39,25 @@ describe('TuyaHomeDeviceManager', () => {
|
|
|
42
39
|
tokenInfo: { uid: 'test_uid' },
|
|
43
40
|
};
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
mockConfig = {
|
|
43
|
+
platform: 'TuyaPlatform',
|
|
44
|
+
name: 'Tuya',
|
|
45
|
+
mode: 'cloud',
|
|
46
|
+
cloud: {
|
|
47
|
+
projectType: '2',
|
|
48
|
+
accessId: 'test_id',
|
|
49
|
+
accessKey: 'test_key',
|
|
50
|
+
countryCode: 1,
|
|
51
|
+
username: 'user@example.com',
|
|
52
|
+
password: 'password',
|
|
53
|
+
appSchema: 'tuyaSmart',
|
|
54
|
+
generateWeatherAccessory: false,
|
|
55
|
+
weatherAPI: '',
|
|
56
|
+
forceIPv4: false,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
manager = new TuyaHomeDeviceManager(mockAPI, mockConfig.cloud, false);
|
|
46
61
|
});
|
|
47
62
|
|
|
48
63
|
describe('initialization', () => {
|
|
@@ -57,7 +72,7 @@ describe('TuyaHomeDeviceManager', () => {
|
|
|
57
72
|
});
|
|
58
73
|
|
|
59
74
|
test('supports debug mode', () => {
|
|
60
|
-
const debugManager = new TuyaHomeDeviceManager(mockAPI, true);
|
|
75
|
+
const debugManager = new TuyaHomeDeviceManager(mockAPI, mockConfig.cloud, true);
|
|
61
76
|
expect(debugManager.debug).toBe(true);
|
|
62
77
|
});
|
|
63
78
|
|
|
@@ -537,4 +552,80 @@ describe('TuyaHomeDeviceManager', () => {
|
|
|
537
552
|
}
|
|
538
553
|
});
|
|
539
554
|
});
|
|
555
|
+
|
|
556
|
+
describe('get device config', () => {
|
|
557
|
+
test('resolves device config precedence: device, then product, then global', () => {
|
|
558
|
+
const config = {
|
|
559
|
+
platform: 'TuyaPlatform',
|
|
560
|
+
name: 'Tuya',
|
|
561
|
+
mode: 'cloud',
|
|
562
|
+
cloud: {
|
|
563
|
+
projectType: '2',
|
|
564
|
+
accessId: 'id',
|
|
565
|
+
accessKey: 'key',
|
|
566
|
+
countryCode: 1,
|
|
567
|
+
username: 'user@example.com',
|
|
568
|
+
password: 'secret',
|
|
569
|
+
appSchema: 'tuyaSmart',
|
|
570
|
+
generateWeatherAccessory: false,
|
|
571
|
+
weatherAPI: '',
|
|
572
|
+
deviceOverrides: [
|
|
573
|
+
{ id: 'global', category: 'global-cat', configFor: TuyaPluginMode.cloud },
|
|
574
|
+
{ id: 'prod-1', category: 'product-cat', configFor: TuyaPluginMode.cloud },
|
|
575
|
+
{ id: 'device-1', category: 'device-cat', configFor: TuyaPluginMode.cloud },
|
|
576
|
+
],
|
|
577
|
+
} as TuyaPlatformHomeConfig,
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
const deviceManager = new TuyaHomeDeviceManager(mockAPI, config.cloud, false);
|
|
581
|
+
|
|
582
|
+
const exact = deviceManager.getDeviceConfig({ id: 'device-1', uuid: 'uuid-1', product_id: 'prod-1' } as any);
|
|
583
|
+
const byProduct = deviceManager.getDeviceConfig({ id: 'device-2', uuid: 'uuid-2', product_id: 'prod-1' } as any);
|
|
584
|
+
const fallback = deviceManager.getDeviceConfig({ id: 'device-3', uuid: 'uuid-3', product_id: 'prod-3' } as any);
|
|
585
|
+
|
|
586
|
+
expect(exact?.category).toBe('device-cat');
|
|
587
|
+
expect(byProduct?.category).toBe('product-cat');
|
|
588
|
+
expect(fallback?.category).toBe('global-cat');
|
|
589
|
+
});
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
describe('get device config', () => {
|
|
593
|
+
test('finds schema config case-insensitively', () => {
|
|
594
|
+
const config = {
|
|
595
|
+
platform: 'TuyaPlatform',
|
|
596
|
+
name: 'Tuya',
|
|
597
|
+
mode: 'cloud',
|
|
598
|
+
cloud: {
|
|
599
|
+
projectType: '2',
|
|
600
|
+
accessId: 'id',
|
|
601
|
+
accessKey: 'key',
|
|
602
|
+
countryCode: 1,
|
|
603
|
+
username: 'user@example.com',
|
|
604
|
+
password: 'secret',
|
|
605
|
+
appSchema: 'tuyaSmart',
|
|
606
|
+
generateWeatherAccessory: false,
|
|
607
|
+
weatherAPI: '',
|
|
608
|
+
deviceOverrides: [
|
|
609
|
+
{
|
|
610
|
+
id: 'device-1',
|
|
611
|
+
schema: [
|
|
612
|
+
{ code: 'switch_1', newCode: 'new_switch_1', hidden: true },
|
|
613
|
+
],
|
|
614
|
+
configFor: TuyaPluginMode.cloud
|
|
615
|
+
},
|
|
616
|
+
],
|
|
617
|
+
} as TuyaPlatformHomeConfig,
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
const device = { id: 'device-1', uuid: 'device-1', product_id: 'prod-1' } as any;
|
|
621
|
+
|
|
622
|
+
const deviceManager = new TuyaHomeDeviceManager(mockAPI, config.cloud, false);
|
|
623
|
+
const result = deviceManager!.getDeviceSchemaConfig(device, 'SWITCH_1');
|
|
624
|
+
|
|
625
|
+
expect(result).toBeDefined();
|
|
626
|
+
expect(result?.code).toBe('switch_1');
|
|
627
|
+
expect((result as any).newCode).toBe('new_switch_1');
|
|
628
|
+
expect(result?.hidden).toBe(true);
|
|
629
|
+
});
|
|
630
|
+
});
|
|
540
631
|
});
|
package/test/tuyaOpenAPI.test.ts
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { describe, expect, test, beforeEach, jest } from '@jest/globals';
|
|
3
3
|
import TuyaOpenAPI, { TuyaOpenAPIResponse } from '../src/cloud/api/TuyaOpenAPI';
|
|
4
|
+
import { ExLogger, initLogger } from '../src/shared/util/Logger';
|
|
4
5
|
|
|
5
6
|
// Mock Logger
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
PrefixLogger: class PrefixLogger {
|
|
15
|
-
constructor(public log: any, public name: string, public debug: boolean) {}
|
|
16
|
-
},
|
|
17
|
-
}));
|
|
7
|
+
const mockLog: ExLogger = {
|
|
8
|
+
debug: jest.fn(),
|
|
9
|
+
info: jest.fn(),
|
|
10
|
+
warn: jest.fn(),
|
|
11
|
+
error: jest.fn(),
|
|
12
|
+
log: jest.fn(),
|
|
13
|
+
success: jest.fn(),
|
|
14
|
+
} as unknown as ExLogger;
|
|
18
15
|
|
|
19
16
|
// Mock https module
|
|
20
17
|
jest.mock('https', () => ({
|
|
21
18
|
request: jest.fn(),
|
|
19
|
+
Agent: jest.fn(),
|
|
22
20
|
}));
|
|
23
21
|
|
|
24
22
|
// Mock util
|
|
@@ -32,18 +30,12 @@ describe('TuyaOpenAPI', () => {
|
|
|
32
30
|
let mockLogger: any;
|
|
33
31
|
|
|
34
32
|
beforeEach(() => {
|
|
35
|
-
|
|
36
|
-
log: jest.fn(),
|
|
37
|
-
info: jest.fn(),
|
|
38
|
-
warn: jest.fn(),
|
|
39
|
-
error: jest.fn(),
|
|
40
|
-
};
|
|
33
|
+
initLogger(mockLog);
|
|
41
34
|
|
|
42
35
|
api = new TuyaOpenAPI(
|
|
43
36
|
TuyaOpenAPI.Endpoints.AMERICA,
|
|
44
37
|
'test_access_id',
|
|
45
38
|
'test_access_key',
|
|
46
|
-
mockLogger,
|
|
47
39
|
'en',
|
|
48
40
|
false
|
|
49
41
|
);
|
|
@@ -88,7 +80,8 @@ describe('TuyaOpenAPI', () => {
|
|
|
88
80
|
});
|
|
89
81
|
|
|
90
82
|
test('creates logger with API name', () => {
|
|
91
|
-
expect(api
|
|
83
|
+
expect(api['log']).toBeDefined();
|
|
84
|
+
expect((api['log'] as any)['prefix']).toEqual('TuyaOpenAPI');
|
|
92
85
|
});
|
|
93
86
|
});
|
|
94
87
|
|
|
@@ -150,8 +143,7 @@ describe('TuyaOpenAPI', () => {
|
|
|
150
143
|
const testApi = new TuyaOpenAPI(
|
|
151
144
|
TuyaOpenAPI.Endpoints.AMERICA,
|
|
152
145
|
'my_access_id',
|
|
153
|
-
'my_access_key'
|
|
154
|
-
mockLogger
|
|
146
|
+
'my_access_key'
|
|
155
147
|
);
|
|
156
148
|
expect(testApi.accessId).toBe('my_access_id');
|
|
157
149
|
});
|
|
@@ -160,8 +152,7 @@ describe('TuyaOpenAPI', () => {
|
|
|
160
152
|
const testApi = new TuyaOpenAPI(
|
|
161
153
|
TuyaOpenAPI.Endpoints.AMERICA,
|
|
162
154
|
'my_access_id',
|
|
163
|
-
'my_access_key'
|
|
164
|
-
mockLogger
|
|
155
|
+
'my_access_key'
|
|
165
156
|
);
|
|
166
157
|
expect(testApi.accessKey).toBe('my_access_key');
|
|
167
158
|
});
|
|
@@ -170,14 +161,12 @@ describe('TuyaOpenAPI', () => {
|
|
|
170
161
|
const api1 = new TuyaOpenAPI(
|
|
171
162
|
TuyaOpenAPI.Endpoints.AMERICA,
|
|
172
163
|
'id1',
|
|
173
|
-
'key1'
|
|
174
|
-
mockLogger
|
|
164
|
+
'key1'
|
|
175
165
|
);
|
|
176
166
|
const api2 = new TuyaOpenAPI(
|
|
177
167
|
TuyaOpenAPI.Endpoints.AMERICA,
|
|
178
168
|
'id2',
|
|
179
|
-
'key2'
|
|
180
|
-
mockLogger
|
|
169
|
+
'key2'
|
|
181
170
|
);
|
|
182
171
|
|
|
183
172
|
expect(api1.accessId).not.toBe(api2.accessId);
|
|
@@ -261,8 +250,7 @@ describe('TuyaOpenAPI', () => {
|
|
|
261
250
|
const apiEU = new TuyaOpenAPI(
|
|
262
251
|
TuyaOpenAPI.Endpoints.EUROPE,
|
|
263
252
|
'id',
|
|
264
|
-
'key'
|
|
265
|
-
mockLogger
|
|
253
|
+
'key'
|
|
266
254
|
);
|
|
267
255
|
expect(apiEU.endpoint).toBe(TuyaOpenAPI.Endpoints.EUROPE);
|
|
268
256
|
});
|
|
@@ -272,8 +260,7 @@ describe('TuyaOpenAPI', () => {
|
|
|
272
260
|
TuyaOpenAPI.Endpoints.CHINA,
|
|
273
261
|
'id',
|
|
274
262
|
'key',
|
|
275
|
-
|
|
276
|
-
'zh'
|
|
263
|
+
'zh',
|
|
277
264
|
);
|
|
278
265
|
expect(apiZH.lang).toBe('zh');
|
|
279
266
|
});
|
|
@@ -282,8 +269,7 @@ describe('TuyaOpenAPI', () => {
|
|
|
282
269
|
const apiDefault = new TuyaOpenAPI(
|
|
283
270
|
TuyaOpenAPI.Endpoints.AMERICA,
|
|
284
271
|
'id',
|
|
285
|
-
'key'
|
|
286
|
-
mockLogger
|
|
272
|
+
'key'
|
|
287
273
|
);
|
|
288
274
|
expect(apiDefault.lang).toBe('en');
|
|
289
275
|
});
|
|
@@ -293,9 +279,8 @@ describe('TuyaOpenAPI', () => {
|
|
|
293
279
|
TuyaOpenAPI.Endpoints.AMERICA,
|
|
294
280
|
'id',
|
|
295
281
|
'key',
|
|
296
|
-
mockLogger,
|
|
297
282
|
'en',
|
|
298
|
-
true
|
|
283
|
+
true,
|
|
299
284
|
);
|
|
300
285
|
expect(apiDebug.debug).toBe(true);
|
|
301
286
|
});
|
|
@@ -306,14 +291,12 @@ describe('TuyaOpenAPI', () => {
|
|
|
306
291
|
const api1 = new TuyaOpenAPI(
|
|
307
292
|
TuyaOpenAPI.Endpoints.AMERICA,
|
|
308
293
|
'id1',
|
|
309
|
-
'key1'
|
|
310
|
-
mockLogger
|
|
294
|
+
'key1'
|
|
311
295
|
);
|
|
312
296
|
const api2 = new TuyaOpenAPI(
|
|
313
297
|
TuyaOpenAPI.Endpoints.EUROPE,
|
|
314
298
|
'id2',
|
|
315
|
-
'key2'
|
|
316
|
-
mockLogger
|
|
299
|
+
'key2'
|
|
317
300
|
);
|
|
318
301
|
|
|
319
302
|
api1.assetIDArr.push('asset_1');
|
|
@@ -328,14 +311,12 @@ describe('TuyaOpenAPI', () => {
|
|
|
328
311
|
const api1 = new TuyaOpenAPI(
|
|
329
312
|
TuyaOpenAPI.Endpoints.AMERICA,
|
|
330
313
|
'id1',
|
|
331
|
-
'key1'
|
|
332
|
-
mockLogger
|
|
314
|
+
'key1'
|
|
333
315
|
);
|
|
334
316
|
const api2 = new TuyaOpenAPI(
|
|
335
317
|
TuyaOpenAPI.Endpoints.EUROPE,
|
|
336
318
|
'id2',
|
|
337
|
-
'key2'
|
|
338
|
-
mockLogger
|
|
319
|
+
'key2'
|
|
339
320
|
);
|
|
340
321
|
|
|
341
322
|
api1.deviceArr = [{ id: 'dev1' }];
|
package/test/tuyaOpenMQ.test.ts
CHANGED
|
@@ -7,24 +7,14 @@ jest.mock('mqtt', () => ({
|
|
|
7
7
|
}));
|
|
8
8
|
|
|
9
9
|
// Mock Logger
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
},
|
|
19
|
-
PrefixLogger: class PrefixLogger {
|
|
20
|
-
log = jest.fn();
|
|
21
|
-
info = jest.fn();
|
|
22
|
-
warn = jest.fn();
|
|
23
|
-
error = jest.fn();
|
|
24
|
-
debug = jest.fn();
|
|
25
|
-
constructor(public logger: any, public name: string, public isDebug: boolean) {}
|
|
26
|
-
},
|
|
27
|
-
}));
|
|
10
|
+
const mockLog: ExLogger = {
|
|
11
|
+
debug: jest.fn(),
|
|
12
|
+
info: jest.fn(),
|
|
13
|
+
warn: jest.fn(),
|
|
14
|
+
error: jest.fn(),
|
|
15
|
+
log: jest.fn(),
|
|
16
|
+
success: jest.fn(),
|
|
17
|
+
} as unknown as ExLogger;
|
|
28
18
|
|
|
29
19
|
// Mock util
|
|
30
20
|
jest.mock('../src/shared/util/util', () => ({
|
|
@@ -38,6 +28,7 @@ jest.mock('../src/cloud/device/TuyaDevice', () => ({
|
|
|
38
28
|
|
|
39
29
|
import TuyaOpenMQ from '../src/cloud/api/TuyaOpenMQ';
|
|
40
30
|
import mqtt from 'mqtt';
|
|
31
|
+
import { ExLogger, initLogger } from '../src/shared/util/Logger';
|
|
41
32
|
|
|
42
33
|
describe('TuyaOpenMQ', () => {
|
|
43
34
|
let mq: TuyaOpenMQ;
|
|
@@ -46,6 +37,7 @@ describe('TuyaOpenMQ', () => {
|
|
|
46
37
|
|
|
47
38
|
beforeEach(() => {
|
|
48
39
|
jest.clearAllMocks();
|
|
40
|
+
initLogger(mockLog);
|
|
49
41
|
|
|
50
42
|
// Create mock MQTT client
|
|
51
43
|
mockClient = {
|
|
@@ -64,7 +56,7 @@ describe('TuyaOpenMQ', () => {
|
|
|
64
56
|
post: jest.fn(),
|
|
65
57
|
} as any;
|
|
66
58
|
|
|
67
|
-
mq = new TuyaOpenMQ(mockAPI,
|
|
59
|
+
mq = new TuyaOpenMQ(mockAPI, false);
|
|
68
60
|
});
|
|
69
61
|
|
|
70
62
|
describe('initialization', () => {
|
|
@@ -274,18 +266,18 @@ describe('TuyaOpenMQ', () => {
|
|
|
274
266
|
});
|
|
275
267
|
|
|
276
268
|
test('debug flag can be true', () => {
|
|
277
|
-
const debugMQ = new TuyaOpenMQ(mockAPI,
|
|
269
|
+
const debugMQ = new TuyaOpenMQ(mockAPI, true);
|
|
278
270
|
expect(debugMQ.debug).toBe(true);
|
|
279
271
|
});
|
|
280
272
|
|
|
281
273
|
test('debug flag can be false', () => {
|
|
282
|
-
const noDebugMQ = new TuyaOpenMQ(mockAPI,
|
|
274
|
+
const noDebugMQ = new TuyaOpenMQ(mockAPI, false);
|
|
283
275
|
expect(noDebugMQ.debug).toBe(false);
|
|
284
276
|
});
|
|
285
277
|
|
|
286
278
|
test('link ID is unique between instances', () => {
|
|
287
|
-
const mq1 = new TuyaOpenMQ(mockAPI,
|
|
288
|
-
const mq2 = new TuyaOpenMQ(mockAPI,
|
|
279
|
+
const mq1 = new TuyaOpenMQ(mockAPI, false);
|
|
280
|
+
const mq2 = new TuyaOpenMQ(mockAPI, false);
|
|
289
281
|
|
|
290
282
|
expect(mq1.linkId).toBeDefined();
|
|
291
283
|
expect(mq2.linkId).toBeDefined();
|
package/test/util.test.ts
CHANGED
|
@@ -1,30 +1,49 @@
|
|
|
1
|
-
import { describe, expect, test } from '@jest/globals';
|
|
1
|
+
import { describe, expect, jest, test } from '@jest/globals';
|
|
2
2
|
import {
|
|
3
3
|
sanitizeName,
|
|
4
4
|
remap,
|
|
5
5
|
limit,
|
|
6
6
|
deepEqual,
|
|
7
|
+
deepClone,
|
|
7
8
|
debounce,
|
|
8
9
|
toHapProperty,
|
|
10
|
+
createDelegate,
|
|
9
11
|
} from '../src/shared/util/util';
|
|
10
12
|
import { TuyaDeviceSchemaProperty } from '../src/cloud/device/TuyaDevice';
|
|
11
13
|
|
|
14
|
+
// based on https://github.com/homebridge/HAP-NodeJS/blob/843453605a949f50e2e26aa7ab74364edcd8137d/src/lib/util/checkName.ts#L23
|
|
15
|
+
function isValidName(value: any) {
|
|
16
|
+
if (
|
|
17
|
+
typeof value === "string" &&
|
|
18
|
+
!/^[\p{L}\p{N}][\p{L}\p{N}\p{Zs}\u2019'&!._:;()/,-]*[\p{L}\p{N}]$/u.test(value)
|
|
19
|
+
) {
|
|
20
|
+
return false;
|
|
21
|
+
} else {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
12
26
|
describe('sanitizeName', () => {
|
|
13
27
|
test('removes underscores and collapses to spaces', () => {
|
|
14
28
|
expect(sanitizeName('switch_1')).toBe('switch 1');
|
|
29
|
+
expect(isValidName(sanitizeName('switch_1'))).toBe(true);
|
|
15
30
|
});
|
|
16
31
|
|
|
17
32
|
test('preserves ASCII alphanumeric and apostrophes', () => {
|
|
18
33
|
expect(sanitizeName("John's Lamp")).toBe("John's Lamp");
|
|
34
|
+
expect(isValidName(sanitizeName("John's Lamp"))).toBe(true);
|
|
19
35
|
});
|
|
20
36
|
|
|
21
37
|
test('preserves accented and non-Latin letters (Unicode letters)', () => {
|
|
22
38
|
expect(sanitizeName('Café')).toBe('Café');
|
|
23
39
|
expect(sanitizeName('Тест123')).toBe('Тест123');
|
|
40
|
+
expect(isValidName(sanitizeName('Café'))).toBe(true);
|
|
41
|
+
expect(isValidName(sanitizeName('Тест123'))).toBe(true);
|
|
24
42
|
});
|
|
25
43
|
|
|
26
44
|
test('preserves CJK characters', () => {
|
|
27
45
|
expect(sanitizeName('中文测试')).toBe('中文测试');
|
|
46
|
+
expect(isValidName(sanitizeName('中文测试'))).toBe(true);
|
|
28
47
|
});
|
|
29
48
|
|
|
30
49
|
test('returns undefined if sanitized name is empty or invalid', () => {
|
|
@@ -40,25 +59,29 @@ describe('sanitizeName', () => {
|
|
|
40
59
|
test('handles mixed content correctly', () => {
|
|
41
60
|
expect(sanitizeName('device_123_name')).toBe('device 123 name');
|
|
42
61
|
expect(sanitizeName('My-Device-Name')).toBe('My Device Name');
|
|
62
|
+
expect(isValidName(sanitizeName('device_123_name'))).toBe(true);
|
|
63
|
+
expect(isValidName(sanitizeName('My-Device-Name'))).toBe(true);
|
|
43
64
|
});
|
|
44
65
|
|
|
45
66
|
test('collapses multiple consecutive spaces', () => {
|
|
46
67
|
expect(sanitizeName('name with spaces')).toBe('name with spaces');
|
|
68
|
+
expect(isValidName(sanitizeName('name with spaces'))).toBe(true);
|
|
47
69
|
});
|
|
48
70
|
|
|
49
71
|
test('trims leading and trailing spaces', () => {
|
|
50
72
|
expect(sanitizeName(' My Device ')).toBe('My Device');
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
test('rejects names that start or end with non-alphanumeric', () => {
|
|
54
|
-
expect(sanitizeName('_device')).toBeUndefined();
|
|
55
|
-
expect(sanitizeName('device_')).toBeUndefined();
|
|
56
|
-
expect(sanitizeName('_device_')).toBeUndefined();
|
|
73
|
+
expect(isValidName(sanitizeName(' My Device '))).toBe(true);
|
|
57
74
|
});
|
|
58
75
|
|
|
59
76
|
test('handles single character names', () => {
|
|
60
77
|
expect(sanitizeName('A')).toBeUndefined(); // Single char fails the regex
|
|
61
78
|
expect(sanitizeName('AB')).toBe('AB');
|
|
79
|
+
expect(isValidName(sanitizeName('AB'))).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('name with braces', () => {
|
|
83
|
+
expect(sanitizeName('AB(C)')).toBe('AB C');
|
|
84
|
+
expect(isValidName(sanitizeName('AB(C)'))).toBe(true);
|
|
62
85
|
});
|
|
63
86
|
});
|
|
64
87
|
|
|
@@ -170,6 +193,25 @@ describe('deepEqual', () => {
|
|
|
170
193
|
});
|
|
171
194
|
});
|
|
172
195
|
|
|
196
|
+
describe('deepClone', () => {
|
|
197
|
+
test('clones nested objects and arrays', () => {
|
|
198
|
+
const value = { a: 1, b: { c: [2, 3] } };
|
|
199
|
+
const cloned = deepClone(value);
|
|
200
|
+
|
|
201
|
+
expect(cloned).toEqual(value);
|
|
202
|
+
expect(cloned).not.toBe(value);
|
|
203
|
+
expect(cloned.b).not.toBe(value.b);
|
|
204
|
+
expect(cloned.b.c).not.toBe(value.b.c);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('preserves primitives and null', () => {
|
|
208
|
+
expect(deepClone('test')).toBe('test');
|
|
209
|
+
expect(deepClone(42)).toBe(42);
|
|
210
|
+
expect(deepClone(null)).toBeNull();
|
|
211
|
+
expect(deepClone(undefined)).toBeUndefined();
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
173
215
|
describe('debounce', () => {
|
|
174
216
|
test('debounces function execution', (done) => {
|
|
175
217
|
let callCount = 0;
|
|
@@ -316,3 +358,61 @@ describe('toHapProperty', () => {
|
|
|
316
358
|
expect(typeof result).toBe('object');
|
|
317
359
|
});
|
|
318
360
|
});
|
|
361
|
+
|
|
362
|
+
class DelegateTargetClass {
|
|
363
|
+
do(x: number): number;
|
|
364
|
+
do(x: number, y: number): number;
|
|
365
|
+
do(x: any, y?: any): any {
|
|
366
|
+
if (y === undefined) {
|
|
367
|
+
return `original1:${x}`;
|
|
368
|
+
}
|
|
369
|
+
return `original2:${x},${y}`;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
describe("createDelegate with overloaded methods (different arg count)", () => {
|
|
373
|
+
test("overrides both overload signatures", () => {
|
|
374
|
+
const worker = new DelegateTargetClass();
|
|
375
|
+
|
|
376
|
+
const delegate = createDelegate(worker, {
|
|
377
|
+
do: ((original: any) => (...args: any[]) => {
|
|
378
|
+
return `override:${args.join(",")}`;
|
|
379
|
+
}) as any,
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
expect(delegate.do(10)).toBe("override:10");
|
|
383
|
+
expect(delegate.do(10, 20)).toBe("override:10,20");
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
test("overrides only the single-argument overload and delegates the two-argument overload", () => {
|
|
387
|
+
const worker = new DelegateTargetClass();
|
|
388
|
+
|
|
389
|
+
const delegate = createDelegate(worker, {
|
|
390
|
+
do: ((original: any) => (...args: any[]) => {
|
|
391
|
+
if (args.length === 1) {
|
|
392
|
+
return `override1:${args[0]}`;
|
|
393
|
+
}
|
|
394
|
+
return original(...args);
|
|
395
|
+
}) as any,
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
expect(delegate.do(10)).toBe("override1:10");
|
|
399
|
+
expect(delegate.do(10, 20)).toBe("original2:10,20");
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
test("overrides only the two-argument overload and delegates the single-argument overload", () => {
|
|
403
|
+
const worker = new DelegateTargetClass();
|
|
404
|
+
|
|
405
|
+
const delegate = createDelegate(worker, {
|
|
406
|
+
do: ((original: any) => (...args: any[]) => {
|
|
407
|
+
if (args.length === 2) {
|
|
408
|
+
return `override2:${args[0]},${args[1]}`;
|
|
409
|
+
}
|
|
410
|
+
return original(...args);
|
|
411
|
+
}) as any,
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
expect(delegate.do(10)).toBe("original1:10");
|
|
415
|
+
expect(delegate.do(10, 20)).toBe("override2:10,20");
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
});
|