@homebridge-plugins/homebridge-tuya 2.2.1 → 3.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +161 -144
  3. package/config.schema.json +976 -11
  4. package/dist/{core → cloud/api}/TuyaOpenAPI.js +6 -7
  5. package/dist/cloud/api/TuyaOpenAPI.js.map +1 -0
  6. package/dist/{core → cloud/api}/TuyaOpenMQ.js +13 -11
  7. package/dist/cloud/api/TuyaOpenMQ.js.map +1 -0
  8. package/dist/cloud/device/TuyaCustomDeviceManager.js.map +1 -0
  9. package/dist/{device → cloud/device}/TuyaDevice.js +14 -1
  10. package/dist/cloud/device/TuyaDevice.js.map +1 -0
  11. package/dist/{device → cloud/device}/TuyaDeviceManager.js +8 -3
  12. package/dist/cloud/device/TuyaDeviceManager.js.map +1 -0
  13. package/dist/cloud/device/TuyaHomeDeviceManager.js.map +1 -0
  14. package/dist/config.js +1 -0
  15. package/dist/config.js.map +1 -1
  16. package/dist/local/CloudLocalReconciliation.js +180 -0
  17. package/dist/local/CloudLocalReconciliation.js.map +1 -0
  18. package/dist/local/DynamicChildDiscovery.js +154 -0
  19. package/dist/local/DynamicChildDiscovery.js.map +1 -0
  20. package/dist/local/LocalDevice.js +419 -0
  21. package/dist/local/LocalDevice.js.map +1 -0
  22. package/dist/local/LocalDeviceManager.js +833 -0
  23. package/dist/local/LocalDeviceManager.js.map +1 -0
  24. package/dist/local/TuyaDiscovery.js +248 -0
  25. package/dist/local/TuyaDiscovery.js.map +1 -0
  26. package/dist/local/ZigbeeEventDetection.js +213 -0
  27. package/dist/local/ZigbeeEventDetection.js.map +1 -0
  28. package/dist/local/ZigbeeGatewayDetection.js +109 -0
  29. package/dist/local/ZigbeeGatewayDetection.js.map +1 -0
  30. package/dist/local/config.js +6 -0
  31. package/dist/local/config.js.map +1 -0
  32. package/dist/local/protocol/ChildPayloadUtility.js +94 -0
  33. package/dist/local/protocol/ChildPayloadUtility.js.map +1 -0
  34. package/dist/local/protocol/Protocol.js +3 -0
  35. package/dist/local/protocol/Protocol.js.map +1 -0
  36. package/dist/local/protocol/ProtocolFactory.js +27 -0
  37. package/dist/local/protocol/ProtocolFactory.js.map +1 -0
  38. package/dist/local/protocol/ProtocolUtilities.js +329 -0
  39. package/dist/local/protocol/ProtocolUtilities.js.map +1 -0
  40. package/dist/local/protocol/ProtocolV31V32.js +60 -0
  41. package/dist/local/protocol/ProtocolV31V32.js.map +1 -0
  42. package/dist/local/protocol/ProtocolV33.js +52 -0
  43. package/dist/local/protocol/ProtocolV33.js.map +1 -0
  44. package/dist/local/protocol/ProtocolV34.js +104 -0
  45. package/dist/local/protocol/ProtocolV34.js.map +1 -0
  46. package/dist/local/protocol/ProtocolV35.js +77 -0
  47. package/dist/local/protocol/ProtocolV35.js.map +1 -0
  48. package/dist/platform.js +149 -69
  49. package/dist/platform.js.map +1 -1
  50. package/dist/shared/AccessoryFactory.js +276 -0
  51. package/dist/shared/AccessoryFactory.js.map +1 -0
  52. package/dist/{accessory → shared/accessories}/AccessoryFactory.js +2 -2
  53. package/dist/shared/accessories/AccessoryFactory.js.map +1 -0
  54. package/dist/shared/accessories/AirConditionerAccessory.js.map +1 -0
  55. package/dist/{accessory → shared/accessories}/AirPurifierAccessory.js +1 -1
  56. package/dist/shared/accessories/AirPurifierAccessory.js.map +1 -0
  57. package/dist/shared/accessories/AirQualitySensorAccessory.js.map +1 -0
  58. package/dist/{accessory → shared/accessories}/BaseAccessory.js +99 -30
  59. package/dist/shared/accessories/BaseAccessory.js.map +1 -0
  60. package/dist/shared/accessories/BlindsAccessory.js +199 -0
  61. package/dist/shared/accessories/BlindsAccessory.js.map +1 -0
  62. package/dist/{accessory → shared/accessories}/CameraAccessory.js +7 -3
  63. package/dist/shared/accessories/CameraAccessory.js.map +1 -0
  64. package/dist/shared/accessories/CarbonDioxideSensorAccessory.js.map +1 -0
  65. package/dist/shared/accessories/CarbonMonoxideSensorAccessory.js.map +1 -0
  66. package/dist/shared/accessories/ContactSensorAccessory.js.map +1 -0
  67. package/dist/shared/accessories/DehumidifierAccessory.js.map +1 -0
  68. package/dist/shared/accessories/DiffuserAccessory.js.map +1 -0
  69. package/dist/shared/accessories/DimmerAccessory.js.map +1 -0
  70. package/dist/{accessory → shared/accessories}/DoorbellAccessory.js +3 -1
  71. package/dist/shared/accessories/DoorbellAccessory.js.map +1 -0
  72. package/dist/{accessory → shared/accessories}/ExtractionHoodAccessory.js +4 -2
  73. package/dist/shared/accessories/ExtractionHoodAccessory.js.map +1 -0
  74. package/dist/{accessory → shared/accessories}/FanAccessory.js +10 -4
  75. package/dist/shared/accessories/FanAccessory.js.map +1 -0
  76. package/dist/shared/accessories/GarageDoorAccessory.js.map +1 -0
  77. package/dist/shared/accessories/HeaterAccessory.js.map +1 -0
  78. package/dist/shared/accessories/HeaterAccessory_old.js.map +1 -0
  79. package/dist/shared/accessories/HumanPresenceSensorAccessory.js.map +1 -0
  80. package/dist/{accessory → shared/accessories}/HumidifierAccessory.js +3 -1
  81. package/dist/shared/accessories/HumidifierAccessory.js.map +1 -0
  82. package/dist/{accessory → shared/accessories}/IRAirConditionerAccessory.js +2 -2
  83. package/dist/shared/accessories/IRAirConditionerAccessory.js.map +1 -0
  84. package/dist/shared/accessories/IRControlHubAccessory.js.map +1 -0
  85. package/dist/shared/accessories/IRControlHubSubAccessory.js.map +1 -0
  86. package/dist/shared/accessories/IRGenericAccessory.js.map +1 -0
  87. package/dist/shared/accessories/LeakSensorAccessory.js.map +1 -0
  88. package/dist/shared/accessories/LightAccessory.js.map +1 -0
  89. package/dist/shared/accessories/LightSensorAccessory.js.map +1 -0
  90. package/dist/shared/accessories/LocationWeatherAccessory.js.map +1 -0
  91. package/dist/shared/accessories/LockAccessory.js.map +1 -0
  92. package/dist/shared/accessories/MotionSensorAccessory.js.map +1 -0
  93. package/dist/shared/accessories/OutletAccessory.js.map +1 -0
  94. package/dist/shared/accessories/PetFeederAccessory.js.map +1 -0
  95. package/dist/shared/accessories/SceneAccessory.js.map +1 -0
  96. package/dist/{accessory → shared/accessories}/SceneSwitchAccessory.js +1 -1
  97. package/dist/shared/accessories/SceneSwitchAccessory.js.map +1 -0
  98. package/dist/shared/accessories/SecuritySystemAccessory.js.map +1 -0
  99. package/dist/shared/accessories/SmokeSensorAccessory.js.map +1 -0
  100. package/dist/shared/accessories/SwitchAccessory.js +148 -0
  101. package/dist/shared/accessories/SwitchAccessory.js.map +1 -0
  102. package/dist/shared/accessories/TemperatureHumiditySensorAccessory.js.map +1 -0
  103. package/dist/shared/accessories/ThermostatAccessory.js.map +1 -0
  104. package/dist/shared/accessories/TowerRackAccessory.js.map +1 -0
  105. package/dist/{accessory → shared/accessories}/ValveAccessory.js +1 -1
  106. package/dist/shared/accessories/ValveAccessory.js.map +1 -0
  107. package/dist/{accessory → shared/accessories}/VibrationSensorAccessory.js +7 -3
  108. package/dist/shared/accessories/VibrationSensorAccessory.js.map +1 -0
  109. package/dist/shared/accessories/WeatherStationAccessory.js.map +1 -0
  110. package/dist/shared/accessories/WetBulbGlobeTemperatureAccessory.js.map +1 -0
  111. package/dist/shared/accessories/WhiteNoiseLightAccessory.js.map +1 -0
  112. package/dist/shared/accessories/WindowAccessory.js.map +1 -0
  113. package/dist/shared/accessories/WindowCoveringAccessory.js.map +1 -0
  114. package/dist/shared/accessories/WirelessSwitchAccessory.js.map +1 -0
  115. package/dist/shared/accessories/characteristic/Active.js.map +1 -0
  116. package/dist/{accessory → shared/accessories}/characteristic/AirQuality.js +1 -1
  117. package/dist/shared/accessories/characteristic/AirQuality.js.map +1 -0
  118. package/dist/shared/accessories/characteristic/CurrentRelativeHumidity.js.map +1 -0
  119. package/dist/shared/accessories/characteristic/CurrentTemperature.js.map +1 -0
  120. package/dist/shared/accessories/characteristic/CurrentWeather.js.map +1 -0
  121. package/dist/shared/accessories/characteristic/CurrentWeatherByOpenMeteo.js.map +1 -0
  122. package/dist/shared/accessories/characteristic/CurrentWetBulbGlobeTemperature.js.map +1 -0
  123. package/dist/shared/accessories/characteristic/EnergyUsage.js.map +1 -0
  124. package/dist/shared/accessories/characteristic/Light.js.map +1 -0
  125. package/dist/shared/accessories/characteristic/LightSensor.js.map +1 -0
  126. package/dist/shared/accessories/characteristic/LockPhysicalControls.js.map +1 -0
  127. package/dist/{accessory → shared/accessories}/characteristic/MotionDetected.js +1 -1
  128. package/dist/shared/accessories/characteristic/MotionDetected.js.map +1 -0
  129. package/dist/shared/accessories/characteristic/Name.js.map +1 -0
  130. package/dist/shared/accessories/characteristic/OccupancyDetected.js.map +1 -0
  131. package/dist/{accessory → shared/accessories}/characteristic/On.js +1 -1
  132. package/dist/shared/accessories/characteristic/On.js.map +1 -0
  133. package/dist/shared/accessories/characteristic/OutletInUse.js.map +1 -0
  134. package/dist/{accessory → shared/accessories}/characteristic/ProgrammableSwitchEvent.js +2 -2
  135. package/dist/shared/accessories/characteristic/ProgrammableSwitchEvent.js.map +1 -0
  136. package/dist/shared/accessories/characteristic/RelativeHumidityDehumidifierThreshold.js.map +1 -0
  137. package/dist/shared/accessories/characteristic/RotationSpeed.js.map +1 -0
  138. package/dist/shared/accessories/characteristic/SecuritySystemState.js.map +1 -0
  139. package/dist/shared/accessories/characteristic/SwingMode.js.map +1 -0
  140. package/dist/shared/accessories/characteristic/TargetTemperature.js.map +1 -0
  141. package/dist/shared/accessories/characteristic/TemperatureDisplayUnits.js.map +1 -0
  142. package/dist/shared/util/ConfigHash.js +79 -0
  143. package/dist/shared/util/ConfigHash.js.map +1 -0
  144. package/dist/shared/util/FfmpegStreamingProcess.js.map +1 -0
  145. package/dist/shared/util/InfraredTool.js.map +1 -0
  146. package/dist/shared/util/Logger.js.map +1 -0
  147. package/dist/shared/util/TuyaRecordingDelegate.js.map +1 -0
  148. package/dist/shared/util/TuyaStreamDelegate.js.map +1 -0
  149. package/dist/shared/util/color.js.map +1 -0
  150. package/dist/shared/util/util.js +135 -0
  151. package/dist/shared/util/util.js.map +1 -0
  152. package/eslint.config.mjs +52 -0
  153. package/jest.config.js +6 -0
  154. package/package.json +22 -27
  155. package/test/__mocks__/@homebridge-camera-utils.js +10 -0
  156. package/test/__mocks__/color-convert.js +24 -0
  157. package/test/__mocks__/kelvin-to-rgb.js +21 -0
  158. package/test/accessoryFactory.test.ts +522 -0
  159. package/test/config.test.ts +430 -0
  160. package/test/custom.test.ts +4 -4
  161. package/test/errorHandling.test.ts +570 -0
  162. package/test/errorHandlingCoverage.test.ts +410 -0
  163. package/test/home.test.ts +4 -4
  164. package/test/localDevice.test.ts +616 -0
  165. package/test/localDeviceManager.behavior.test.ts +185 -0
  166. package/test/localDeviceManager.test.ts +268 -0
  167. package/test/mqttMessages.test.ts +495 -0
  168. package/test/platform.test.ts +515 -0
  169. package/test/platform.validation.local.test.ts +250 -0
  170. package/test/protocol.test.ts +446 -0
  171. package/test/protocolUtilities.test.ts +351 -0
  172. package/test/sanitizeName.test.ts +2 -1
  173. package/test/tuyaCustomDeviceManager.test.ts +469 -0
  174. package/test/tuyaDevice.test.ts +425 -0
  175. package/test/tuyaDeviceManager.test.ts +813 -0
  176. package/test/tuyaDiscovery.test.ts +439 -0
  177. package/test/tuyaHomeDeviceManager.test.ts +540 -0
  178. package/test/tuyaOpenAPI.test.ts +404 -0
  179. package/test/tuyaOpenMQ.test.ts +444 -0
  180. package/test/util.test.ts +318 -0
  181. package/test/util.ts +4 -3
  182. package/test/zigbee/ChildPayloadUtility.test.ts +199 -0
  183. package/test/zigbee/CloudLocalReconciliation.test.ts +284 -0
  184. package/test/zigbee/DynamicChildDiscovery.test.ts +333 -0
  185. package/test/zigbee/LocalDevice.zigbee.test.ts +274 -0
  186. package/test/zigbee/LocalDeviceManager.cloud-discovery.test.ts +163 -0
  187. package/test/zigbee/LocalDeviceManager.zigbee.reconnect.test.ts +200 -0
  188. package/test/zigbee/LocalDeviceManager.zigbee.test.ts +344 -0
  189. package/test/zigbee/ZigbeeEventDetection.test.ts +418 -0
  190. package/test/zigbee/ZigbeeGatewayDetection.test.ts +222 -0
  191. package/tuya-local-configs/dev-1.hash +1 -0
  192. package/tuya-local-configs/device1.hash +1 -0
  193. package/wiki/Get-Local-Keys-for-Your-Devices.md +85 -0
  194. package/dist/accessory/AccessoryFactory.js.map +0 -1
  195. package/dist/accessory/AirConditionerAccessory.js.map +0 -1
  196. package/dist/accessory/AirPurifierAccessory.js.map +0 -1
  197. package/dist/accessory/AirQualitySensorAccessory.js.map +0 -1
  198. package/dist/accessory/BaseAccessory.js.map +0 -1
  199. package/dist/accessory/CameraAccessory.js.map +0 -1
  200. package/dist/accessory/CarbonDioxideSensorAccessory.js.map +0 -1
  201. package/dist/accessory/CarbonMonoxideSensorAccessory.js.map +0 -1
  202. package/dist/accessory/ContactSensorAccessory.js.map +0 -1
  203. package/dist/accessory/DehumidifierAccessory.js.map +0 -1
  204. package/dist/accessory/DiffuserAccessory.js.map +0 -1
  205. package/dist/accessory/DimmerAccessory.js.map +0 -1
  206. package/dist/accessory/DoorbellAccessory.js.map +0 -1
  207. package/dist/accessory/ExtractionHoodAccessory.js.map +0 -1
  208. package/dist/accessory/FanAccessory.js.map +0 -1
  209. package/dist/accessory/GarageDoorAccessory.js.map +0 -1
  210. package/dist/accessory/HeaterAccessory.js.map +0 -1
  211. package/dist/accessory/HeaterAccessory_old.js.map +0 -1
  212. package/dist/accessory/HumanPresenceSensorAccessory.js.map +0 -1
  213. package/dist/accessory/HumidifierAccessory.js.map +0 -1
  214. package/dist/accessory/IRAirConditionerAccessory.js.map +0 -1
  215. package/dist/accessory/IRControlHubAccessory.js.map +0 -1
  216. package/dist/accessory/IRControlHubSubAccessory.js.map +0 -1
  217. package/dist/accessory/IRGenericAccessory.js.map +0 -1
  218. package/dist/accessory/LeakSensorAccessory.js.map +0 -1
  219. package/dist/accessory/LightAccessory.js.map +0 -1
  220. package/dist/accessory/LightSensorAccessory.js.map +0 -1
  221. package/dist/accessory/LocationWeatherAccessory.js.map +0 -1
  222. package/dist/accessory/LockAccessory.js.map +0 -1
  223. package/dist/accessory/MotionSensorAccessory.js.map +0 -1
  224. package/dist/accessory/OutletAccessory.js.map +0 -1
  225. package/dist/accessory/PetFeederAccessory.js.map +0 -1
  226. package/dist/accessory/SceneAccessory.js.map +0 -1
  227. package/dist/accessory/SceneSwitchAccessory.js.map +0 -1
  228. package/dist/accessory/SecuritySystemAccessory.js.map +0 -1
  229. package/dist/accessory/SmokeSensorAccessory.js.map +0 -1
  230. package/dist/accessory/SwitchAccessory.js +0 -85
  231. package/dist/accessory/SwitchAccessory.js.map +0 -1
  232. package/dist/accessory/TemperatureHumiditySensorAccessory.js.map +0 -1
  233. package/dist/accessory/ThermostatAccessory.js.map +0 -1
  234. package/dist/accessory/TowerRackAccessory.js.map +0 -1
  235. package/dist/accessory/ValveAccessory.js.map +0 -1
  236. package/dist/accessory/VibrationSensorAccessory.js.map +0 -1
  237. package/dist/accessory/WeatherStationAccessory.js.map +0 -1
  238. package/dist/accessory/WetBulbGlobeTemperatureAccessory.js.map +0 -1
  239. package/dist/accessory/WhiteNoiseLightAccessory.js.map +0 -1
  240. package/dist/accessory/WindowAccessory.js.map +0 -1
  241. package/dist/accessory/WindowCoveringAccessory.js.map +0 -1
  242. package/dist/accessory/WirelessSwitchAccessory.js.map +0 -1
  243. package/dist/accessory/characteristic/Active.js.map +0 -1
  244. package/dist/accessory/characteristic/AirQuality.js.map +0 -1
  245. package/dist/accessory/characteristic/CurrentRelativeHumidity.js.map +0 -1
  246. package/dist/accessory/characteristic/CurrentTemperature.js.map +0 -1
  247. package/dist/accessory/characteristic/CurrentWeather.js.map +0 -1
  248. package/dist/accessory/characteristic/CurrentWeatherByOpenMeteo.js.map +0 -1
  249. package/dist/accessory/characteristic/CurrentWetBulbGlobeTemperature.js.map +0 -1
  250. package/dist/accessory/characteristic/EnergyUsage.js.map +0 -1
  251. package/dist/accessory/characteristic/Light.js.map +0 -1
  252. package/dist/accessory/characteristic/LightSensor.js.map +0 -1
  253. package/dist/accessory/characteristic/LockPhysicalControls.js.map +0 -1
  254. package/dist/accessory/characteristic/MotionDetected.js.map +0 -1
  255. package/dist/accessory/characteristic/Name.js.map +0 -1
  256. package/dist/accessory/characteristic/OccupancyDetected.js.map +0 -1
  257. package/dist/accessory/characteristic/On.js.map +0 -1
  258. package/dist/accessory/characteristic/OutletInUse.js.map +0 -1
  259. package/dist/accessory/characteristic/ProgrammableSwitchEvent.js.map +0 -1
  260. package/dist/accessory/characteristic/RelativeHumidityDehumidifierThreshold.js.map +0 -1
  261. package/dist/accessory/characteristic/RotationSpeed.js.map +0 -1
  262. package/dist/accessory/characteristic/SecuritySystemState.js.map +0 -1
  263. package/dist/accessory/characteristic/SwingMode.js.map +0 -1
  264. package/dist/accessory/characteristic/TargetTemperature.js.map +0 -1
  265. package/dist/accessory/characteristic/TemperatureDisplayUnits.js.map +0 -1
  266. package/dist/core/TuyaOpenAPI.js.map +0 -1
  267. package/dist/core/TuyaOpenMQ.js.map +0 -1
  268. package/dist/device/TuyaCustomDeviceManager.js.map +0 -1
  269. package/dist/device/TuyaDevice.js.map +0 -1
  270. package/dist/device/TuyaDeviceManager.js.map +0 -1
  271. package/dist/device/TuyaHomeDeviceManager.js.map +0 -1
  272. package/dist/util/FfmpegStreamingProcess.js.map +0 -1
  273. package/dist/util/InfraredTool.js.map +0 -1
  274. package/dist/util/Logger.js.map +0 -1
  275. package/dist/util/TuyaRecordingDelegate.js.map +0 -1
  276. package/dist/util/TuyaStreamDelegate.js.map +0 -1
  277. package/dist/util/color.js.map +0 -1
  278. package/dist/util/util.js +0 -63
  279. package/dist/util/util.js.map +0 -1
  280. /package/dist/{device → cloud/device}/TuyaCustomDeviceManager.js +0 -0
  281. /package/dist/{device → cloud/device}/TuyaHomeDeviceManager.js +0 -0
  282. /package/dist/{accessory → shared/accessories}/AirConditionerAccessory.js +0 -0
  283. /package/dist/{accessory → shared/accessories}/AirQualitySensorAccessory.js +0 -0
  284. /package/dist/{accessory → shared/accessories}/CarbonDioxideSensorAccessory.js +0 -0
  285. /package/dist/{accessory → shared/accessories}/CarbonMonoxideSensorAccessory.js +0 -0
  286. /package/dist/{accessory → shared/accessories}/ContactSensorAccessory.js +0 -0
  287. /package/dist/{accessory → shared/accessories}/DehumidifierAccessory.js +0 -0
  288. /package/dist/{accessory → shared/accessories}/DiffuserAccessory.js +0 -0
  289. /package/dist/{accessory → shared/accessories}/DimmerAccessory.js +0 -0
  290. /package/dist/{accessory → shared/accessories}/GarageDoorAccessory.js +0 -0
  291. /package/dist/{accessory → shared/accessories}/HeaterAccessory.js +0 -0
  292. /package/dist/{accessory → shared/accessories}/HeaterAccessory_old.js +0 -0
  293. /package/dist/{accessory → shared/accessories}/HumanPresenceSensorAccessory.js +0 -0
  294. /package/dist/{accessory → shared/accessories}/IRControlHubAccessory.js +0 -0
  295. /package/dist/{accessory → shared/accessories}/IRControlHubSubAccessory.js +0 -0
  296. /package/dist/{accessory → shared/accessories}/IRGenericAccessory.js +0 -0
  297. /package/dist/{accessory → shared/accessories}/LeakSensorAccessory.js +0 -0
  298. /package/dist/{accessory → shared/accessories}/LightAccessory.js +0 -0
  299. /package/dist/{accessory → shared/accessories}/LightSensorAccessory.js +0 -0
  300. /package/dist/{accessory → shared/accessories}/LocationWeatherAccessory.js +0 -0
  301. /package/dist/{accessory → shared/accessories}/LockAccessory.js +0 -0
  302. /package/dist/{accessory → shared/accessories}/MotionSensorAccessory.js +0 -0
  303. /package/dist/{accessory → shared/accessories}/OutletAccessory.js +0 -0
  304. /package/dist/{accessory → shared/accessories}/PetFeederAccessory.js +0 -0
  305. /package/dist/{accessory → shared/accessories}/SceneAccessory.js +0 -0
  306. /package/dist/{accessory → shared/accessories}/SecuritySystemAccessory.js +0 -0
  307. /package/dist/{accessory → shared/accessories}/SmokeSensorAccessory.js +0 -0
  308. /package/dist/{accessory → shared/accessories}/TemperatureHumiditySensorAccessory.js +0 -0
  309. /package/dist/{accessory → shared/accessories}/ThermostatAccessory.js +0 -0
  310. /package/dist/{accessory → shared/accessories}/TowerRackAccessory.js +0 -0
  311. /package/dist/{accessory → shared/accessories}/WeatherStationAccessory.js +0 -0
  312. /package/dist/{accessory → shared/accessories}/WetBulbGlobeTemperatureAccessory.js +0 -0
  313. /package/dist/{accessory → shared/accessories}/WhiteNoiseLightAccessory.js +0 -0
  314. /package/dist/{accessory → shared/accessories}/WindowAccessory.js +0 -0
  315. /package/dist/{accessory → shared/accessories}/WindowCoveringAccessory.js +0 -0
  316. /package/dist/{accessory → shared/accessories}/WirelessSwitchAccessory.js +0 -0
  317. /package/dist/{accessory → shared/accessories}/characteristic/Active.js +0 -0
  318. /package/dist/{accessory → shared/accessories}/characteristic/CurrentRelativeHumidity.js +0 -0
  319. /package/dist/{accessory → shared/accessories}/characteristic/CurrentTemperature.js +0 -0
  320. /package/dist/{accessory → shared/accessories}/characteristic/CurrentWeather.js +0 -0
  321. /package/dist/{accessory → shared/accessories}/characteristic/CurrentWeatherByOpenMeteo.js +0 -0
  322. /package/dist/{accessory → shared/accessories}/characteristic/CurrentWetBulbGlobeTemperature.js +0 -0
  323. /package/dist/{accessory → shared/accessories}/characteristic/EnergyUsage.js +0 -0
  324. /package/dist/{accessory → shared/accessories}/characteristic/Light.js +0 -0
  325. /package/dist/{accessory → shared/accessories}/characteristic/LightSensor.js +0 -0
  326. /package/dist/{accessory → shared/accessories}/characteristic/LockPhysicalControls.js +0 -0
  327. /package/dist/{accessory → shared/accessories}/characteristic/Name.js +0 -0
  328. /package/dist/{accessory → shared/accessories}/characteristic/OccupancyDetected.js +0 -0
  329. /package/dist/{accessory → shared/accessories}/characteristic/OutletInUse.js +0 -0
  330. /package/dist/{accessory → shared/accessories}/characteristic/RelativeHumidityDehumidifierThreshold.js +0 -0
  331. /package/dist/{accessory → shared/accessories}/characteristic/RotationSpeed.js +0 -0
  332. /package/dist/{accessory → shared/accessories}/characteristic/SecuritySystemState.js +0 -0
  333. /package/dist/{accessory → shared/accessories}/characteristic/SwingMode.js +0 -0
  334. /package/dist/{accessory → shared/accessories}/characteristic/TargetTemperature.js +0 -0
  335. /package/dist/{accessory → shared/accessories}/characteristic/TemperatureDisplayUnits.js +0 -0
  336. /package/dist/{util → shared/util}/FfmpegStreamingProcess.js +0 -0
  337. /package/dist/{util → shared/util}/InfraredTool.js +0 -0
  338. /package/dist/{util → shared/util}/Logger.js +0 -0
  339. /package/dist/{util → shared/util}/TuyaRecordingDelegate.js +0 -0
  340. /package/dist/{util → shared/util}/TuyaStreamDelegate.js +0 -0
  341. /package/dist/{util → shared/util}/color.js +0 -0
