@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
|
@@ -37,14 +37,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
const TuyaDevice_1 = __importStar(require("../cloud/device/TuyaDevice"));
|
|
40
|
-
const
|
|
41
|
-
const TuyaDeviceManager_1 = __importDefault(require("../cloud/device/TuyaDeviceManager"));
|
|
40
|
+
const TuyaDeviceManager_1 = __importDefault(require("../shared/TuyaDeviceManager"));
|
|
42
41
|
const TuyaDiscovery_1 = __importDefault(require("./TuyaDiscovery"));
|
|
43
42
|
const LocalDevice_1 = __importDefault(require("./LocalDevice"));
|
|
44
|
-
const Logger_1 = require("../shared/util/Logger");
|
|
45
43
|
const ConfigHash_1 = require("../shared/util/ConfigHash");
|
|
46
44
|
const ZigbeeGatewayDetection_1 = require("./ZigbeeGatewayDetection");
|
|
47
45
|
const DynamicChildDiscovery_1 = require("./DynamicChildDiscovery");
|
|
46
|
+
const config_1 = require("../config");
|
|
48
47
|
/**
|
|
49
48
|
* Default DP-to-code mapping used when the user hasn't supplied one.
|
|
50
49
|
* Keys are Tuya standard instruction codes; values are typical DP numbers.
|
|
@@ -92,12 +91,8 @@ function buildDpToCodeMap(dpMapping) {
|
|
|
92
91
|
*/
|
|
93
92
|
class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
94
93
|
// ──────────────────────────────────────────────────────────────────────────
|
|
95
|
-
constructor(localConfig,
|
|
96
|
-
|
|
97
|
-
const dummyLog = new Logger_1.PrefixLogger(log, 'LocalDummy', false);
|
|
98
|
-
const dummyApi = new TuyaOpenAPI_1.default('', '', '', dummyLog);
|
|
99
|
-
super(dummyApi, false);
|
|
100
|
-
this.localDevices = [];
|
|
94
|
+
constructor(localConfig, debugMode = false) {
|
|
95
|
+
super(debugMode);
|
|
101
96
|
this.localConnections = new Map();
|
|
102
97
|
this.discoveryTimeout = null;
|
|
103
98
|
this.rediscoveryTimeout = null;
|
|
@@ -113,20 +108,96 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
113
108
|
this.discoveredVersions = new Map();
|
|
114
109
|
// Pending local response watches to cancel superseded commands
|
|
115
110
|
this.pendingLocalResponseWatchers = new Map();
|
|
116
|
-
// Tracks which devices had config changes
|
|
117
|
-
this.configChanged = new Map();
|
|
118
111
|
// ── Zigbee gateway/child support ──────────────────────────────────────────
|
|
119
112
|
/** Parent gateway ID → GatewayRelationship (derived from config at init). */
|
|
120
113
|
this.gatewayRelationships = new Map();
|
|
121
114
|
/** Parent gateway device ID → its active LocalDevice connection. */
|
|
122
115
|
this.gatewayConnections = new Map();
|
|
123
|
-
// Stop the MQ that the parent started
|
|
124
|
-
this.mq.stop();
|
|
125
|
-
this.parentLog = log;
|
|
126
|
-
this.log = new Logger_1.PrefixLogger(log, 'LocalDeviceManager', false);
|
|
127
116
|
this.config = localConfig;
|
|
128
|
-
this.discovery = new TuyaDiscovery_1.default(
|
|
129
|
-
|
|
117
|
+
this.discovery = new TuyaDiscovery_1.default();
|
|
118
|
+
}
|
|
119
|
+
async pullDevices() {
|
|
120
|
+
await this.initLocalDevices();
|
|
121
|
+
this.connectAllDevices();
|
|
122
|
+
const devices = [...this.devices];
|
|
123
|
+
this.log.info(`Registered ${devices.length} local device(s).`);
|
|
124
|
+
return devices;
|
|
125
|
+
}
|
|
126
|
+
createDeviceConfigHash(device) {
|
|
127
|
+
const cfg = this.config.devices?.find(config => config.tuyaDeviceId === device.id);
|
|
128
|
+
if (!cfg) {
|
|
129
|
+
return '';
|
|
130
|
+
}
|
|
131
|
+
const effectiveSwitchCount = this._getEffectiveSwitchCount(cfg, device);
|
|
132
|
+
// Check if config has changed since last run
|
|
133
|
+
// Hash the config fields that affect device behavior
|
|
134
|
+
const configToHash = {
|
|
135
|
+
tuyaDeviceId: cfg.tuyaDeviceId,
|
|
136
|
+
name: cfg.name,
|
|
137
|
+
tuyaKey: cfg.tuyaKey,
|
|
138
|
+
dpMapping: this._getDPMap(cfg.tuyaDeviceId),
|
|
139
|
+
switchCount: effectiveSwitchCount,
|
|
140
|
+
outletCount: effectiveSwitchCount,
|
|
141
|
+
protocolVersion: cfg.protocolVersion,
|
|
142
|
+
category: cfg.category,
|
|
143
|
+
};
|
|
144
|
+
return ConfigHash_1.ConfigHash.computeHash(configToHash);
|
|
145
|
+
}
|
|
146
|
+
configDevice(device) {
|
|
147
|
+
const deviceConfig = this.getDeviceConfig(device);
|
|
148
|
+
if (deviceConfig?.category) {
|
|
149
|
+
this.log.warn('Override %o category from %o to %o', device.name, device.category, deviceConfig.category);
|
|
150
|
+
device.category = deviceConfig.category;
|
|
151
|
+
}
|
|
152
|
+
if (deviceConfig?.unbridged) {
|
|
153
|
+
this.log.warn('Unbridge %o category %o', device.name, device.category);
|
|
154
|
+
device.unbridged = deviceConfig.unbridged;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
getDeviceSchemaConfig(device, dpCode) {
|
|
158
|
+
const schema = this.getDeviceConfig(device)?.schema;
|
|
159
|
+
if (!schema || !dpCode) {
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
// ignore case - allow both the device code and its (optional) rename
|
|
163
|
+
const target = dpCode.toString().toLowerCase();
|
|
164
|
+
return schema.find(s => {
|
|
165
|
+
const code = s.code?.toString().toLowerCase();
|
|
166
|
+
const newCode = s.newCode?.toString().toLowerCase();
|
|
167
|
+
return code === target || newCode === target;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
enableGarageDoorUseContactSensorForState(device) {
|
|
171
|
+
return this.getDeviceConfig(device)?.garageDoorUseContactSensorForState === true;
|
|
172
|
+
}
|
|
173
|
+
async retrieveDeviceRTSP(deviceID) {
|
|
174
|
+
const cameraConfig = this.config.cameras?.find(cameraConfig => cameraConfig.deviceId === deviceID);
|
|
175
|
+
if (cameraConfig) {
|
|
176
|
+
const rtspUrl = cameraConfig.rtspUrl;
|
|
177
|
+
if (rtspUrl.includes('@') || !cameraConfig.username) {
|
|
178
|
+
return rtspUrl;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
return `rtsp://${cameraConfig.username}:${cameraConfig.password}@${rtspUrl.substring('rtsp://'.length)}`;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return '';
|
|
185
|
+
}
|
|
186
|
+
getDeviceConfig(device) {
|
|
187
|
+
if (!this.config) {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
// Find matching override, respecting source filtering
|
|
191
|
+
const matches = this.config.deviceOverrides?.filter(config => {
|
|
192
|
+
const sourceMatch = [config_1.TuyaPluginMode.local, config_1.TuyaPluginMode.both].includes(config.configFor);
|
|
193
|
+
const idMatch = config.id === device.id || config.id === device.uuid ||
|
|
194
|
+
config.id === device.product_id || config.id === 'global';
|
|
195
|
+
return sourceMatch && idMatch;
|
|
196
|
+
}) ?? [];
|
|
197
|
+
// Return device-specific config, then product, then global
|
|
198
|
+
return matches.find(config => config.id === device.id || config.id === device.uuid) ||
|
|
199
|
+
matches.find(config => config.id === device.product_id) ||
|
|
200
|
+
matches.find(config => config.id === 'global');
|
|
130
201
|
}
|
|
131
202
|
/**
|
|
132
203
|
* Initialise discovery and register manually configured devices.
|
|
@@ -134,9 +205,10 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
134
205
|
*/
|
|
135
206
|
async initLocalDevices() {
|
|
136
207
|
// ── Zigbee: detect parent-child relationships before registering devices ──
|
|
137
|
-
|
|
208
|
+
const zigbeeDevices = this.config.devices?.filter(ZigbeeGatewayDetection_1.ZigbeeGatewayDetection.isZigbeeDevice);
|
|
209
|
+
if (zigbeeDevices && zigbeeDevices.length > 0) {
|
|
138
210
|
try {
|
|
139
|
-
this.gatewayRelationships = ZigbeeGatewayDetection_1.ZigbeeGatewayDetection.detectFromDevices(
|
|
211
|
+
this.gatewayRelationships = ZigbeeGatewayDetection_1.ZigbeeGatewayDetection.detectFromDevices(zigbeeDevices);
|
|
140
212
|
if (this.gatewayRelationships.size > 0) {
|
|
141
213
|
for (const [parentId, rel] of this.gatewayRelationships) {
|
|
142
214
|
this.log.info(`Zigbee gateway detected: ${parentId} has ${rel.children.length} sub-device(s): ` +
|
|
@@ -157,10 +229,13 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
157
229
|
if (ZigbeeGatewayDetection_1.ZigbeeGatewayDetection.isChild(cfg)) {
|
|
158
230
|
continue;
|
|
159
231
|
}
|
|
160
|
-
this._registerDeviceConfig(cfg);
|
|
232
|
+
const device = this._registerDeviceConfig(cfg);
|
|
233
|
+
if (!!device) {
|
|
234
|
+
this._syncSubDevices(device);
|
|
235
|
+
}
|
|
161
236
|
}
|
|
162
237
|
// Validate devices have keys if auto-discovery is disabled
|
|
163
|
-
if (this.config.autoDiscoverDevices
|
|
238
|
+
if (!this.config.autoDiscoverDevices) {
|
|
164
239
|
for (const cfg of this.config.devices) {
|
|
165
240
|
if (!cfg.tuyaKey && !ZigbeeGatewayDetection_1.ZigbeeGatewayDetection.isChild(cfg)) {
|
|
166
241
|
const deviceName = cfg.name || cfg.tuyaDeviceId;
|
|
@@ -172,7 +247,7 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
172
247
|
}
|
|
173
248
|
// Start UDP discovery unless explicitly disabled
|
|
174
249
|
if (this.config.autoDiscoverDevices !== false) {
|
|
175
|
-
this.discovery.on(
|
|
250
|
+
this.discovery.on(TuyaDiscovery_1.default.Events.DEVICE_DISCOVER, (result) => {
|
|
176
251
|
this._onDiscovered(result);
|
|
177
252
|
});
|
|
178
253
|
this._startDiscoveryPhase();
|
|
@@ -185,6 +260,59 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
185
260
|
}
|
|
186
261
|
}
|
|
187
262
|
}
|
|
263
|
+
/** sync connection info for sub devices */
|
|
264
|
+
_syncSubDevices(device) {
|
|
265
|
+
// We assume cases where only the parent device has settings and the sub‑device has none, as well as the opposite situation.
|
|
266
|
+
// or maybe a possibility that some cases may still be undetected.
|
|
267
|
+
if (device.sub) {
|
|
268
|
+
const parentDevice = this.devices.find(d => d.id === device.parent_id);
|
|
269
|
+
if (parentDevice) {
|
|
270
|
+
this._syncConnectionInfo(parentDevice, device);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
const dummyParentDevice = this._buildDiscoveredDevice({
|
|
274
|
+
id: device.parent_id,
|
|
275
|
+
ip: '',
|
|
276
|
+
version: '',
|
|
277
|
+
});
|
|
278
|
+
this._syncConnectionInfo(dummyParentDevice, device);
|
|
279
|
+
this.devices.push(dummyParentDevice);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
const subDevices = this.devices.filter(d => d.sub && d.parent_id === device.id);
|
|
284
|
+
subDevices.forEach(subDevice => {
|
|
285
|
+
this._syncConnectionInfo(device, subDevice);
|
|
286
|
+
});
|
|
287
|
+
// else no subDevices
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* parentDevice and subDevice must have same localIp, localKey, localVersion.
|
|
292
|
+
* priority: value exists > value not exists > subDevice > parentDevice
|
|
293
|
+
*/
|
|
294
|
+
_syncConnectionInfo(parentDevice, subDevice) {
|
|
295
|
+
const connectionProps = ['localIp', 'localKey', 'localVersion'];
|
|
296
|
+
for (const prop of connectionProps) {
|
|
297
|
+
const parentValue = parentDevice[prop];
|
|
298
|
+
const subValue = subDevice[prop];
|
|
299
|
+
const resolvedValue = this._resolveConnectionInfoValue(parentValue, subValue);
|
|
300
|
+
if (resolvedValue === undefined) {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
parentDevice[prop] = resolvedValue;
|
|
304
|
+
subDevice[prop] = resolvedValue;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
_resolveConnectionInfoValue(parentValue, subValue) {
|
|
308
|
+
if (subValue !== undefined && subValue !== null && subValue !== '') {
|
|
309
|
+
return subValue;
|
|
310
|
+
}
|
|
311
|
+
if (parentValue !== undefined && parentValue !== null && parentValue !== '') {
|
|
312
|
+
return parentValue;
|
|
313
|
+
}
|
|
314
|
+
return undefined;
|
|
315
|
+
}
|
|
188
316
|
/** Stop discovery and disconnect all local TCP connections. */
|
|
189
317
|
stopLocalDevices() {
|
|
190
318
|
if (this.discoveryTimeout) {
|
|
@@ -207,9 +335,24 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
207
335
|
}
|
|
208
336
|
this.gatewayConnections.clear();
|
|
209
337
|
}
|
|
210
|
-
/** Returns ALL devices (both local shadow entries from this manager). */
|
|
211
338
|
getDevice(deviceID) {
|
|
212
|
-
|
|
339
|
+
const device = this.devices.find(d => d.id === deviceID);
|
|
340
|
+
if (device) {
|
|
341
|
+
// local devices have synthetic schemas based on config, so enrich the device schema from config on retrieval
|
|
342
|
+
// Merge config schema with device schema, prioritizing config
|
|
343
|
+
device.schema.forEach(s => {
|
|
344
|
+
const configSchema = this.getDeviceConfig(device)?.schema?.find(cs => cs.code === s.code);
|
|
345
|
+
if (configSchema) {
|
|
346
|
+
Object.assign(s, configSchema);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
this.getDeviceConfig(device)?.schema?.forEach(cs => {
|
|
350
|
+
if (!device.schema.some(s => s.code === cs.code)) {
|
|
351
|
+
device.schema.push(cs);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
return device;
|
|
213
356
|
}
|
|
214
357
|
/**
|
|
215
358
|
* Send commands to a local device.
|
|
@@ -217,11 +360,12 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
217
360
|
* all existing accessory handlers work without modification.
|
|
218
361
|
*/
|
|
219
362
|
async sendCommands(deviceID, commands) {
|
|
220
|
-
const dpMap = this.
|
|
363
|
+
const dpMap = this._getDPMap(deviceID);
|
|
221
364
|
if (!dpMap) {
|
|
222
365
|
this.log.warn(`No dpMapping for local device ${deviceID}`);
|
|
223
|
-
return;
|
|
366
|
+
return false;
|
|
224
367
|
}
|
|
368
|
+
this.log.error(`dpMap:${JSON.stringify(dpMap)}`);
|
|
225
369
|
const dps = {};
|
|
226
370
|
for (const { code, value } of commands) {
|
|
227
371
|
const dp = dpMap[code];
|
|
@@ -232,10 +376,10 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
232
376
|
dps[String(dp)] = value;
|
|
233
377
|
}
|
|
234
378
|
if (Object.keys(dps).length === 0) {
|
|
235
|
-
return;
|
|
379
|
+
return false;
|
|
236
380
|
}
|
|
237
381
|
// Log the command for user visibility
|
|
238
|
-
const device = this.
|
|
382
|
+
const device = this.getDevice(deviceID);
|
|
239
383
|
const deviceName = device?.name || deviceID;
|
|
240
384
|
const commandStr = commands.map(c => `${c.code}=${c.value}`).join(', ');
|
|
241
385
|
this.log.info(`[${deviceName}] Sending command (local): ${commandStr}`);
|
|
@@ -251,7 +395,7 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
251
395
|
if (!conn) {
|
|
252
396
|
conn = this._createConnection(deviceID);
|
|
253
397
|
if (!conn) {
|
|
254
|
-
return;
|
|
398
|
+
return false;
|
|
255
399
|
}
|
|
256
400
|
}
|
|
257
401
|
const expectedDps = new Set(Object.keys(dps));
|
|
@@ -312,12 +456,13 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
312
456
|
return true;
|
|
313
457
|
}
|
|
314
458
|
try {
|
|
315
|
-
await responsePromise;
|
|
316
|
-
return true;
|
|
459
|
+
return await responsePromise;
|
|
317
460
|
}
|
|
318
461
|
catch (error) {
|
|
319
462
|
this.log.warn(`Local command timeout or error for ${deviceName}: ${error instanceof Error ? error.message : error}`);
|
|
320
|
-
throw error
|
|
463
|
+
// To prevent forcing the caller to implement try‑catch handling, this function will not throw error.
|
|
464
|
+
// throw error;
|
|
465
|
+
return false;
|
|
321
466
|
}
|
|
322
467
|
}
|
|
323
468
|
_cancelSupersededLocalResponseWatchers(deviceID, expectedDps) {
|
|
@@ -349,52 +494,11 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
349
494
|
this.pendingLocalResponseWatchers.delete(deviceID);
|
|
350
495
|
}
|
|
351
496
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
const dpMap = this.dpMaps.get(deviceID) ?? {};
|
|
358
|
-
const statusDps = new Set();
|
|
359
|
-
for (const status of statusUpdates) {
|
|
360
|
-
const dp = dpMap[status.code];
|
|
361
|
-
statusDps.add(dp !== undefined ? String(dp) : String(status.code));
|
|
362
|
-
const existing = device.status.find(s => s.code === status.code);
|
|
363
|
-
if (existing) {
|
|
364
|
-
existing.value = status.value;
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
device.status.push({ code: status.code, value: status.value });
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
const watchers = this.pendingLocalResponseWatchers.get(deviceID);
|
|
371
|
-
if (!watchers || watchers.length === 0) {
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
const remaining = [];
|
|
375
|
-
for (const watcher of watchers) {
|
|
376
|
-
let matched = false;
|
|
377
|
-
for (const dp of watcher.expectedDps) {
|
|
378
|
-
if (statusDps.has(dp)) {
|
|
379
|
-
matched = true;
|
|
380
|
-
break;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
if (matched) {
|
|
384
|
-
watcher.cleanup();
|
|
385
|
-
watcher.resolve(true);
|
|
386
|
-
}
|
|
387
|
-
else {
|
|
388
|
-
remaining.push(watcher);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
if (remaining.length > 0) {
|
|
392
|
-
this.pendingLocalResponseWatchers.set(deviceID, remaining);
|
|
393
|
-
}
|
|
394
|
-
else {
|
|
395
|
-
this.pendingLocalResponseWatchers.delete(deviceID);
|
|
396
|
-
}
|
|
397
|
-
this.emit(TuyaDeviceManager_1.default.Events.DEVICE_STATUS_UPDATE, device, statusUpdates);
|
|
497
|
+
/**
|
|
498
|
+
* Logic to suppress unnecessary discovery processes.
|
|
499
|
+
*/
|
|
500
|
+
static isTargetDevice(device) {
|
|
501
|
+
return !device.isVirtualDevice() || !device.sub;
|
|
398
502
|
}
|
|
399
503
|
// ── Private helpers ────────────────────────────────────────────────────────
|
|
400
504
|
/**
|
|
@@ -407,7 +511,7 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
407
511
|
}
|
|
408
512
|
this.isDiscoveryActive = true;
|
|
409
513
|
this.discoveredInCurrentPhase.clear();
|
|
410
|
-
this.log.
|
|
514
|
+
this.log.debug('Starting discovery phase');
|
|
411
515
|
this.discovery.start();
|
|
412
516
|
// Stop after configurable timeout (config is in seconds, default 60s)
|
|
413
517
|
// Convert to milliseconds
|
|
@@ -420,16 +524,16 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
420
524
|
this.discovery.stop();
|
|
421
525
|
// Report discovery results for clarity
|
|
422
526
|
if (this.discoveredInCurrentPhase.size > 0) {
|
|
423
|
-
this.log.
|
|
527
|
+
this.log.debug(`Ended discovery phase – rediscovered ${this.discoveredInCurrentPhase.size} device(s)`);
|
|
424
528
|
}
|
|
425
529
|
else {
|
|
426
530
|
// No devices found; they may be using cached IPs from previous discovery
|
|
427
|
-
const knownDevices = this.
|
|
531
|
+
const knownDevices = this.devices.filter(d => d.localKey);
|
|
428
532
|
if (knownDevices.length > 0) {
|
|
429
|
-
this.log.
|
|
533
|
+
this.log.debug(`Ended discovery phase – no new devices found (${knownDevices.length} configured device(s) using cached IP)`);
|
|
430
534
|
}
|
|
431
535
|
else {
|
|
432
|
-
this.log.
|
|
536
|
+
this.log.debug('Ended discovery phase – no devices found');
|
|
433
537
|
}
|
|
434
538
|
}
|
|
435
539
|
this.discoveryTimeout = null;
|
|
@@ -457,35 +561,19 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
457
561
|
if (!cfg.tuyaDeviceId) {
|
|
458
562
|
const name = cfg.name ?? 'unknown';
|
|
459
563
|
this.log.warn(`Skipping invalid local config entry for ${name}: missing tuyaDeviceId`);
|
|
460
|
-
return;
|
|
461
|
-
}
|
|
462
|
-
const effectiveMap = Object.assign({}, DEFAULT_DP_MAP, cfg.dpMapping ?? {});
|
|
463
|
-
this.dpMaps.set(cfg.tuyaDeviceId, effectiveMap);
|
|
464
|
-
this.reverseDpMaps.set(cfg.tuyaDeviceId, buildDpToCodeMap(effectiveMap));
|
|
465
|
-
const existing = this.localDevices.find(d => d.id === cfg.tuyaDeviceId);
|
|
466
|
-
// Check if config has changed since last run
|
|
467
|
-
// Hash the config fields that affect device behavior
|
|
468
|
-
const configToHash = {
|
|
469
|
-
tuyaDeviceId: cfg.tuyaDeviceId,
|
|
470
|
-
name: cfg.name,
|
|
471
|
-
tuyaKey: cfg.tuyaKey,
|
|
472
|
-
dpMapping: cfg.dpMapping,
|
|
473
|
-
switchCount: cfg.switchCount,
|
|
474
|
-
outletCount: cfg.outletCount,
|
|
475
|
-
protocolVersion: cfg.protocolVersion,
|
|
476
|
-
category: cfg.category,
|
|
477
|
-
};
|
|
478
|
-
const { changed: configChanged } = this.configHash.hasConfigChanged(cfg.tuyaDeviceId, configToHash);
|
|
479
|
-
this.configChanged.set(cfg.tuyaDeviceId, configChanged);
|
|
480
|
-
if (configChanged && existing) {
|
|
481
|
-
this.log.info(`Device ${cfg.tuyaDeviceId}: config changed, rebuilding schema`);
|
|
564
|
+
return undefined;
|
|
482
565
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
this.devices.push(device); // keep parent's devices array in sync
|
|
487
|
-
this.emit(TuyaDeviceManager_1.default.Events.DEVICE_ADD, device);
|
|
566
|
+
const existing = this.getDevice(cfg.tuyaDeviceId);
|
|
567
|
+
if (existing) {
|
|
568
|
+
return existing;
|
|
488
569
|
}
|
|
570
|
+
const effectiveMap = this._createDPMap(cfg);
|
|
571
|
+
this._setDPMap(cfg.tuyaDeviceId, cfg.parentDeviceId, ZigbeeGatewayDetection_1.ZigbeeGatewayDetection.isZigbeeDevice(cfg), effectiveMap);
|
|
572
|
+
const device = this._buildTuyaDevice(cfg);
|
|
573
|
+
this.configDevice(device);
|
|
574
|
+
this.devices.push(device);
|
|
575
|
+
this.emit(TuyaDeviceManager_1.default.Events.DEVICE_ADD, device);
|
|
576
|
+
return device;
|
|
489
577
|
}
|
|
490
578
|
/**
|
|
491
579
|
* Set up auto-detection listener to count switches from device status updates.
|
|
@@ -494,7 +582,7 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
494
582
|
*/
|
|
495
583
|
_setupAutoDetectionListener(deviceId, device, conn) {
|
|
496
584
|
const cfg = this.config.devices?.find(d => d.tuyaDeviceId === deviceId);
|
|
497
|
-
if (!cfg || (cfg
|
|
585
|
+
if (!cfg || this._getConfiguredSwitchCount(cfg) !== undefined) {
|
|
498
586
|
return; // Already has explicit count
|
|
499
587
|
}
|
|
500
588
|
this.log.debug(`[AutoDetect] Setting up auto-detection listener for ${deviceId}`);
|
|
@@ -503,8 +591,7 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
503
591
|
const onStatusChange = (changes) => {
|
|
504
592
|
this.log.debug(`[AutoDetect] Status change received for ${deviceId}: ${JSON.stringify(Object.keys(changes))}`);
|
|
505
593
|
// Collect switch numbers from incoming changes
|
|
506
|
-
const
|
|
507
|
-
const reverseMap = buildDpToCodeMap(dpMap);
|
|
594
|
+
const reverseMap = this.reverseDpMaps.get(deviceId) ?? {};
|
|
508
595
|
for (const dpStr of Object.keys(changes)) {
|
|
509
596
|
const dpNum = parseInt(dpStr, 10);
|
|
510
597
|
const code = reverseMap[dpNum];
|
|
@@ -527,28 +614,12 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
527
614
|
this.log.info(`[AutoDetect] Auto-detected ${detectedCount} switch(es) for "${cfg.name}" (${deviceId}): ` +
|
|
528
615
|
`switches=[${switchList}]`);
|
|
529
616
|
// Update device schema with detected switch count
|
|
530
|
-
device.schema = this._buildSyntheticSchema(this.
|
|
531
|
-
device.switchCount = detectedCount;
|
|
617
|
+
device.schema = this._buildSyntheticSchema(device, this._getDPMap(deviceId), detectedCount);
|
|
618
|
+
device.switchCount = this._getEffectiveSwitchCount(cfg) ?? detectedCount;
|
|
532
619
|
// Auto-detection is now complete
|
|
533
620
|
device.isAutoDetecting = false;
|
|
534
|
-
//
|
|
535
|
-
|
|
536
|
-
const updatedConfigToHash = {
|
|
537
|
-
tuyaDeviceId: cfg.tuyaDeviceId,
|
|
538
|
-
name: cfg.name,
|
|
539
|
-
tuyaKey: cfg.tuyaKey,
|
|
540
|
-
dpMapping: cfg.dpMapping,
|
|
541
|
-
switchCount: detectedCount,
|
|
542
|
-
outletCount: cfg.outletCount,
|
|
543
|
-
protocolVersion: cfg.protocolVersion,
|
|
544
|
-
category: cfg.category,
|
|
545
|
-
};
|
|
546
|
-
const { changed: schemaChanged } = this.configHash.hasConfigChanged(deviceId, updatedConfigToHash);
|
|
547
|
-
if (schemaChanged) {
|
|
548
|
-
this.log.debug('[AutoDetect] Schema changed after auto-detection, marking config as changed');
|
|
549
|
-
device.configChanged = true;
|
|
550
|
-
this.configChanged.set(deviceId, true);
|
|
551
|
-
}
|
|
621
|
+
// update config
|
|
622
|
+
cfg.switchCount = device.switchCount;
|
|
552
623
|
// Notify the platform so configureServices() is re-run and switch_2+ services are added.
|
|
553
624
|
this.emit(TuyaDeviceManager_1.default.Events.DEVICE_INFO_UPDATE, device, { schemaUpdated: true });
|
|
554
625
|
}
|
|
@@ -568,7 +639,7 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
568
639
|
this.discoveredVersions.set(result.id, result.version);
|
|
569
640
|
this.discoveredInCurrentPhase.add(result.id);
|
|
570
641
|
// If we already have a TuyaDevice for this ID (from manual config), update its IP
|
|
571
|
-
const existing = this.
|
|
642
|
+
const existing = this.getDevice(result.id);
|
|
572
643
|
if (existing) {
|
|
573
644
|
this.log.info(`Device ${result.id} (v${result.version}) rediscovered @ ${result.ip} ` +
|
|
574
645
|
'– updating connection');
|
|
@@ -594,14 +665,14 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
594
665
|
// New device discovered via UDP – create a placeholder TuyaDevice
|
|
595
666
|
// (it won't be controllable until the user provides a tuyaKey via config)
|
|
596
667
|
const device = this._buildDiscoveredDevice(result);
|
|
597
|
-
this.
|
|
668
|
+
this.configDevice(device);
|
|
598
669
|
this.devices.push(device);
|
|
599
670
|
const productInfo = result.productKey ? ` productKey=${result.productKey}` : '';
|
|
600
671
|
this.log.info(`Local device discovered: ${result.id} @ ${result.ip} (v${result.version}${productInfo}) ` +
|
|
601
672
|
'– add to config with tuyaKey to control');
|
|
602
673
|
this.emit(TuyaDeviceManager_1.default.Events.DEVICE_ADD, device);
|
|
603
674
|
}
|
|
604
|
-
_buildTuyaDevice(cfg
|
|
675
|
+
_buildTuyaDevice(cfg) {
|
|
605
676
|
const device = new TuyaDevice_1.default({});
|
|
606
677
|
const deviceId = cfg.tuyaDeviceId ?? '';
|
|
607
678
|
device.id = deviceId;
|
|
@@ -622,11 +693,15 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
622
693
|
device.active_time = 0;
|
|
623
694
|
device.update_time = 0;
|
|
624
695
|
device.status = [];
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
696
|
+
device.parent_id = cfg.parentDeviceId;
|
|
697
|
+
device.remote_keys = cfg.remote_keys;
|
|
698
|
+
device.sub = !ZigbeeGatewayDetection_1.ZigbeeGatewayDetection.isChild(cfg) && !!cfg.parentDeviceId;
|
|
699
|
+
const configuredSwitchCount = this._getConfiguredSwitchCount(cfg);
|
|
700
|
+
const switchCount = configuredSwitchCount ?? 1;
|
|
701
|
+
const autoDetectNote = configuredSwitchCount === undefined && cfg.tuyaKey ? ' (auto-detecting on connect)' : '';
|
|
702
|
+
const isAutoDetecting = !!(cfg.tuyaKey && configuredSwitchCount === undefined);
|
|
628
703
|
this.log.info(`Building synthetic schema for ${cfg.name} with switchCount=${switchCount}${autoDetectNote}`);
|
|
629
|
-
device.schema = this._buildSyntheticSchema(
|
|
704
|
+
device.schema = this._buildSyntheticSchema(device, this._getDPMap(device.id), switchCount);
|
|
630
705
|
this.log.info(`Device "${cfg.name}" schema includes ${device.schema.length} codes: ${device.schema.map(s => s.code).join(', ')}`);
|
|
631
706
|
// Store local-specific metadata directly on the device object for later use
|
|
632
707
|
device.localKey = cfg.tuyaKey;
|
|
@@ -638,8 +713,7 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
638
713
|
device.isLocal = true;
|
|
639
714
|
device.switchCount = switchCount;
|
|
640
715
|
device.isAutoDetecting = isAutoDetecting;
|
|
641
|
-
|
|
642
|
-
device.configChanged = configChanged;
|
|
716
|
+
this.log.debug(`_buildTuyaDevice local device:${JSON.stringify(device)}`);
|
|
643
717
|
return device;
|
|
644
718
|
}
|
|
645
719
|
_buildDiscoveredDevice(result) {
|
|
@@ -665,11 +739,13 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
665
739
|
device.schema = [];
|
|
666
740
|
device.isLocal = true;
|
|
667
741
|
device.localVersion = result.version;
|
|
742
|
+
this.log.info(`_buildDiscoveredDevice local device:${JSON.stringify(device)}`);
|
|
668
743
|
return device;
|
|
669
744
|
}
|
|
670
|
-
_buildSyntheticSchema(dpMapping, switchCount = 1) {
|
|
745
|
+
_buildSyntheticSchema(device, dpMapping, switchCount = 1) {
|
|
671
746
|
// If switchCount is limited, filter switch-related entries to only the needed ones
|
|
672
747
|
let filteredMapping = dpMapping;
|
|
748
|
+
this.log.error(`deviceID:${device.id}, switchCount:${switchCount}`);
|
|
673
749
|
if (switchCount > 0) {
|
|
674
750
|
// Only include switch_1 through switch_N where N = switchCount
|
|
675
751
|
// Also exclude other switch variants (like switch_led, switch_inching) if limited
|
|
@@ -694,45 +770,84 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
694
770
|
this.log.debug(`Filtered switches: kept [${switchCodes.join(', ')}], excluded others`);
|
|
695
771
|
}
|
|
696
772
|
}
|
|
697
|
-
|
|
773
|
+
this.log.debug(`local device schema codes:${JSON.stringify(filteredMapping)}`);
|
|
774
|
+
const schemas = Object.keys(filteredMapping).map(code => ({
|
|
698
775
|
code,
|
|
699
776
|
mode: TuyaDevice_1.TuyaDeviceSchemaMode.READ_WRITE,
|
|
700
777
|
type: TuyaDevice_1.TuyaDeviceSchemaType.Boolean, // best-effort default; handlers may override
|
|
701
778
|
property: {},
|
|
702
779
|
}));
|
|
780
|
+
// apply overrides. The synthetic schemas are keyed on the (possibly renamed)
|
|
781
|
+
// dp code, so match on newCode when a rename is set, otherwise on the device code.
|
|
782
|
+
this.getDeviceConfig(device)?.schema?.forEach(s => {
|
|
783
|
+
if (!s.code) {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
const targetCode = s.newCode?.trim() || s.code;
|
|
787
|
+
if (!targetCode) {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
const schema = schemas.find(t => t.code === targetCode);
|
|
791
|
+
if (!!schema) {
|
|
792
|
+
schema.type = s.type ?? schema.type;
|
|
793
|
+
schema.property = s.property ?? schema.property;
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
schemas.push({
|
|
797
|
+
code: targetCode,
|
|
798
|
+
mode: TuyaDevice_1.TuyaDeviceSchemaMode.READ_WRITE,
|
|
799
|
+
type: s.type ?? TuyaDevice_1.TuyaDeviceSchemaType.Boolean,
|
|
800
|
+
property: s.property ?? {},
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
this.log.error('schema:%o', schemas);
|
|
805
|
+
return schemas;
|
|
703
806
|
}
|
|
704
807
|
_createConnection(deviceID) {
|
|
705
|
-
|
|
808
|
+
let device = this.getDevice(deviceID);
|
|
706
809
|
if (!device) {
|
|
707
810
|
return undefined;
|
|
708
811
|
}
|
|
709
|
-
|
|
812
|
+
// Since the sub‑device’s actual entity is the parent device, no separate connection is established for the sub‑device.
|
|
813
|
+
if (device.sub) {
|
|
814
|
+
const parentDevice = this.getDevice(device.parent_id);
|
|
815
|
+
if (parentDevice) {
|
|
816
|
+
device = parentDevice;
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
this.log.warn(`parent device not found. parentDeviceID: ${device.parent_id}, subDeviceID: ${deviceID}.`);
|
|
820
|
+
this.log.warn('sub device will be used as parent device.');
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
const connectDeviceID = device.id;
|
|
824
|
+
let localKey = device.localKey;
|
|
710
825
|
if (!localKey) {
|
|
711
|
-
this.log.warn(`No tuyaKey configured for local device ${
|
|
826
|
+
this.log.warn(`No tuyaKey configured for local device ${connectDeviceID} — cannot connect.`);
|
|
712
827
|
return undefined;
|
|
713
828
|
}
|
|
714
|
-
const ip = device.
|
|
829
|
+
const ip = device.localIp ?? device.ip;
|
|
715
830
|
if (!ip) {
|
|
716
|
-
this.log.warn(`No IP known for local device ${
|
|
831
|
+
this.log.warn(`No IP known for local device ${connectDeviceID} — cannot connect.`);
|
|
717
832
|
return undefined;
|
|
718
833
|
}
|
|
719
834
|
const version = device.localVersion
|
|
720
|
-
?? this.discoveredVersions.get(
|
|
835
|
+
?? this.discoveredVersions.get(connectDeviceID)
|
|
721
836
|
?? '3.3';
|
|
722
837
|
const conn = new LocalDevice_1.default({
|
|
723
|
-
id:
|
|
838
|
+
id: connectDeviceID,
|
|
724
839
|
key: Buffer.from(localKey, 'utf8'),
|
|
725
840
|
ip,
|
|
726
841
|
version,
|
|
727
842
|
name: device.name,
|
|
728
|
-
}
|
|
843
|
+
});
|
|
729
844
|
conn.on('connect', () => {
|
|
730
845
|
device.online = true;
|
|
731
846
|
this.emit(TuyaDeviceManager_1.default.Events.DEVICE_INFO_UPDATE, device, { online: true });
|
|
732
847
|
// ── Zigbee: when a gateway connects, set up its children ──
|
|
733
|
-
if (this.gatewayRelationships.has(
|
|
734
|
-
this.gatewayConnections.set(
|
|
735
|
-
this._setupZigbeeChildren(
|
|
848
|
+
if (this.gatewayRelationships.has(connectDeviceID)) {
|
|
849
|
+
this.gatewayConnections.set(connectDeviceID, conn);
|
|
850
|
+
this._setupZigbeeChildren(connectDeviceID, conn);
|
|
736
851
|
}
|
|
737
852
|
});
|
|
738
853
|
conn.on('disconnect', () => {
|
|
@@ -740,7 +855,7 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
740
855
|
this.emit(TuyaDeviceManager_1.default.Events.DEVICE_INFO_UPDATE, device, { online: false });
|
|
741
856
|
});
|
|
742
857
|
conn.on('change', (changes) => {
|
|
743
|
-
const reverseMap = this.reverseDpMaps.get(
|
|
858
|
+
const reverseMap = this.reverseDpMaps.get(connectDeviceID) ?? {};
|
|
744
859
|
const statusUpdates = [];
|
|
745
860
|
for (const [dp, val] of Object.entries(changes)) {
|
|
746
861
|
const code = reverseMap[parseInt(dp, 10)] ?? dp;
|
|
@@ -759,12 +874,12 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
759
874
|
}
|
|
760
875
|
});
|
|
761
876
|
conn.on('error', (err) => {
|
|
762
|
-
this.log.warn(`Error for local device ${
|
|
877
|
+
this.log.warn(`Error for local device ${connectDeviceID}: ${err.message}`);
|
|
763
878
|
});
|
|
764
879
|
// Set up auto-detection listener BEFORE connecting to avoid race conditions
|
|
765
|
-
this._setupAutoDetectionListener(
|
|
880
|
+
this._setupAutoDetectionListener(connectDeviceID, device, conn);
|
|
766
881
|
conn.connect();
|
|
767
|
-
this.localConnections.set(
|
|
882
|
+
this.localConnections.set(connectDeviceID, conn);
|
|
768
883
|
return conn;
|
|
769
884
|
}
|
|
770
885
|
/**
|
|
@@ -797,7 +912,7 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
797
912
|
* Preserves the child's state and event listeners while updating the parent reference.
|
|
798
913
|
*/
|
|
799
914
|
_reconnectZigbeeChild(childDeviceId, cid, childConn, newParentConn) {
|
|
800
|
-
const childTuyaDevice = this.
|
|
915
|
+
const childTuyaDevice = this.getDevice(childDeviceId);
|
|
801
916
|
if (!childTuyaDevice) {
|
|
802
917
|
this.log.warn(`Zigbee child ${childDeviceId}: TuyaDevice not found during reconnect`);
|
|
803
918
|
return;
|
|
@@ -837,10 +952,10 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
837
952
|
this.log.debug(`Zigbee child ${childDeviceId}: using per-child category override`);
|
|
838
953
|
}
|
|
839
954
|
// Register TuyaDevice if not already present
|
|
840
|
-
if (!this.
|
|
955
|
+
if (!this.getDevice(childDeviceId)) {
|
|
841
956
|
this._registerDeviceConfig(effectiveChildCfg);
|
|
842
957
|
}
|
|
843
|
-
const childTuyaDevice = this.
|
|
958
|
+
const childTuyaDevice = this.getDevice(childDeviceId);
|
|
844
959
|
if (!childTuyaDevice) {
|
|
845
960
|
this.log.warn(`Could not build TuyaDevice for Zigbee child ${childDeviceId}`);
|
|
846
961
|
return;
|
|
@@ -852,7 +967,7 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
852
967
|
ip: parentConn['context'].ip,
|
|
853
968
|
version: parentConn['context'].version,
|
|
854
969
|
name: cfg.name ?? childDeviceId,
|
|
855
|
-
}
|
|
970
|
+
});
|
|
856
971
|
// Link parent ↔ child
|
|
857
972
|
childConn.parentDevice = parentConn;
|
|
858
973
|
childConn.childId = cid;
|
|
@@ -958,7 +1073,7 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
958
1073
|
}
|
|
959
1074
|
/** Connect all configured local devices eagerly (called after init). */
|
|
960
1075
|
connectAllDevices() {
|
|
961
|
-
for (const device of this.
|
|
1076
|
+
for (const device of this.devices) {
|
|
962
1077
|
const localKey = device.localKey;
|
|
963
1078
|
if (!localKey) {
|
|
964
1079
|
continue; // Skip if no local key configured
|
|
@@ -976,6 +1091,88 @@ class LocalDeviceManager extends TuyaDeviceManager_1.default {
|
|
|
976
1091
|
}
|
|
977
1092
|
}
|
|
978
1093
|
}
|
|
1094
|
+
_getConfiguredSwitchCount(cfg) {
|
|
1095
|
+
if (!cfg) {
|
|
1096
|
+
return undefined;
|
|
1097
|
+
}
|
|
1098
|
+
if (cfg.switchCount !== undefined) {
|
|
1099
|
+
return cfg.switchCount;
|
|
1100
|
+
}
|
|
1101
|
+
if (cfg.outletCount !== undefined) {
|
|
1102
|
+
return cfg.outletCount;
|
|
1103
|
+
}
|
|
1104
|
+
return undefined;
|
|
1105
|
+
}
|
|
1106
|
+
_getEffectiveSwitchCount(cfg, device) {
|
|
1107
|
+
const configuredSwitchCount = this._getConfiguredSwitchCount(cfg);
|
|
1108
|
+
if (configuredSwitchCount !== undefined) {
|
|
1109
|
+
return configuredSwitchCount;
|
|
1110
|
+
}
|
|
1111
|
+
const deviceCount = device ? device.switchCount
|
|
1112
|
+
?? device.outletCount
|
|
1113
|
+
: undefined;
|
|
1114
|
+
return deviceCount;
|
|
1115
|
+
}
|
|
1116
|
+
_createDPMap(cfg) {
|
|
1117
|
+
const effectiveMap = Object.assign({}, cfg.dpMapping, Object.fromEntries(cfg.dpMappingArray?.map(item => [item.dpCode, item.dpID]) ?? []));
|
|
1118
|
+
if (Object.keys(effectiveMap).length === 0) {
|
|
1119
|
+
Object.assign(effectiveMap, DEFAULT_DP_MAP);
|
|
1120
|
+
}
|
|
1121
|
+
// override dpcodes
|
|
1122
|
+
for (const [dpCode, dpID] of Object.entries(effectiveMap)) {
|
|
1123
|
+
const schemaConfig = this.getDeviceSchemaConfig({ id: cfg.tuyaDeviceId }, dpCode);
|
|
1124
|
+
if (!schemaConfig?.newCode) {
|
|
1125
|
+
continue;
|
|
1126
|
+
}
|
|
1127
|
+
// Only treat newCode as a rename when it actually differs from the device code.
|
|
1128
|
+
// Renaming to the same key would set-then-delete it, dropping the dp↔code mapping.
|
|
1129
|
+
if (schemaConfig.newCode && schemaConfig.newCode !== dpCode) {
|
|
1130
|
+
effectiveMap[schemaConfig.newCode] = dpID;
|
|
1131
|
+
delete effectiveMap[dpCode];
|
|
1132
|
+
}
|
|
1133
|
+
const targetCode = schemaConfig.newCode.trim();
|
|
1134
|
+
if (!targetCode || targetCode === dpCode) {
|
|
1135
|
+
continue;
|
|
1136
|
+
}
|
|
1137
|
+
effectiveMap[targetCode] = dpID;
|
|
1138
|
+
delete effectiveMap[dpCode];
|
|
1139
|
+
}
|
|
1140
|
+
return effectiveMap;
|
|
1141
|
+
}
|
|
1142
|
+
_setDPMap(deviceID, parentDeviceId, isZigbeeDevice, dpMap) {
|
|
1143
|
+
// Because sub‑devices have no actual entity, they are registered as part of the parent device’s information.
|
|
1144
|
+
// Since there is only one real device,
|
|
1145
|
+
// configuring each sub‑device individually is unnecessary—and even if you did, the settings would end up identical.
|
|
1146
|
+
// If any inconsistencies occur, the values are merged, with later definitions taking precedence.
|
|
1147
|
+
const isSubDevice = !isZigbeeDevice && !!parentDeviceId;
|
|
1148
|
+
if (isSubDevice) {
|
|
1149
|
+
const parentDPMap = this._getDPMap(parentDeviceId);
|
|
1150
|
+
const mergedDPMap = { ...parentDPMap, ...dpMap };
|
|
1151
|
+
this.dpMaps.set(parentDeviceId, mergedDPMap);
|
|
1152
|
+
this.reverseDpMaps.set(parentDeviceId, buildDpToCodeMap(mergedDPMap));
|
|
1153
|
+
}
|
|
1154
|
+
else {
|
|
1155
|
+
this.dpMaps.set(deviceID, dpMap);
|
|
1156
|
+
this.reverseDpMaps.set(deviceID, buildDpToCodeMap(dpMap));
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
_getDPMap(deviceID) {
|
|
1160
|
+
let localConfig = this.config.devices?.find(config => config.tuyaDeviceId === deviceID);
|
|
1161
|
+
if (!localConfig) {
|
|
1162
|
+
// ZigbeeChildDevice or HubSubDevice
|
|
1163
|
+
localConfig = this.config.devices?.find(config => config.parentDeviceId === deviceID);
|
|
1164
|
+
}
|
|
1165
|
+
if (!localConfig) {
|
|
1166
|
+
// A Local device almost never operates without configuration, but this is just in case.
|
|
1167
|
+
return DEFAULT_DP_MAP;
|
|
1168
|
+
}
|
|
1169
|
+
if (!ZigbeeGatewayDetection_1.ZigbeeGatewayDetection.isChild(localConfig) && localConfig.parentDeviceId) {
|
|
1170
|
+
return this.dpMaps.get(localConfig.parentDeviceId) ?? DEFAULT_DP_MAP;
|
|
1171
|
+
}
|
|
1172
|
+
else {
|
|
1173
|
+
return this.dpMaps.get(deviceID) ?? DEFAULT_DP_MAP;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
979
1176
|
}
|
|
980
1177
|
exports.default = LocalDeviceManager;
|
|
981
1178
|
//# sourceMappingURL=LocalDeviceManager.js.map
|