@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.
Files changed (298) hide show
  1. package/README.md +354 -142
  2. package/config.schema.json +1221 -893
  3. package/dist/cloud/api/TuyaOpenAPI.js +108 -60
  4. package/dist/cloud/api/TuyaOpenAPI.js.map +1 -1
  5. package/dist/cloud/api/TuyaOpenMQ.js +45 -22
  6. package/dist/cloud/api/TuyaOpenMQ.js.map +1 -1
  7. package/dist/cloud/device/{TuyaDeviceManager.js → TuyaCloudDeviceManager.js} +146 -96
  8. package/dist/cloud/device/TuyaCloudDeviceManager.js.map +1 -0
  9. package/dist/cloud/device/TuyaCustomDeviceManager.js +75 -5
  10. package/dist/cloud/device/TuyaCustomDeviceManager.js.map +1 -1
  11. package/dist/cloud/device/TuyaDevice.js.map +1 -1
  12. package/dist/cloud/device/TuyaHomeDeviceManager.js +81 -13
  13. package/dist/cloud/device/TuyaHomeDeviceManager.js.map +1 -1
  14. package/dist/config.js +26 -5
  15. package/dist/config.js.map +1 -1
  16. package/dist/local/DynamicChildDiscovery.js +2 -1
  17. package/dist/local/DynamicChildDiscovery.js.map +1 -1
  18. package/dist/local/LocalDevice.js +16 -3
  19. package/dist/local/LocalDevice.js.map +1 -1
  20. package/dist/local/LocalDeviceManager.js +361 -164
  21. package/dist/local/LocalDeviceManager.js.map +1 -1
  22. package/dist/local/TuyaDiscovery.js +16 -7
  23. package/dist/local/TuyaDiscovery.js.map +1 -1
  24. package/dist/local/ZigbeeGatewayDetection.js +7 -4
  25. package/dist/local/ZigbeeGatewayDetection.js.map +1 -1
  26. package/dist/local/protocol/ProtocolUtilities.js +34 -17
  27. package/dist/local/protocol/ProtocolUtilities.js.map +1 -1
  28. package/dist/local/protocol/ProtocolV31V32.js +4 -2
  29. package/dist/local/protocol/ProtocolV31V32.js.map +1 -1
  30. package/dist/local/protocol/ProtocolV33.js +4 -2
  31. package/dist/local/protocol/ProtocolV33.js.map +1 -1
  32. package/dist/local/protocol/ProtocolV34.js +10 -5
  33. package/dist/local/protocol/ProtocolV34.js.map +1 -1
  34. package/dist/local/protocol/ProtocolV35.js +8 -4
  35. package/dist/local/protocol/ProtocolV35.js.map +1 -1
  36. package/dist/platform.js +253 -493
  37. package/dist/platform.js.map +1 -1
  38. package/dist/settings.js +0 -2
  39. package/dist/settings.js.map +1 -1
  40. package/dist/shared/TuyaDeviceManager.js +147 -0
  41. package/dist/shared/TuyaDeviceManager.js.map +1 -0
  42. package/dist/shared/TuyaHybridDeviceManager.js +215 -0
  43. package/dist/shared/TuyaHybridDeviceManager.js.map +1 -0
  44. package/dist/shared/accessory/AccessoryFactory.js +350 -0
  45. package/dist/shared/accessory/AccessoryFactory.js.map +1 -0
  46. package/dist/shared/{accessories → accessory}/AirConditionerAccessory.js +21 -15
  47. package/dist/shared/accessory/AirConditionerAccessory.js.map +1 -0
  48. package/dist/shared/{accessories → accessory}/AirPurifierAccessory.js.map +1 -1
  49. package/dist/shared/accessory/AirQualitySensorAccessory.js.map +1 -0
  50. package/dist/shared/{accessories → accessory}/BaseAccessory.js +16 -95
  51. package/dist/shared/accessory/BaseAccessory.js.map +1 -0
  52. package/dist/shared/{accessories → accessory}/BlindsAccessory.js.map +1 -1
  53. package/dist/shared/{accessories → accessory}/CameraAccessory.js +2 -2
  54. package/dist/shared/accessory/CameraAccessory.js.map +1 -0
  55. package/dist/shared/{accessories → accessory}/CarbonDioxideSensorAccessory.js.map +1 -1
  56. package/dist/shared/{accessories → accessory}/CarbonMonoxideSensorAccessory.js.map +1 -1
  57. package/dist/shared/{accessories → accessory}/ContactSensorAccessory.js.map +1 -1
  58. package/dist/shared/{accessories → accessory}/DehumidifierAccessory.js.map +1 -1
  59. package/dist/shared/{accessories → accessory}/DiffuserAccessory.js.map +1 -1
  60. package/dist/shared/{accessories → accessory}/DimmerAccessory.js.map +1 -1
  61. package/dist/shared/{accessories → accessory}/DoorbellAccessory.js.map +1 -1
  62. package/dist/shared/{accessories → accessory}/ExtractionHoodAccessory.js.map +1 -1
  63. package/dist/shared/{accessories → accessory}/FanAccessory.js.map +1 -1
  64. package/dist/shared/{accessories → accessory}/GarageDoorAccessory.js +19 -2
  65. package/dist/shared/accessory/GarageDoorAccessory.js.map +1 -0
  66. package/dist/shared/{accessories → accessory}/HeaterAccessory.js.map +1 -1
  67. package/dist/shared/{accessories → accessory}/HeaterAccessory_old.js.map +1 -1
  68. package/dist/shared/accessory/HumanPresenceSensorAccessory.js.map +1 -0
  69. package/dist/shared/{accessories → accessory}/HumidifierAccessory.js.map +1 -1
  70. package/dist/shared/accessory/IRAdapter.js +167 -0
  71. package/dist/shared/accessory/IRAdapter.js.map +1 -0
  72. package/dist/shared/accessory/IRAirConditionerAccessory.js.map +1 -0
  73. package/dist/shared/accessory/IRControlHubAccessory.js.map +1 -0
  74. package/dist/shared/accessory/IRControlHubSubAccessory.js.map +1 -0
  75. package/dist/shared/accessory/IRFanAccessory.js +90 -0
  76. package/dist/shared/accessory/IRFanAccessory.js.map +1 -0
  77. package/dist/shared/accessory/IRGenericAccessory.js.map +1 -0
  78. package/dist/shared/{accessories → accessory}/LeakSensorAccessory.js.map +1 -1
  79. package/dist/shared/{accessories → accessory}/LightAccessory.js.map +1 -1
  80. package/dist/shared/{accessories → accessory}/LightSensorAccessory.js.map +1 -1
  81. package/dist/shared/{accessories → accessory}/LocationWeatherAccessory.js +1 -1
  82. package/dist/shared/accessory/LocationWeatherAccessory.js.map +1 -0
  83. package/dist/shared/{accessories → accessory}/LockAccessory.js +3 -3
  84. package/dist/shared/{accessories → accessory}/LockAccessory.js.map +1 -1
  85. package/dist/shared/accessory/MotionSensorAccessory.js.map +1 -0
  86. package/dist/shared/accessory/OutletAccessory.js.map +1 -0
  87. package/dist/shared/{accessories → accessory}/PetFeederAccessory.js.map +1 -1
  88. package/dist/shared/{accessories → accessory}/SceneAccessory.js +1 -1
  89. package/dist/shared/accessory/SceneAccessory.js.map +1 -0
  90. package/dist/shared/accessory/SceneSwitchAccessory.js.map +1 -0
  91. package/dist/shared/accessory/SecuritySystemAccessory.js.map +1 -0
  92. package/dist/shared/{accessories → accessory}/SmokeSensorAccessory.js.map +1 -1
  93. package/dist/shared/{accessories → accessory}/SwitchAccessory.js +1 -45
  94. package/dist/shared/accessory/SwitchAccessory.js.map +1 -0
  95. package/dist/shared/accessory/TemperatureHumiditySensorAccessory.js.map +1 -0
  96. package/dist/shared/{accessories → accessory}/ThermostatAccessory.js.map +1 -1
  97. package/dist/shared/{accessories → accessory}/TowerRackAccessory.js.map +1 -1
  98. package/dist/shared/{accessories → accessory}/ValveAccessory.js.map +1 -1
  99. package/dist/shared/{accessories → accessory}/VibrationSensorAccessory.js.map +1 -1
  100. package/dist/shared/accessory/WeatherStationAccessory.js.map +1 -0
  101. package/dist/shared/accessory/WetBulbGlobeTemperatureAccessory.js.map +1 -0
  102. package/dist/shared/{accessories → accessory}/WhiteNoiseLightAccessory.js +1 -0
  103. package/dist/shared/accessory/WhiteNoiseLightAccessory.js.map +1 -0
  104. package/dist/shared/accessory/WindowAccessory.js.map +1 -0
  105. package/dist/shared/{accessories → accessory}/WindowCoveringAccessory.js.map +1 -1
  106. package/dist/shared/{accessories → accessory}/WirelessSwitchAccessory.js.map +1 -1
  107. package/dist/shared/accessory/characteristic/Active.js.map +1 -0
  108. package/dist/shared/accessory/characteristic/AirQuality.js.map +1 -0
  109. package/dist/shared/{accessories → accessory}/characteristic/CurrentRelativeHumidity.js +3 -0
  110. package/dist/shared/accessory/characteristic/CurrentRelativeHumidity.js.map +1 -0
  111. package/dist/shared/accessory/characteristic/CurrentTemperature.js.map +1 -0
  112. package/dist/shared/accessory/characteristic/CurrentWeather.js.map +1 -0
  113. package/dist/shared/accessory/characteristic/CurrentWeatherByOpenMeteo.js.map +1 -0
  114. package/dist/shared/{accessories → accessory}/characteristic/CurrentWetBulbGlobeTemperature.js +3 -2
  115. package/dist/shared/accessory/characteristic/CurrentWetBulbGlobeTemperature.js.map +1 -0
  116. package/dist/shared/{accessories → accessory}/characteristic/EnergyUsage.js +0 -5
  117. package/dist/shared/accessory/characteristic/EnergyUsage.js.map +1 -0
  118. package/dist/shared/{accessories → accessory}/characteristic/Light.js +28 -5
  119. package/dist/shared/accessory/characteristic/Light.js.map +1 -0
  120. package/dist/shared/accessory/characteristic/LightSensor.js.map +1 -0
  121. package/dist/shared/{accessories → accessory}/characteristic/LockPhysicalControls.js +3 -0
  122. package/dist/shared/accessory/characteristic/LockPhysicalControls.js.map +1 -0
  123. package/dist/shared/accessory/characteristic/MotionDetected.js.map +1 -0
  124. package/dist/shared/accessory/characteristic/Name.js.map +1 -0
  125. package/dist/shared/accessory/characteristic/OccupancyDetected.js.map +1 -0
  126. package/dist/shared/{accessories → accessory}/characteristic/On.js +1 -0
  127. package/dist/shared/accessory/characteristic/On.js.map +1 -0
  128. package/dist/shared/accessory/characteristic/OutletInUse.js.map +1 -0
  129. package/dist/shared/accessory/characteristic/ProgrammableSwitchEvent.js.map +1 -0
  130. package/dist/shared/{accessories → accessory}/characteristic/RelativeHumidityDehumidifierThreshold.js +3 -0
  131. package/dist/shared/accessory/characteristic/RelativeHumidityDehumidifierThreshold.js.map +1 -0
  132. package/dist/shared/accessory/characteristic/RotationSpeed.js.map +1 -0
  133. package/dist/shared/accessory/characteristic/SecuritySystemState.js.map +1 -0
  134. package/dist/shared/{accessories → accessory}/characteristic/SwingMode.js +3 -0
  135. package/dist/shared/accessory/characteristic/SwingMode.js.map +1 -0
  136. package/dist/shared/accessory/characteristic/TargetTemperature.js.map +1 -0
  137. package/dist/shared/accessory/characteristic/TemperatureDisplayUnits.js.map +1 -0
  138. package/dist/shared/util/ConfigHash.js +2 -2
  139. package/dist/shared/util/ConfigHash.js.map +1 -1
  140. package/dist/shared/util/ConfigMigrator.js +222 -0
  141. package/dist/shared/util/ConfigMigrator.js.map +1 -0
  142. package/dist/shared/util/FfmpegStreamingProcess.js +62 -0
  143. package/dist/shared/util/FfmpegStreamingProcess.js.map +1 -1
  144. package/dist/shared/util/InfraredTool.js +0 -2
  145. package/dist/shared/util/InfraredTool.js.map +1 -1
  146. package/dist/shared/util/Logger.js +85 -10
  147. package/dist/shared/util/Logger.js.map +1 -1
  148. package/dist/shared/util/TuyaStreamDelegate.js +194 -97
  149. package/dist/shared/util/TuyaStreamDelegate.js.map +1 -1
  150. package/dist/shared/util/util.js +59 -4
  151. package/dist/shared/util/util.js.map +1 -1
  152. package/docs/ADVANCED_OPTIONS.md +603 -0
  153. package/docs/CONFIG_GUIDE.md +616 -0
  154. package/docs/Get-Local-Keys-for-Your-Devices.md +246 -0
  155. package/{SUPPORTED_DEVICES.md → docs/SUPPORTED_DEVICES.md} +24 -3
  156. package/eslint.config.mjs +0 -1
  157. package/{jest.config.js → jest.config.ts} +5 -2
  158. package/package.json +12 -9
  159. package/test/ConfigMigrator.test.ts +1060 -0
  160. package/test/Logger.test.ts +482 -0
  161. package/test/accessoryFactory.data.test.ts +172 -0
  162. package/test/accessoryFactory.test.ts +64 -35
  163. package/test/airConditioner.test.ts +742 -0
  164. package/test/config.test.ts +17 -13
  165. package/test/custom.test.ts +2 -2
  166. package/test/errorHandling.test.ts +12 -12
  167. package/test/home.test.ts +1 -1
  168. package/test/hybridDeviceManager.test.ts +808 -0
  169. package/test/light.test.ts +250 -0
  170. package/test/localDevice.test.ts +21 -50
  171. package/test/localDeviceManager.behavior.test.ts +196 -31
  172. package/test/localDeviceManager.test.ts +124 -41
  173. package/test/mqttMessages.test.ts +33 -14
  174. package/test/platform.test.ts +337 -814
  175. package/test/platform.validation.local.test.ts +58 -119
  176. package/test/tuyaCustomDeviceManager.test.ts +106 -16
  177. package/test/tuyaDeviceManager.test.ts +636 -639
  178. package/test/tuyaDiscovery.test.ts +21 -33
  179. package/test/tuyaHomeDeviceManager.test.ts +109 -18
  180. package/test/tuyaOpenAPI.test.ts +25 -44
  181. package/test/tuyaOpenMQ.test.ts +15 -23
  182. package/test/util.test.ts +107 -7
  183. package/test/zigbee/LocalDevice.zigbee.test.ts +14 -18
  184. package/test/zigbee/LocalDeviceManager.cloud-discovery.test.ts +19 -20
  185. package/test/zigbee/LocalDeviceManager.zigbee.reconnect.test.ts +19 -20
  186. package/test/zigbee/LocalDeviceManager.zigbee.test.ts +73 -35
  187. package/test/zigbee/ZigbeeGatewayDetection.test.ts +2 -2
  188. package/ADVANCED_OPTIONS.md +0 -267
  189. package/dist/cloud/device/TuyaDeviceManager.js.map +0 -1
  190. package/dist/local/CloudLocalReconciliation.js +0 -180
  191. package/dist/local/CloudLocalReconciliation.js.map +0 -1
  192. package/dist/shared/AccessoryFactory.js +0 -276
  193. package/dist/shared/AccessoryFactory.js.map +0 -1
  194. package/dist/shared/accessories/AccessoryFactory.js +0 -305
  195. package/dist/shared/accessories/AccessoryFactory.js.map +0 -1
  196. package/dist/shared/accessories/AirConditionerAccessory.js.map +0 -1
  197. package/dist/shared/accessories/AirQualitySensorAccessory.js.map +0 -1
  198. package/dist/shared/accessories/BaseAccessory.js.map +0 -1
  199. package/dist/shared/accessories/CameraAccessory.js.map +0 -1
  200. package/dist/shared/accessories/GarageDoorAccessory.js.map +0 -1
  201. package/dist/shared/accessories/HumanPresenceSensorAccessory.js.map +0 -1
  202. package/dist/shared/accessories/IRAirConditionerAccessory.js.map +0 -1
  203. package/dist/shared/accessories/IRControlHubAccessory.js.map +0 -1
  204. package/dist/shared/accessories/IRControlHubSubAccessory.js.map +0 -1
  205. package/dist/shared/accessories/IRGenericAccessory.js.map +0 -1
  206. package/dist/shared/accessories/LocationWeatherAccessory.js.map +0 -1
  207. package/dist/shared/accessories/MotionSensorAccessory.js.map +0 -1
  208. package/dist/shared/accessories/OutletAccessory.js.map +0 -1
  209. package/dist/shared/accessories/SceneAccessory.js.map +0 -1
  210. package/dist/shared/accessories/SceneSwitchAccessory.js.map +0 -1
  211. package/dist/shared/accessories/SecuritySystemAccessory.js.map +0 -1
  212. package/dist/shared/accessories/SwitchAccessory.js.map +0 -1
  213. package/dist/shared/accessories/TemperatureHumiditySensorAccessory.js.map +0 -1
  214. package/dist/shared/accessories/WeatherStationAccessory.js.map +0 -1
  215. package/dist/shared/accessories/WetBulbGlobeTemperatureAccessory.js.map +0 -1
  216. package/dist/shared/accessories/WhiteNoiseLightAccessory.js.map +0 -1
  217. package/dist/shared/accessories/WindowAccessory.js.map +0 -1
  218. package/dist/shared/accessories/characteristic/Active.js.map +0 -1
  219. package/dist/shared/accessories/characteristic/AirQuality.js.map +0 -1
  220. package/dist/shared/accessories/characteristic/CurrentRelativeHumidity.js.map +0 -1
  221. package/dist/shared/accessories/characteristic/CurrentTemperature.js.map +0 -1
  222. package/dist/shared/accessories/characteristic/CurrentWeather.js.map +0 -1
  223. package/dist/shared/accessories/characteristic/CurrentWeatherByOpenMeteo.js.map +0 -1
  224. package/dist/shared/accessories/characteristic/CurrentWetBulbGlobeTemperature.js.map +0 -1
  225. package/dist/shared/accessories/characteristic/EnergyUsage.js.map +0 -1
  226. package/dist/shared/accessories/characteristic/Light.js.map +0 -1
  227. package/dist/shared/accessories/characteristic/LightSensor.js.map +0 -1
  228. package/dist/shared/accessories/characteristic/LockPhysicalControls.js.map +0 -1
  229. package/dist/shared/accessories/characteristic/MotionDetected.js.map +0 -1
  230. package/dist/shared/accessories/characteristic/Name.js.map +0 -1
  231. package/dist/shared/accessories/characteristic/OccupancyDetected.js.map +0 -1
  232. package/dist/shared/accessories/characteristic/On.js.map +0 -1
  233. package/dist/shared/accessories/characteristic/OutletInUse.js.map +0 -1
  234. package/dist/shared/accessories/characteristic/ProgrammableSwitchEvent.js.map +0 -1
  235. package/dist/shared/accessories/characteristic/RelativeHumidityDehumidifierThreshold.js.map +0 -1
  236. package/dist/shared/accessories/characteristic/RotationSpeed.js.map +0 -1
  237. package/dist/shared/accessories/characteristic/SecuritySystemState.js.map +0 -1
  238. package/dist/shared/accessories/characteristic/SwingMode.js.map +0 -1
  239. package/dist/shared/accessories/characteristic/TargetTemperature.js.map +0 -1
  240. package/dist/shared/accessories/characteristic/TemperatureDisplayUnits.js.map +0 -1
  241. package/test/zigbee/CloudLocalReconciliation.test.ts +0 -284
  242. package/tuya-local-configs/dev-1.hash +0 -1
  243. package/tuya-local-configs/device1.hash +0 -1
  244. package/wiki/Get-Local-Keys-for-Your-Devices.md +0 -85
  245. /package/dist/shared/{accessories → accessory}/AirPurifierAccessory.js +0 -0
  246. /package/dist/shared/{accessories → accessory}/AirQualitySensorAccessory.js +0 -0
  247. /package/dist/shared/{accessories → accessory}/BlindsAccessory.js +0 -0
  248. /package/dist/shared/{accessories → accessory}/CarbonDioxideSensorAccessory.js +0 -0
  249. /package/dist/shared/{accessories → accessory}/CarbonMonoxideSensorAccessory.js +0 -0
  250. /package/dist/shared/{accessories → accessory}/ContactSensorAccessory.js +0 -0
  251. /package/dist/shared/{accessories → accessory}/DehumidifierAccessory.js +0 -0
  252. /package/dist/shared/{accessories → accessory}/DiffuserAccessory.js +0 -0
  253. /package/dist/shared/{accessories → accessory}/DimmerAccessory.js +0 -0
  254. /package/dist/shared/{accessories → accessory}/DoorbellAccessory.js +0 -0
  255. /package/dist/shared/{accessories → accessory}/ExtractionHoodAccessory.js +0 -0
  256. /package/dist/shared/{accessories → accessory}/FanAccessory.js +0 -0
  257. /package/dist/shared/{accessories → accessory}/HeaterAccessory.js +0 -0
  258. /package/dist/shared/{accessories → accessory}/HeaterAccessory_old.js +0 -0
  259. /package/dist/shared/{accessories → accessory}/HumanPresenceSensorAccessory.js +0 -0
  260. /package/dist/shared/{accessories → accessory}/HumidifierAccessory.js +0 -0
  261. /package/dist/shared/{accessories → accessory}/IRAirConditionerAccessory.js +0 -0
  262. /package/dist/shared/{accessories → accessory}/IRControlHubAccessory.js +0 -0
  263. /package/dist/shared/{accessories → accessory}/IRControlHubSubAccessory.js +0 -0
  264. /package/dist/shared/{accessories → accessory}/IRGenericAccessory.js +0 -0
  265. /package/dist/shared/{accessories → accessory}/LeakSensorAccessory.js +0 -0
  266. /package/dist/shared/{accessories → accessory}/LightAccessory.js +0 -0
  267. /package/dist/shared/{accessories → accessory}/LightSensorAccessory.js +0 -0
  268. /package/dist/shared/{accessories → accessory}/MotionSensorAccessory.js +0 -0
  269. /package/dist/shared/{accessories → accessory}/OutletAccessory.js +0 -0
  270. /package/dist/shared/{accessories → accessory}/PetFeederAccessory.js +0 -0
  271. /package/dist/shared/{accessories → accessory}/SceneSwitchAccessory.js +0 -0
  272. /package/dist/shared/{accessories → accessory}/SecuritySystemAccessory.js +0 -0
  273. /package/dist/shared/{accessories → accessory}/SmokeSensorAccessory.js +0 -0
  274. /package/dist/shared/{accessories → accessory}/TemperatureHumiditySensorAccessory.js +0 -0
  275. /package/dist/shared/{accessories → accessory}/ThermostatAccessory.js +0 -0
  276. /package/dist/shared/{accessories → accessory}/TowerRackAccessory.js +0 -0
  277. /package/dist/shared/{accessories → accessory}/ValveAccessory.js +0 -0
  278. /package/dist/shared/{accessories → accessory}/VibrationSensorAccessory.js +0 -0
  279. /package/dist/shared/{accessories → accessory}/WeatherStationAccessory.js +0 -0
  280. /package/dist/shared/{accessories → accessory}/WetBulbGlobeTemperatureAccessory.js +0 -0
  281. /package/dist/shared/{accessories → accessory}/WindowAccessory.js +0 -0
  282. /package/dist/shared/{accessories → accessory}/WindowCoveringAccessory.js +0 -0
  283. /package/dist/shared/{accessories → accessory}/WirelessSwitchAccessory.js +0 -0
  284. /package/dist/shared/{accessories → accessory}/characteristic/Active.js +0 -0
  285. /package/dist/shared/{accessories → accessory}/characteristic/AirQuality.js +0 -0
  286. /package/dist/shared/{accessories → accessory}/characteristic/CurrentTemperature.js +0 -0
  287. /package/dist/shared/{accessories → accessory}/characteristic/CurrentWeather.js +0 -0
  288. /package/dist/shared/{accessories → accessory}/characteristic/CurrentWeatherByOpenMeteo.js +0 -0
  289. /package/dist/shared/{accessories → accessory}/characteristic/LightSensor.js +0 -0
  290. /package/dist/shared/{accessories → accessory}/characteristic/MotionDetected.js +0 -0
  291. /package/dist/shared/{accessories → accessory}/characteristic/Name.js +0 -0
  292. /package/dist/shared/{accessories → accessory}/characteristic/OccupancyDetected.js +0 -0
  293. /package/dist/shared/{accessories → accessory}/characteristic/OutletInUse.js +0 -0
  294. /package/dist/shared/{accessories → accessory}/characteristic/ProgrammableSwitchEvent.js +0 -0
  295. /package/dist/shared/{accessories → accessory}/characteristic/RotationSpeed.js +0 -0
  296. /package/dist/shared/{accessories → accessory}/characteristic/SecuritySystemState.js +0 -0
  297. /package/dist/shared/{accessories → accessory}/characteristic/TargetTemperature.js +0 -0
  298. /package/dist/shared/{accessories → accessory}/characteristic/TemperatureDisplayUnits.js +0 -0