@@ -0,0 +1,570 @@
1
+ /* eslint-disable no-console */
2
+ import { describe, expect, test, beforeEach, jest } from '@jest/globals';
3
+ import TuyaDevice from '../src/cloud/device/TuyaDevice';
4
+
5
+ // Mock Logger
6
+ jest.mock('../src/shared/util/Logger', () => ({
7
+ __esModule: true,
8
+ default: class Logger {
9
+ log() {}
10
+ info() {}
11
+ warn() {}
12
+ error() {}
13
+ },
14
+ PrefixLogger: class PrefixLogger {
15
+ constructor(public log: any, public name: string, public debug: boolean) {}
16
+ },
17
+ }));
18
+
19
+ describe('Error Handling & Edge Cases', () => {
20
+ describe('device initialization edge cases', () => {
21
+ test('handles device with minimal properties', () => {
22
+ const device = new TuyaDevice({
23
+ id: 'device_001',
24
+ product_id: 'prod_001',
25
+ category: 'dj',
26
+ name: 'Device',
27
+ status: [],
28
+ });
29
+
30
+ expect(device).toBeDefined();
31
+ expect(device.id).toBe('device_001');
32
+ });
33
+
34
+ test('handles device with null optional fields', () => {
35
+ const device = new TuyaDevice({
36
+ id: 'device_001',
37
+ product_id: 'prod_001',
38
+ category: 'dj',
39
+ name: 'Device',
40
+ icon: null as any,
41
+ model: undefined,
42
+ status: [],
43
+ });
44
+
45
+ expect(device.id).toBe('device_001');
46
+ });
47
+
48
+ test('handles empty string fields', () => {
49
+ const device = new TuyaDevice({
50
+ id: '',
51
+ product_id: '',
52
+ category: 'dj',
53
+ name: '',
54
+ status: [],
55
+ });
56
+
57
+ expect(device).toBeDefined();
58
+ });
59
+
60
+ test('handles special characters in device name', () => {
61
+ const device = new TuyaDevice({
62
+ id: 'device_001',
63
+ product_id: 'prod_001',
64
+ category: 'dj',
65
+ name: 'Device @#$% & ()',
66
+ status: [],
67
+ });
68
+
69
+ expect(device.name).toBe('Device @#$% & ()');
70
+ });
71
+
72
+ test('handles very long device name', () => {
73
+ const longName = 'A'.repeat(1000);
74
+ const device = new TuyaDevice({
75
+ id: 'device_001',
76
+ product_id: 'prod_001',
77
+ category: 'dj',
78
+ name: longName,
79
+ status: [],
80
+ });
81
+
82
+ expect(device.name).toBe(longName);
83
+ });
84
+
85
+ test('handles unicode characters in device name', () => {
86
+ const device = new TuyaDevice({
87
+ id: 'device_001',
88
+ product_id: 'prod_001',
89
+ category: 'dj',
90
+ name: '智能灯 🏠 スマートライト',
91
+ status: [],
92
+ });
93
+
94
+ expect(device.name).toBe('智能灯 🏠 スマートライト');
95
+ });
96
+ });
97
+
98
+ describe('status handling edge cases', () => {
99
+ test('handles empty status array', () => {
100
+ const device = new TuyaDevice({
101
+ id: 'device_001',
102
+ product_id: 'prod_001',
103
+ category: 'dj',
104
+ name: 'Device',
105
+ status: [],
106
+ });
107
+
108
+ expect(device.status.length).toBe(0);
109
+ });
110
+
111
+ test('handles status with boolean values', () => {
112
+ const device = new TuyaDevice({
113
+ id: 'device_001',
114
+ product_id: 'prod_001',
115
+ category: 'dj',
116
+ name: 'Device',
117
+ status: [
118
+ { code: 'switch', value: true },
119
+ { code: 'online', value: false },
120
+ ],
121
+ });
122
+
123
+ expect(device.status[0].value).toBe(true);
124
+ expect(device.status[1].value).toBe(false);
125
+ });
126
+
127
+ test('handles status with numeric values', () => {
128
+ const device = new TuyaDevice({
129
+ id: 'device_001',
130
+ product_id: 'prod_001',
131
+ category: 'dj',
132
+ name: 'Device',
133
+ status: [
134
+ { code: 'brightness', value: 255 },
135
+ { code: 'temperature', value: -40 },
136
+ { code: 'zero_value', value: 0 },
137
+ ],
138
+ });
139
+
140
+ expect(device.status[0].value).toBe(255);
141
+ expect(device.status[1].value).toBe(-40);
142
+ expect(device.status[2].value).toBe(0);
143
+ });
144
+
145
+ test('handles status with string values', () => {
146
+ const device = new TuyaDevice({
147
+ id: 'device_001',
148
+ product_id: 'prod_001',
149
+ category: 'dj',
150
+ name: 'Device',
151
+ status: [{ code: 'mode', value: 'heat' }],
152
+ });
153
+
154
+ expect(device.status[0].value).toBe('heat');
155
+ });
156
+
157
+ test('preserves status order from input', () => {
158
+ const device = new TuyaDevice({
159
+ id: 'device_001',
160
+ product_id: 'prod_001',
161
+ category: 'dj',
162
+ name: 'Device',
163
+ status: [
164
+ { code: 'zebra', value: 1 },
165
+ { code: 'alpha', value: 2 },
166
+ { code: 'beta', value: 3 },
167
+ ],
168
+ });
169
+
170
+ // Status should maintain input order, not be sorted
171
+ expect(device.status[0].code).toBe('zebra');
172
+ expect(device.status[1].code).toBe('alpha');
173
+ expect(device.status[2].code).toBe('beta');
174
+ });
175
+
176
+ test('handles duplicate status codes', () => {
177
+ const device = new TuyaDevice({
178
+ id: 'device_001',
179
+ product_id: 'prod_001',
180
+ category: 'dj',
181
+ name: 'Device',
182
+ status: [
183
+ { code: 'switch', value: true },
184
+ { code: 'switch', value: false },
185
+ ],
186
+ });
187
+
188
+ expect(device.status.length).toBe(2);
189
+ });
190
+ });
191
+
192
+ describe('schema handling edge cases', () => {
193
+ test('handles empty schema array', () => {
194
+ const device = new TuyaDevice({
195
+ id: 'device_001',
196
+ product_id: 'prod_001',
197
+ category: 'dj',
198
+ name: 'Device',
199
+ status: [],
200
+ schema: [],
201
+ });
202
+
203
+ expect(device.schema.length).toBe(0);
204
+ });
205
+
206
+ test('handles schema with complex properties', () => {
207
+ const device = new TuyaDevice({
208
+ id: 'device_001',
209
+ product_id: 'prod_001',
210
+ category: 'dj',
211
+ name: 'Device',
212
+ status: [],
213
+ schema: [
214
+ {
215
+ code: 'brightness',
216
+ mode: 'rw' as any,
217
+ type: 'Integer' as any,
218
+ property: {
219
+ min: 0,
220
+ max: 255,
221
+ scale: 0,
222
+ step: 1,
223
+ unit: 'lux',
224
+ },
225
+ },
226
+ ],
227
+ });
228
+
229
+ expect(device.schema.length).toBe(1);
230
+ expect((device.schema[0].property as any).min).toBe(0);
231
+ });
232
+
233
+ test('handles very large schema arrays', () => {
234
+ const largeSchema = Array.from({ length: 1000 }, (_, i) => ({
235
+ code: `property_${i}`,
236
+ mode: 'rw' as any,
237
+ type: 'Boolean' as any,
238
+ property: {} as any,
239
+ }));
240
+
241
+ const device = new TuyaDevice({
242
+ id: 'device_001',
243
+ product_id: 'prod_001',
244
+ category: 'dj',
245
+ name: 'Device',
246
+ status: [],
247
+ schema: largeSchema,
248
+ });
249
+
250
+ expect(device.schema.length).toBe(1000);
251
+ });
252
+ });
253
+
254
+ describe('device virtual status', () => {
255
+ test('handles virtual device flag', () => {
256
+ const device = new TuyaDevice({
257
+ id: 'virtual_001',
258
+ product_id: 'prod_001',
259
+ category: 'dj',
260
+ name: 'Virtual',
261
+ status: [],
262
+ sub: true,
263
+ parent_id: 'parent_device',
264
+ });
265
+
266
+ expect(device.sub).toBe(true);
267
+ expect(device.parent_id).toBe('parent_device');
268
+ });
269
+
270
+ test('detects virtual device by ID prefix', () => {
271
+ const virtualDevice = new TuyaDevice({
272
+ id: 'vdevo123456789',
273
+ product_id: 'prod_001',
274
+ category: 'dj',
275
+ name: 'Virtual',
276
+ status: [],
277
+ });
278
+
279
+ expect(virtualDevice.isVirtualDevice()).toBe(true);
280
+ });
281
+
282
+ test('regular device is not virtual', () => {
283
+ const regularDevice = new TuyaDevice({
284
+ id: 'device_001',
285
+ product_id: 'prod_001',
286
+ category: 'dj',
287
+ name: 'Device',
288
+ status: [],
289
+ });
290
+
291
+ expect(regularDevice.isVirtualDevice()).toBe(false);
292
+ });
293
+ });
294
+
295
+ describe('device type detection', () => {
296
+ test('detects IR control hub', () => {
297
+ const irHub = new TuyaDevice({
298
+ id: 'wnykq_001',
299
+ product_id: 'ir_prod',
300
+ category: 'wnykq',
301
+ name: 'IR Hub',
302
+ status: [],
303
+ });
304
+
305
+ expect(irHub.isIRControlHub()).toBe(true);
306
+ });
307
+
308
+ test('detects IR remote control', () => {
309
+ const irRemote = new TuyaDevice({
310
+ id: 'remote_001',
311
+ product_id: 'ir_prod',
312
+ category: 'infrared_ac',
313
+ name: 'IR Remote',
314
+ status: [],
315
+ });
316
+
317
+ expect(irRemote.isIRRemoteControl()).toBe(true);
318
+ });
319
+
320
+ test('regular device is not IR control', () => {
321
+ const regular = new TuyaDevice({
322
+ id: 'device_001',
323
+ product_id: 'prod_001',
324
+ category: 'dj',
325
+ name: 'Light',
326
+ status: [],
327
+ });
328
+
329
+ expect(regular.isIRControlHub()).toBe(false);
330
+ expect(regular.isIRRemoteControl()).toBe(false);
331
+ });
332
+ });
333
+
334
+ describe('device properties boundary cases', () => {
335
+ test('handles max values for numeric properties', () => {
336
+ const device = new TuyaDevice({
337
+ id: 'device_001',
338
+ product_id: 'prod_001',
339
+ category: 'dj',
340
+ name: 'Device',
341
+ status: [],
342
+ create_time: Number.MAX_SAFE_INTEGER,
343
+ });
344
+
345
+ expect(device.create_time).toBe(Number.MAX_SAFE_INTEGER);
346
+ });
347
+
348
+ test('handles negative values', () => {
349
+ const device = new TuyaDevice({
350
+ id: 'device_001',
351
+ product_id: 'prod_001',
352
+ category: 'dj',
353
+ name: 'Device',
354
+ status: [],
355
+ lat: '-90',
356
+ lon: '-180',
357
+ });
358
+
359
+ expect(device.lat).toBe('-90');
360
+ expect(device.lon).toBe('-180');
361
+ });
362
+
363
+ test('handles geographic coordinates', () => {
364
+ const device = new TuyaDevice({
365
+ id: 'device_001',
366
+ product_id: 'prod_001',
367
+ category: 'dj',
368
+ name: 'Device',
369
+ status: [],
370
+ lat: '40.7128',
371
+ lon: '-74.0060',
372
+ });
373
+
374
+ expect(device.lat).toBe('40.7128');
375
+ expect(device.lon).toBe('-74.0060');
376
+ });
377
+ });
378
+
379
+ describe('array operations on devices', () => {
380
+ test('handles sorting array of devices', () => {
381
+ const devices = [
382
+ new TuyaDevice({
383
+ id: 'z_device',
384
+ product_id: 'prod_z',
385
+ category: 'dj',
386
+ name: 'Z Device',
387
+ status: [],
388
+ }),
389
+ new TuyaDevice({
390
+ id: 'a_device',
391
+ product_id: 'prod_a',
392
+ category: 'dj',
393
+ name: 'A Device',
394
+ status: [],
395
+ }),
396
+ new TuyaDevice({
397
+ id: 'm_device',
398
+ product_id: 'prod_m',
399
+ category: 'dj',
400
+ name: 'M Device',
401
+ status: [],
402
+ }),
403
+ ];
404
+
405
+ const sorted = devices.sort((a, b) => a.id.localeCompare(b.id));
406
+
407
+ expect(sorted[0].id).toBe('a_device');
408
+ expect(sorted[1].id).toBe('m_device');
409
+ expect(sorted[2].id).toBe('z_device');
410
+ });
411
+
412
+ test('handles filtering devices by category', () => {
413
+ const devices = [
414
+ new TuyaDevice({
415
+ id: 'light_1',
416
+ product_id: 'prod_1',
417
+ category: 'dj',
418
+ name: 'Light',
419
+ status: [],
420
+ }),
421
+ new TuyaDevice({
422
+ id: 'switch_1',
423
+ product_id: 'prod_2',
424
+ category: 'kg',
425
+ name: 'Switch',
426
+ status: [],
427
+ }),
428
+ new TuyaDevice({
429
+ id: 'light_2',
430
+ product_id: 'prod_3',
431
+ category: 'dj',
432
+ name: 'Another Light',
433
+ status: [],
434
+ }),
435
+ ];
436
+
437
+ const lights = devices.filter((d) => d.category === 'dj');
438
+ expect(lights.length).toBe(2);
439
+ });
440
+
441
+ test('handles mapping device properties', () => {
442
+ const devices = [
443
+ new TuyaDevice({
444
+ id: 'dev_1',
445
+ product_id: 'prod_1',
446
+ category: 'dj',
447
+ name: 'Device 1',
448
+ status: [],
449
+ }),
450
+ new TuyaDevice({
451
+ id: 'dev_2',
452
+ product_id: 'prod_2',
453
+ category: 'kg',
454
+ name: 'Device 2',
455
+ status: [],
456
+ }),
457
+ ];
458
+
459
+ const ids = devices.map((d) => d.id);
460
+ expect(ids).toEqual(['dev_1', 'dev_2']);
461
+ });
462
+ });
463
+
464
+ describe('configuration validation edge cases', () => {
465
+ test('handles missing required fields gracefully', () => {
466
+ const minimalDevice = new TuyaDevice({
467
+ id: 'dev',
468
+ product_id: 'prod',
469
+ category: 'dj',
470
+ name: 'Device',
471
+ status: [],
472
+ });
473
+
474
+ expect(minimalDevice).toBeDefined();
475
+ expect(minimalDevice.id).toBe('dev');
476
+ });
477
+
478
+ test('handles undefined overwriting default values', () => {
479
+ const device = new TuyaDevice({
480
+ id: 'device_001',
481
+ product_id: 'prod_001',
482
+ category: 'dj',
483
+ name: 'Device',
484
+ status: [],
485
+ online: undefined,
486
+ });
487
+
488
+ expect(device).toBeDefined();
489
+ });
490
+ });
491
+
492
+ describe('concurrent device operations', () => {
493
+ test('handles multiple device instantiations', () => {
494
+ const devices = Array.from({ length: 100 }, (_, i) =>
495
+ new TuyaDevice({
496
+ id: `dev_${i}`,
497
+ product_id: `prod_${i}`,
498
+ category: i % 2 === 0 ? 'dj' : 'kg',
499
+ name: `Device ${i}`,
500
+ status: [],
501
+ })
502
+ );
503
+
504
+ expect(devices.length).toBe(100);
505
+ expect(devices[0].id).toBe('dev_0');
506
+ expect(devices[99].id).toBe('dev_99');
507
+ });
508
+
509
+ test('devices maintain independent state', () => {
510
+ const device1 = new TuyaDevice({
511
+ id: 'dev_1',
512
+ product_id: 'prod_1',
513
+ category: 'dj',
514
+ name: 'Device 1',
515
+ status: [{ code: 's1', value: 1 }],
516
+ });
517
+
518
+ const device2 = new TuyaDevice({
519
+ id: 'dev_2',
520
+ product_id: 'prod_2',
521
+ category: 'kg',
522
+ name: 'Device 2',
523
+ status: [{ code: 's2', value: 2 }],
524
+ });
525
+
526
+ expect(device1.status[0].code).toBe('s1');
527
+ expect(device2.status[0].code).toBe('s2');
528
+ });
529
+ });
530
+
531
+ describe('null and undefined handling', () => {
532
+ test('handles null in optional fields', () => {
533
+ const device = new TuyaDevice({
534
+ id: 'device_001',
535
+ product_id: 'prod_001',
536
+ category: 'dj',
537
+ name: 'Device',
538
+ status: [],
539
+ model: null as any,
540
+ icon: null as any,
541
+ });
542
+
543
+ expect(device.model).toBe(null);
544
+ expect(device.icon).toBe(null);
545
+ });
546
+
547
+ test('distinguishes between undefined and null', () => {
548
+ const device1 = new TuyaDevice({
549
+ id: 'dev1',
550
+ product_id: 'prod1',
551
+ category: 'dj',
552
+ name: 'Dev1',
553
+ status: [],
554
+ model: undefined,
555
+ });
556
+
557
+ const device2 = new TuyaDevice({
558
+ id: 'dev2',
559
+ product_id: 'prod2',
560
+ category: 'dj',
561
+ name: 'Dev2',
562
+ status: [],
563
+ model: null as any,
564
+ });
565
+
566
+ expect(device1.model).toBeUndefined();
567
+ expect(device2.model).toBeNull();
568
+ });
569
+ });
570
+ });