@@ -2,19 +2,17 @@
2
2
  import { describe, expect, it, beforeEach, jest } from '@jest/globals';
3
3
  import EventEmitter from 'events';
4
4
  import LocalDevice, { LocalDeviceContext } from '../../src/local/LocalDevice';
5
+ import { ExLogger, initLogger } from '../../src/shared/util/Logger';
5
6
 
6
7
  // ── Logger mock ───────────────────────────────────────────────────────────────
7
-
8
- jest.mock('../../src/shared/util/Logger', () => ({
9
- __esModule: true,
10
- default: class Logger {
11
- log() {}; info() {}; warn() {}; error() {}; debug() {};
12
- },
13
- PrefixLogger: class PrefixLogger {
14
- constructor(public _log: any, public prefix: string) {}
15
- debug() {}; info() {}; warn() {}; error() {};
16
- },
17
- }));
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;
18
16
 
19
17
  // ── Protocol mock ──────────────────────────────────────────────────────────────
20
18
 
@@ -46,11 +44,6 @@ jest.mock('net', () => ({
46
44
  }));
47
45
 
48
46
  // ── Helpers ────────────────────────────────────────────────────────────────────
49
-
50
- function makeLogger() {
51
- return { log: jest.fn(), info: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn() } as any;
52
- }
53
-
54
47
  function makeParent(overrides: Partial<LocalDeviceContext> = {}): LocalDevice {
55
48
  const ctx: LocalDeviceContext = {
56
49
  id: 'gateway_001',
@@ -60,7 +53,7 @@ function makeParent(overrides: Partial<LocalDeviceContext> = {}): LocalDevice {
60
53
  name: 'Test Gateway',
61
54
  ...overrides,
62
55
  };
63
- return new LocalDevice(ctx, makeLogger());
56
+ return new LocalDevice(ctx);
64
57
  }
65
58
 
66
59
  function makeChild(parent: LocalDevice, cid: string): LocalDevice {
@@ -71,7 +64,7 @@ function makeChild(parent: LocalDevice, cid: string): LocalDevice {
71
64
  version: '3.3',
72
65
  name: 'Test Child',
73
66
  };
74
- const child = new LocalDevice(ctx, makeLogger());
67
+ const child = new LocalDevice(ctx);
75
68
  child.parentDevice = parent;
76
69
  child.childId = cid;
77
70
  parent.children.set(cid, child);
@@ -81,6 +74,9 @@ function makeChild(parent: LocalDevice, cid: string): LocalDevice {
81
74
  // ── Tests ──────────────────────────────────────────────────────────────────────
82
75
 
83
76
  describe('LocalDevice – Zigbee parent/child', () => {
77
+ beforeEach(() => {
78
+ initLogger(mockLog);
79
+ });
84
80
 
85
81
  describe('children Map', () => {
86
82
  it('starts as an empty Map', () => {
@@ -1,20 +1,19 @@
1
1
  import { describe, expect, it, beforeEach, afterEach, jest } from '@jest/globals';
2
2
  import LocalDeviceManager from '../../src/local/LocalDeviceManager';
3
3
  import { LocalConfig } from '../../src/local/config';
4
- import Logger from '../../src/shared/util/Logger';
5
-
6
- function makeMockLog(): Logger {
7
- return {
8
- debug: jest.fn(),
9
- info: jest.fn(),
10
- warn: jest.fn(),
11
- error: jest.fn(),
12
- log: jest.fn(),
13
- } as unknown as Logger;
14
- }
4
+ import { ExLogger, initLogger } from '../../src/shared/util/Logger';
5
+
6
+ // Mock Logger
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;
15
15
 
16
16
  describe('LocalDeviceManager – Cloud-based child discovery', () => {
17
- let log: Logger;
18
17
  let manager: LocalDeviceManager;
19
18
 
20
19
  const GATEWAY_ID = 'cloud_gw_001';
@@ -22,7 +21,7 @@ describe('LocalDeviceManager – Cloud-based child discovery', () => {
22
21
  const DEVICE_IP = '192.168.1.200';
23
22
 
24
23
  beforeEach(() => {
25
- log = makeMockLog();
24
+ initLogger(mockLog);
26
25
  });
27
26
 
28
27
  afterEach(() => {
@@ -46,7 +45,7 @@ describe('LocalDeviceManager – Cloud-based child discovery', () => {
46
45
  ],
47
46
  };
48
47
 
49
- manager = new LocalDeviceManager(config, log);
48
+ manager = new LocalDeviceManager(config);
50
49
 
51
50
  const cloudDevices = [
52
51
  { id: GATEWAY_ID },
@@ -65,7 +64,7 @@ describe('LocalDeviceManager – Cloud-based child discovery', () => {
65
64
  devices: [],
66
65
  };
67
66
 
68
- manager = new LocalDeviceManager(config, log);
67
+ manager = new LocalDeviceManager(config);
69
68
 
70
69
  const cloudDevices = [
71
70
  { id: 'unknown_gw', gateway_id: undefined },
@@ -74,7 +73,7 @@ describe('LocalDeviceManager – Cloud-based child discovery', () => {
74
73
 
75
74
  manager.discoverChildrenFromCloud(cloudDevices);
76
75
 
77
- const debugSpy = log.debug as jest.MockedFunction<typeof log.debug>;
76
+ const debugSpy = jest.spyOn(mockLog, 'debug');
78
77
  expect(debugSpy.mock.calls.length).toBeGreaterThan(0);
79
78
  });
80
79
 
@@ -91,7 +90,7 @@ describe('LocalDeviceManager – Cloud-based child discovery', () => {
91
90
  ],
92
91
  };
93
92
 
94
- manager = new LocalDeviceManager(config, log);
93
+ manager = new LocalDeviceManager(config);
95
94
 
96
95
  // Should not throw
97
96
  expect(() => {
@@ -115,7 +114,7 @@ describe('LocalDeviceManager – Cloud-based child discovery', () => {
115
114
  ],
116
115
  };
117
116
 
118
- manager = new LocalDeviceManager(config, log);
117
+ manager = new LocalDeviceManager(config);
119
118
 
120
119
  const cloudDevices = [
121
120
  { id: GATEWAY_ID },
@@ -125,7 +124,7 @@ describe('LocalDeviceManager – Cloud-based child discovery', () => {
125
124
  manager.discoverChildrenFromCloud(cloudDevices);
126
125
 
127
126
  // Should not log auto-discovery (device is not a gateway)
128
- const infoSpy = log.info as jest.MockedFunction<typeof log.info>;
127
+ const infoSpy = jest.spyOn(mockLog, 'info');
129
128
  const callsWithAutoDiscovery = infoSpy.mock.calls.filter(c =>
130
129
  String(c[0]).includes('auto-discovery'),
131
130
  );
@@ -146,7 +145,7 @@ describe('LocalDeviceManager – Cloud-based child discovery', () => {
146
145
  ],
147
146
  };
148
147
 
149
- manager = new LocalDeviceManager(config, log);
148
+ manager = new LocalDeviceManager(config);
150
149
 
151
150
  const cloudDevices = [
152
151
  { id: GATEWAY_ID },
@@ -1,21 +1,19 @@
1
1
  import { describe, expect, it, beforeEach, afterEach, jest } from '@jest/globals';
2
2
  import LocalDeviceManager from '../../src/local/LocalDeviceManager';
3
- import { LocalConfig, LocalDeviceConfig } from '../../src/local/config';
4
- import TuyaDeviceManager from '../../src/cloud/device/TuyaDeviceManager';
5
- import Logger from '../../src/shared/util/Logger';
6
-
7
- function makeMockLog(): Logger {
8
- return {
9
- debug: jest.fn(),
10
- info: jest.fn(),
11
- warn: jest.fn(),
12
- error: jest.fn(),
13
- log: jest.fn(),
14
- } as unknown as Logger;
15
- }
3
+ import { LocalConfig } from '../../src/local/config';
4
+ import { ExLogger, initLogger } from '../../src/shared/util/Logger';
5
+
6
+ // Mock Logger
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;
16
15
 
17
16
  describe('LocalDeviceManager – Zigbee gateway reconnection', () => {
18
- let log: Logger;
19
17
  let manager: LocalDeviceManager;
20
18
 
21
19
  const GATEWAY_ID = 'gw_reconnect_001';
@@ -50,8 +48,8 @@ describe('LocalDeviceManager – Zigbee gateway reconnection', () => {
50
48
  }
51
49
 
52
50
  beforeEach(() => {
53
- log = makeMockLog();
54
- manager = new LocalDeviceManager(zigbeeReconnectConfig(), log);
51
+ initLogger(mockLog);
52
+ manager = new LocalDeviceManager(zigbeeReconnectConfig());
55
53
  });
56
54
 
57
55
  afterEach(() => {
@@ -81,6 +79,7 @@ describe('LocalDeviceManager – Zigbee gateway reconnection', () => {
81
79
  ip: DEVICE_IP,
82
80
  tuyaKey: DEVICE_KEY,
83
81
  dpMapping: { 'switch_1': 1, 'bright_value': 2 },
82
+ isZigbeeGateway: true
84
83
  },
85
84
  {
86
85
  tuyaDeviceId: CHILD_ID,
@@ -94,7 +93,7 @@ describe('LocalDeviceManager – Zigbee gateway reconnection', () => {
94
93
  ],
95
94
  };
96
95
 
97
- const mgr = new LocalDeviceManager(configWithOverride, log);
96
+ const mgr = new LocalDeviceManager(configWithOverride);
98
97
  // Should initialize without error even with per-child DP overrides
99
98
  await mgr.initLocalDevices();
100
99
 
@@ -131,7 +130,7 @@ describe('LocalDeviceManager – Zigbee gateway reconnection', () => {
131
130
  ],
132
131
  };
133
132
 
134
- const mgr = new LocalDeviceManager(configWithCategoryOverride, log);
133
+ const mgr = new LocalDeviceManager(configWithCategoryOverride);
135
134
  await mgr.initLocalDevices();
136
135
 
137
136
  const gwDevice = mgr.getDevice(GATEWAY_ID);
@@ -173,10 +172,10 @@ describe('LocalDeviceManager – Zigbee gateway reconnection', () => {
173
172
  ],
174
173
  };
175
174
 
176
- const mgr = new LocalDeviceManager(multiChildConfig, log);
175
+ const mgr = new LocalDeviceManager(multiChildConfig);
176
+ const infoSpy = jest.spyOn(mockLog, 'info');
177
177
  await mgr.initLocalDevices();
178
178
 
179
- const infoSpy = log.info as jest.MockedFunction<typeof log.info>;
180
179
  const infoCalls = infoSpy.mock.calls.map(c => String(c[0]));
181
180
  const gatewayLine = infoCalls.find(s => s.includes('Zigbee gateway detected'));
182
181
 
@@ -1,20 +1,19 @@
1
1
  import { describe, expect, it, beforeEach, afterEach, jest } from '@jest/globals';
2
2
  import LocalDeviceManager from '../../src/local/LocalDeviceManager';
3
3
  import { LocalConfig } from '../../src/local/config';
4
- import TuyaDeviceManager from '../../src/cloud/device/TuyaDeviceManager';
5
- import Logger from '../../src/shared/util/Logger';
4
+ import TuyaDevice from '../../src/cloud/device/TuyaDevice';
5
+ import TuyaCloudDeviceManager from '../../src/cloud/device/TuyaCloudDeviceManager';
6
+ import Logger, { ExLogger, initLogger } from '../../src/shared/util/Logger';
6
7
 
7
8
  // ── Logger mock ───────────────────────────────────────────────────────────────
8
-
9
- function makeMockLog(): Logger {
10
- return {
11
- debug: jest.fn(),
12
- info: jest.fn(),
13
- warn: jest.fn(),
14
- error: jest.fn(),
15
- log: jest.fn(),
16
- } as unknown as Logger;
17
- }
9
+ const mockLog: ExLogger = {
10
+ debug: jest.fn(),
11
+ info: jest.fn(),
12
+ warn: jest.fn(),
13
+ error: jest.fn(),
14
+ log: jest.fn(),
15
+ success: jest.fn(),
16
+ } as unknown as ExLogger;
18
17
 
19
18
  // ── Minimal config helpers ──────────────────────────────────────────────────
20
19
 
@@ -82,11 +81,10 @@ function standaloneConfig(): LocalConfig {
82
81
  // ── Tests ──────────────────────────────────────────────────────────────────────
83
82
 
84
83
  describe('LocalDeviceManager – Zigbee integration', () => {
85
- let log: Logger;
86
84
  let manager: LocalDeviceManager;
87
85
 
88
86
  beforeEach(() => {
89
- log = makeMockLog();
87
+ initLogger(mockLog);
90
88
  });
91
89
 
92
90
  afterEach(() => {
@@ -98,7 +96,7 @@ describe('LocalDeviceManager – Zigbee integration', () => {
98
96
 
99
97
  describe('initLocalDevices() – child device handling', () => {
100
98
  it('does not register child devices as TuyaDevices during first init pass', async () => {
101
- manager = new LocalDeviceManager(zigbeeConfig(), log);
99
+ manager = new LocalDeviceManager(zigbeeConfig());
102
100
  await manager.initLocalDevices();
103
101
 
104
102
  // Only the gateway should be in the device list initially
@@ -110,17 +108,17 @@ describe('LocalDeviceManager – Zigbee integration', () => {
110
108
  });
111
109
 
112
110
  it('registers standalone devices normally', async () => {
113
- manager = new LocalDeviceManager(standaloneConfig(), log);
111
+ manager = new LocalDeviceManager(standaloneConfig());
114
112
  await manager.initLocalDevices();
115
113
 
116
114
  expect(manager.devices.map(d => d.id)).toContain('standalone_001');
117
115
  });
118
116
 
119
117
  it('logs gateway relationships when detected', async () => {
120
- manager = new LocalDeviceManager(zigbeeConfig(), log);
118
+ manager = new LocalDeviceManager(zigbeeConfig());
119
+ const infoSpy = jest.spyOn(mockLog, 'info');
121
120
  await manager.initLocalDevices();
122
121
 
123
- const infoSpy = log.info as jest.MockedFunction<typeof log.info>;
124
122
  const infoCalls = infoSpy.mock.calls.map(c => String(c[0]));
125
123
  const gatewayLine = infoCalls.find(s => s.includes('Zigbee gateway'));
126
124
  expect(gatewayLine).toBeDefined();
@@ -128,7 +126,7 @@ describe('LocalDeviceManager – Zigbee integration', () => {
128
126
  });
129
127
 
130
128
  it('proceeds without fatal errors when no Zigbee devices in config', async () => {
131
- manager = new LocalDeviceManager(standaloneConfig(), log);
129
+ manager = new LocalDeviceManager(standaloneConfig());
132
130
  await expect(manager.initLocalDevices()).resolves.not.toThrow();
133
131
  });
134
132
  });
@@ -160,30 +158,70 @@ describe('LocalDeviceManager – Zigbee integration', () => {
160
158
  ],
161
159
  };
162
160
 
163
- manager = new LocalDeviceManager(badConfig, log);
161
+ manager = new LocalDeviceManager(badConfig);
162
+ const errorSpy = jest.spyOn(mockLog, 'error');
164
163
  await expect(manager.initLocalDevices()).resolves.not.toThrow();
165
164
 
166
- const errorSpy = log.error as jest.MockedFunction<typeof log.error>;
167
165
  const errorCalls = errorSpy.mock.calls.map(c => String(c[0]));
168
166
  const zigbeeErrorLine = errorCalls.find(s => s.includes('Zigbee'));
169
167
  expect(zigbeeErrorLine).toBeDefined();
170
168
  });
171
169
  });
172
170
 
171
+ // ── _syncConnectionInfo: shared local connection metadata ───────────────
172
+
173
+ describe('_syncConnectionInfo()', () => {
174
+ it('copies connection metadata from the sub-device to the parent when the parent is missing it', () => {
175
+ manager = new LocalDeviceManager(standaloneConfig());
176
+ const parent = new TuyaDevice({ id: 'parent', name: 'Parent' });
177
+ const sub = new TuyaDevice({ id: 'sub', name: 'Sub' });
178
+
179
+ (sub as TuyaDevice & { localIp?: string }).localIp = '192.168.1.11';
180
+ (sub as TuyaDevice & { localKey?: string }).localKey = 'sub-key';
181
+ (sub as TuyaDevice & { localVersion?: string }).localVersion = '3.4';
182
+
183
+ (manager as any)._syncConnectionInfo(parent, sub);
184
+
185
+ expect((parent as TuyaDevice & { localIp?: string }).localIp).toBe('192.168.1.11');
186
+ expect((parent as TuyaDevice & { localKey?: string }).localKey).toBe('sub-key');
187
+ expect((parent as TuyaDevice & { localVersion?: string }).localVersion).toBe('3.4');
188
+ expect((sub as TuyaDevice & { localIp?: string }).localIp).toBe('192.168.1.11');
189
+ });
190
+
191
+ it('prefers sub-device values over parent values when both are already populated', () => {
192
+ manager = new LocalDeviceManager(standaloneConfig());
193
+ const parent = new TuyaDevice({ id: 'parent', name: 'Parent' });
194
+ const sub = new TuyaDevice({ id: 'sub', name: 'Sub' });
195
+
196
+ (parent as TuyaDevice & { localIp?: string }).localIp = '192.168.1.10';
197
+ (parent as TuyaDevice & { localKey?: string }).localKey = 'parent-key';
198
+ (parent as TuyaDevice & { localVersion?: string }).localVersion = '3.3';
199
+ (sub as TuyaDevice & { localIp?: string }).localIp = '192.168.1.12';
200
+ (sub as TuyaDevice & { localKey?: string }).localKey = 'sub-key';
201
+ (sub as TuyaDevice & { localVersion?: string }).localVersion = '3.5';
202
+
203
+ (manager as any)._syncConnectionInfo(parent, sub);
204
+
205
+ expect((parent as TuyaDevice & { localIp?: string }).localIp).toBe('192.168.1.12');
206
+ expect((parent as TuyaDevice & { localKey?: string }).localKey).toBe('sub-key');
207
+ expect((parent as TuyaDevice & { localVersion?: string }).localVersion).toBe('3.5');
208
+ });
209
+ });
210
+
173
211
  // ── sendCommands: Zigbee child routing ─────────────────────────────────────
174
212
 
175
213
  describe('sendCommands() – Zigbee child routing', () => {
176
214
  it('returns without acting when device has no dpMapping (unknown device)', async () => {
177
- manager = new LocalDeviceManager(zigbeeConfig(), log);
215
+ manager = new LocalDeviceManager(zigbeeConfig());
178
216
  await manager.initLocalDevices();
179
217
 
180
218
  // CHILD_ID_A is not yet registered in the first pass
181
219
  const result = await manager.sendCommands('nonexistent_device', [{ code: 'switch_1', value: true }]);
182
- expect(result).toBeUndefined();
220
+ expect(result).toBe(false);
183
221
  });
184
222
 
185
223
  it('handles sendCommands for a known device that has a dpMapping', async () => {
186
- manager = new LocalDeviceManager(standaloneConfig(), log);
224
+ manager = new LocalDeviceManager(standaloneConfig());
187
225
  await manager.initLocalDevices();
188
226
 
189
227
  // 'standalone_001' is in the device list but has no IP connection (autoDiscover=false, no connect called)
@@ -198,14 +236,14 @@ describe('LocalDeviceManager – Zigbee integration', () => {
198
236
 
199
237
  describe('stopLocalDevices()', () => {
200
238
  it('does not throw when called with Zigbee gateway config and no active connections', async () => {
201
- manager = new LocalDeviceManager(zigbeeConfig(), log);
239
+ manager = new LocalDeviceManager(zigbeeConfig());
202
240
  await manager.initLocalDevices();
203
241
 
204
242
  expect(() => manager.stopLocalDevices()).not.toThrow();
205
243
  });
206
244
 
207
245
  it('can be called multiple times without error', async () => {
208
- manager = new LocalDeviceManager(zigbeeConfig(), log);
246
+ manager = new LocalDeviceManager(zigbeeConfig());
209
247
  await manager.initLocalDevices();
210
248
 
211
249
  expect(() => {
@@ -220,11 +258,11 @@ describe('LocalDeviceManager – Zigbee integration', () => {
220
258
  describe('_setupZigbeeChildren() – via gateway connect event', () => {
221
259
  it('emits DEVICE_ADD for child when gateway connects', async () => {
222
260
  const EventEmitter = (await import('events')).default;
223
- manager = new LocalDeviceManager(zigbeeConfig(), log);
261
+ manager = new LocalDeviceManager(zigbeeConfig());
224
262
  await manager.initLocalDevices();
225
263
 
226
264
  const deviceAddEvents: string[] = [];
227
- manager.on(TuyaDeviceManager.Events.DEVICE_ADD, (device: any) => {
265
+ manager.on(TuyaCloudDeviceManager.Events.DEVICE_ADD, (device: any) => {
228
266
  deviceAddEvents.push(device.id);
229
267
  });
230
268
 
@@ -249,7 +287,7 @@ describe('LocalDeviceManager – Zigbee integration', () => {
249
287
  });
250
288
 
251
289
  it('correctly maps child deviceId <-> cid in the relationship', async () => {
252
- manager = new LocalDeviceManager(zigbeeConfig(), log);
290
+ manager = new LocalDeviceManager(zigbeeConfig());
253
291
  await manager.initLocalDevices();
254
292
 
255
293
  const gatewayRelationships = (manager as any).gatewayRelationships as Map<string, any>;
@@ -271,7 +309,7 @@ describe('LocalDeviceManager – Zigbee integration', () => {
271
309
 
272
310
  describe('getDevice()', () => {
273
311
  it('returns the gateway TuyaDevice by ID', async () => {
274
- manager = new LocalDeviceManager(zigbeeConfig(), log);
312
+ manager = new LocalDeviceManager(zigbeeConfig());
275
313
  await manager.initLocalDevices();
276
314
 
277
315
  const gw = manager.getDevice(GATEWAY_ID);
@@ -281,7 +319,7 @@ describe('LocalDeviceManager – Zigbee integration', () => {
281
319
  });
282
320
 
283
321
  it('returns undefined for a child device before parent connects', async () => {
284
- manager = new LocalDeviceManager(zigbeeConfig(), log);
322
+ manager = new LocalDeviceManager(zigbeeConfig());
285
323
  await manager.initLocalDevices();
286
324
 
287
325
  // Children not yet registered (lazy registration happens on parent connect)
@@ -290,7 +328,7 @@ describe('LocalDeviceManager – Zigbee integration', () => {
290
328
  });
291
329
 
292
330
  it('returns undefined for a completely unknown device', async () => {
293
- manager = new LocalDeviceManager(zigbeeConfig(), log);
331
+ manager = new LocalDeviceManager(zigbeeConfig());
294
332
  await manager.initLocalDevices();
295
333
 
296
334
  expect(manager.getDevice('no_such_device')).toBeUndefined();
@@ -315,7 +353,7 @@ describe('LocalDeviceManager – Zigbee integration', () => {
315
353
  ],
316
354
  };
317
355
 
318
- manager = new LocalDeviceManager(mixedConfig, log);
356
+ manager = new LocalDeviceManager(mixedConfig);
319
357
  await manager.initLocalDevices();
320
358
 
321
359
  const ids = manager.devices.map(d => d.id);
@@ -326,7 +364,7 @@ describe('LocalDeviceManager – Zigbee integration', () => {
326
364
  });
327
365
 
328
366
  it('detects the correct number of gateway relationships', async () => {
329
- manager = new LocalDeviceManager(zigbeeConfig(), log);
367
+ manager = new LocalDeviceManager(zigbeeConfig());
330
368
  await manager.initLocalDevices();
331
369
 
332
370
  const gatewayRelationships = (manager as any).gatewayRelationships as Map<string, any>;
@@ -334,7 +372,7 @@ describe('LocalDeviceManager – Zigbee integration', () => {
334
372
  });
335
373
 
336
374
  it('has no gateway relationships for purely standalone config', async () => {
337
- manager = new LocalDeviceManager(standaloneConfig(), log);
375
+ manager = new LocalDeviceManager(standaloneConfig());
338
376
  await manager.initLocalDevices();
339
377
 
340
378
  const gatewayRelationships = (manager as any).gatewayRelationships as Map<string, any>;
@@ -112,13 +112,13 @@ describe('ZigbeeGatewayDetection', () => {
112
112
  device('child_1', { parentDeviceId: 'gw_1' }),
113
113
  ];
114
114
  expect(() => ZigbeeGatewayDetection.detectFromDevices(devices))
115
- .toThrow('parentDeviceId but is missing zigbeeChildId');
115
+ .toThrow('Device "child_1" has parentDeviceId:gw_1 but is missing zigbeeChildId. Both fields are required for Zigbee sub-devices.');
116
116
  });
117
117
 
118
118
  it('throws when zigbeeChildId is set without parentDeviceId', () => {
119
119
  const devices = [device('child_1', { zigbeeChildId: '0011223344556601' })];
120
120
  expect(() => ZigbeeGatewayDetection.detectFromDevices(devices))
121
- .toThrow('zigbeeChildId but is missing parentDeviceId');
121
+ .toThrow('Device "child_1" has zigbeeChildId:0011223344556601 but is missing parentDeviceId. Both fields are required for Zigbee sub-devices.');
122
122
  });
123
123
 
124
124
  it('throws for an invalid CID (too short)', () => {