tuya2ildevice 0.1.0__tar.gz

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 (421) hide show
  1. tuya2ildevice-0.1.0/.gitignore +9 -0
  2. tuya2ildevice-0.1.0/LICENSE +21 -0
  3. tuya2ildevice-0.1.0/PKG-INFO +146 -0
  4. tuya2ildevice-0.1.0/README.md +127 -0
  5. tuya2ildevice-0.1.0/docs/analysis/PHASE1_SYNTHESIS.md +85 -0
  6. tuya2ildevice-0.1.0/docs/analysis/PHASE2_GAP_ANALYSIS.md +277 -0
  7. tuya2ildevice-0.1.0/docs/analysis/PHASE3_SPEC_REVIEW.md +296 -0
  8. tuya2ildevice-0.1.0/docs/analysis/PHASE4_GOLDEN.md +16 -0
  9. tuya2ildevice-0.1.0/docs/analysis/SDK_CONVERT_INVESTIGATION.md +121 -0
  10. tuya2ildevice-0.1.0/docs/analysis/SOURCES.txt +6 -0
  11. tuya2ildevice-0.1.0/docs/analysis/catalog/A_value_transform.md +208 -0
  12. tuya2ildevice-0.1.0/docs/analysis/catalog/B_quirks.md +157 -0
  13. tuya2ildevice-0.1.0/docs/analysis/catalog/C_light_climate_fan_humidifier.md +440 -0
  14. tuya2ildevice-0.1.0/docs/analysis/catalog/D_cover_vacuum_valve_siren_alarm.md +357 -0
  15. tuya2ildevice-0.1.0/docs/analysis/catalog/E_simple_platforms.md +473 -0
  16. tuya2ildevice-0.1.0/docs/analysis/catalog/F_core_crosscutting.md +256 -0
  17. tuya2ildevice-0.1.0/docs/engine-spec.md +441 -0
  18. tuya2ildevice-0.1.0/pyproject.toml +34 -0
  19. tuya2ildevice-0.1.0/scripts/gen_core_tables.py +131 -0
  20. tuya2ildevice-0.1.0/scripts/gen_host_units.py +16 -0
  21. tuya2ildevice-0.1.0/scripts/gen_quirks.py +58 -0
  22. tuya2ildevice-0.1.0/scripts/golden/README.md +38 -0
  23. tuya2ildevice-0.1.0/scripts/golden/ambr.py +79 -0
  24. tuya2ildevice-0.1.0/scripts/golden/build_golden.py +48 -0
  25. tuya2ildevice-0.1.0/scripts/golden/extract_actions.py +55 -0
  26. tuya2ildevice-0.1.0/scripts/golden/quirk_oracle.py +33 -0
  27. tuya2ildevice-0.1.0/scripts/golden/quirk_oracle_synthetic.py +18 -0
  28. tuya2ildevice-0.1.0/scripts/golden/snapshots.json +7907 -0
  29. tuya2ildevice-0.1.0/scripts/golden/synthetic_snapshots.json +272 -0
  30. tuya2ildevice-0.1.0/src/tuya2ildevice/__init__.py +18 -0
  31. tuya2ildevice-0.1.0/src/tuya2ildevice/assemble.py +397 -0
  32. tuya2ildevice-0.1.0/src/tuya2ildevice/checks.py +69 -0
  33. tuya2ildevice-0.1.0/src/tuya2ildevice/converters.py +139 -0
  34. tuya2ildevice-0.1.0/src/tuya2ildevice/driver.py +266 -0
  35. tuya2ildevice-0.1.0/src/tuya2ildevice/fallback.py +96 -0
  36. tuya2ildevice-0.1.0/src/tuya2ildevice/host/__init__.py +20 -0
  37. tuya2ildevice-0.1.0/src/tuya2ildevice/host/bridge.py +37 -0
  38. tuya2ildevice-0.1.0/src/tuya2ildevice/host/devices.py +87 -0
  39. tuya2ildevice-0.1.0/src/tuya2ildevice/host/memory.py +65 -0
  40. tuya2ildevice-0.1.0/src/tuya2ildevice/host/mqtt.py +103 -0
  41. tuya2ildevice-0.1.0/src/tuya2ildevice/host/runner.py +137 -0
  42. tuya2ildevice-0.1.0/src/tuya2ildevice/host/transport.py +27 -0
  43. tuya2ildevice-0.1.0/src/tuya2ildevice/io.py +96 -0
  44. tuya2ildevice-0.1.0/src/tuya2ildevice/mqtt.py +322 -0
  45. tuya2ildevice-0.1.0/src/tuya2ildevice/overrides.py +209 -0
  46. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/__init__.py +8 -0
  47. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/adapter.py +208 -0
  48. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/codecs.py +104 -0
  49. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/data/host_units.json +766 -0
  50. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/model.py +144 -0
  51. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/ops.py +71 -0
  52. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/platforms.py +1034 -0
  53. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/quirks/quirks.json +916 -0
  54. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/quirks.py +104 -0
  55. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/runtime.py +127 -0
  56. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/_enums.json +560 -0
  57. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/_units.json +208 -0
  58. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/alarm_control_panel.json +29 -0
  59. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/binary_sensor.json +591 -0
  60. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/button.json +69 -0
  61. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/camera.json +15 -0
  62. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/climate.json +57 -0
  63. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/cover.json +131 -0
  64. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/event.json +104 -0
  65. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/fan.json +35 -0
  66. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/humidifier.json +29 -0
  67. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/light.json +470 -0
  68. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/number.json +627 -0
  69. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/select.json +510 -0
  70. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/sensor.json +3796 -0
  71. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/siren.json +49 -0
  72. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/switch.json +1377 -0
  73. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/vacuum.json +19 -0
  74. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/tables/valve.json +87 -0
  75. tuya2ildevice-0.1.0/src/tuya2ildevice/tuya/units.py +42 -0
  76. tuya2ildevice-0.1.0/tests/chain/baseline.json +58 -0
  77. tuya2ildevice-0.1.0/tests/chain/conftest.py +11 -0
  78. tuya2ildevice-0.1.0/tests/chain/measure.py +45 -0
  79. tuya2ildevice-0.1.0/tests/chain/props.py +81 -0
  80. tuya2ildevice-0.1.0/tests/chain/test_counts.py +41 -0
  81. tuya2ildevice-0.1.0/tests/chain/test_props.py +45 -0
  82. tuya2ildevice-0.1.0/tests/conftest.py +6 -0
  83. tuya2ildevice-0.1.0/tests/golden/actions_golden.json +887 -0
  84. tuya2ildevice-0.1.0/tests/golden/core_fixtures/bh_dft4ebatvon3ha5s.json +80 -0
  85. tuya2ildevice-0.1.0/tests/golden/core_fixtures/bzyd_45idzfufidgee7ir.json +137 -0
  86. tuya2ildevice-0.1.0/tests/golden/core_fixtures/bzyd_ssimhf6r8kgwepfb.json +76 -0
  87. tuya2ildevice-0.1.0/tests/golden/core_fixtures/bzyd_tkqgkrutewrmbn9c.json +147 -0
  88. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cjkg_hmabvy81.json +283 -0
  89. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cjkg_uenof8jd.json +171 -0
  90. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ckmkzq_1yyqfw4djv9eii3q.json +59 -0
  91. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cl_3r8gc33pnqsxfe1g.json +122 -0
  92. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cl_669wsr2w4cvinbh4.json +138 -0
  93. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cl_cpbo62rn.json +100 -0
  94. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cl_ebt12ypvexnixvtf.json +57 -0
  95. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cl_g1cp07dsqnbdbbki.json +102 -0
  96. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cl_lfkr93x0ukp5gaia.json +138 -0
  97. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cl_n3xgr5pdmpinictg.json +37 -0
  98. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cl_qqdxfdht.json +65 -0
  99. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cl_qtemqjy7axczkkls.json +109 -0
  100. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cl_rD7uqAAgQOpSA2Rx.json +37 -0
  101. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cl_zah67ekd.json +60 -0
  102. tuya2ildevice-0.1.0/tests/golden/core_fixtures/clkg_nhyj64w2.json +93 -0
  103. tuya2ildevice-0.1.0/tests/golden/core_fixtures/clkg_wltqkykhni0papzj.json +114 -0
  104. tuya2ildevice-0.1.0/tests/golden/core_fixtures/clkg_xqvhthwkbmp3aghs.json +114 -0
  105. tuya2ildevice-0.1.0/tests/golden/core_fixtures/clkg_y7j64p60glp8qpx7.json +108 -0
  106. tuya2ildevice-0.1.0/tests/golden/core_fixtures/co2bj_yakol79dibtswovc.json +56 -0
  107. tuya2ildevice-0.1.0/tests/golden/core_fixtures/co2bj_yrr3eiyiacm31ski.json +285 -0
  108. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cobj_hcdy5zrq3ikzthws.json +59 -0
  109. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cs_b9oyi2yofflroq1g.json +134 -0
  110. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cs_biflejkeshx1sqig.json +130 -0
  111. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cs_eguoms25tkxtf5u8.json +88 -0
  112. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cs_ipmyy4nigpqcnd8q.json +40 -0
  113. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cs_ka2wfrdoogpvgzfi.json +127 -0
  114. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cs_qhxmvae667uap4zh.json +30 -0
  115. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cs_u0wirz487erb0eka.json +169 -0
  116. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cs_vmxuxszzjwp5smli.json +30 -0
  117. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cs_zibqa9dutqyaxym2.json +54 -0
  118. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cwjwq_agwu93lr.json +64 -0
  119. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cwwsq_lxfvx41gqdotrkgi.json +111 -0
  120. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cwwsq_wfkzyy0evslzsmoi.json +99 -0
  121. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cwysj_akln8rb04cav403q.json +73 -0
  122. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cwysj_z3rpyvznfcch99aa.json +130 -0
  123. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_0fHWRe8ULjtmnBNd.json +149 -0
  124. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_0g1fmqh6d5io7lcn.json +54 -0
  125. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_2iepauebcvo74ujc.json +168 -0
  126. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_2jxesipczks0kdct.json +86 -0
  127. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_37mnhia3pojleqfh.json +87 -0
  128. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_39sy2g68gsjwo2xv.json +155 -0
  129. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_4mbgrfotyNzMxDAv.json +87 -0
  130. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_6fa7odsufen374x2.json +168 -0
  131. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_79a7z01v3n35kytb.json +21 -0
  132. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_9ivirni8wemum6cw.json +87 -0
  133. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_AiHXxAyyn7eAkLQY.json +54 -0
  134. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_CHLZe9HQ6QIXujVN.json +54 -0
  135. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_EYfNTuTPZln9e4cn.json +87 -0
  136. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_ExGgQmjt0SHMdlDZ.json +57 -0
  137. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_HBRBzv1UVBVfF6SL.json +56 -0
  138. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_IGzCi97RpN2Lf9cu.json +149 -0
  139. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_PGEkBctAbtzKOZng.json +54 -0
  140. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_anwgf2xugjxpkfxb.json +116 -0
  141. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_cuhokdii7ojyw8k2.json +54 -0
  142. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_dhto3y4uachr1wll.json +21 -0
  143. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_dntgh2ngvshfxpsz.json +33 -0
  144. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_fbvia0apnlnattcy.json +101 -0
  145. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_fencxse0bnut96ig.json +100 -0
  146. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_gbtxrqfy9xcsakyp.json +168 -0
  147. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_gjnozsaz.json +133 -0
  148. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_guitoc9iylae4axs.json +217 -0
  149. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_hA2GsgMfTQFTz9JL.json +54 -0
  150. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_hj0a5c7ckzzexu8l.json +98 -0
  151. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_ik9sbig3mthx9hjz.json +168 -0
  152. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_ipabufmlmodje1ws.json +165 -0
  153. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_iqhidxhhmgxk5eja.json +54 -0
  154. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_jnbbxsb84gvvyfg5.json +56 -0
  155. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_jti3ce2hzvsposgj.json +215 -0
  156. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_mQUhiTg9kwydBFBd.json +87 -0
  157. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_n8iVBAPLFKAAAszH.json +54 -0
  158. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_nkb0fmtlfyqosnvk.json +98 -0
  159. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_nx8rv6jpe1tsnffk.json +116 -0
  160. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_piuensvr.json +33 -0
  161. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_qm0iq4nqnrlzh4qc.json +168 -0
  162. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_qxJSyTLEtX5WrzA9.json +87 -0
  163. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_raceucn29wk2yawe.json +56 -0
  164. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_sb6bwb1n8ma2c5q4.json +168 -0
  165. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_t0a4hwsf8anfsadp.json +116 -0
  166. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_tf6qp8t3hl9h7m94.json +86 -0
  167. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_tkn2s79mzedk6pwr.json +160 -0
  168. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_vrbpx6h7fsi5mujb.json +223 -0
  169. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_vxqn72kwtosoy4d3.json +98 -0
  170. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_w0qqde0g.json +133 -0
  171. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_wifvoilfrqeo6hvu.json +98 -0
  172. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_wrz6vzch8htux2zp.json +168 -0
  173. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_y4jnobxh.json +33 -0
  174. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_yncyws7tu1q4cpsz.json +37 -0
  175. tuya2ildevice-0.1.0/tests/golden/core_fixtures/cz_z6pht25s3p0gs26q.json +207 -0
  176. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dc_l3bpgg8ibsagon4x.json +147 -0
  177. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dd_gaobbrxqiblcng2p.json +21 -0
  178. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dgnbj_layxxij0sdbrfmrf.json +508 -0
  179. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_0gyaslysqfp4gfis.json +557 -0
  180. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_8szt7whdvwpmxglk.json +493 -0
  181. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_8ugheslg.json +57 -0
  182. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_8y0aquaa8v6tho8w.json +336 -0
  183. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_AqHUMdcbYzIq1Of4.json +508 -0
  184. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_amx1bgdrfab6jngb.json +333 -0
  185. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_bSXSSFArVKtc4DyC.json +54 -0
  186. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_baf9tt9lb8t5uc7z.json +75 -0
  187. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_c3nsqogqovapdpfj.json +348 -0
  188. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_d4g0fbsoaal841o6.json +375 -0
  189. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_dbou1ap4.json +390 -0
  190. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_djnozmdyqyriow8z.json +482 -0
  191. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_ekwolitfjhxn55js.json +557 -0
  192. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_fuupmcr2mb1odkja.json +336 -0
  193. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_h4aX2JkHZNByQ4AV.json +54 -0
  194. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_hp6orhaqm6as3jnv.json +508 -0
  195. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_hpc8ddyfv85haxa7.json +154 -0
  196. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_iayz2jmtlipjnxj7.json +527 -0
  197. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_idnfq7xbx8qewyoa.json +521 -0
  198. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_ilddqqih3tucdk68.json +75 -0
  199. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_j1bgp31cffutizub.json +432 -0
  200. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_k3okx0w3bsgmindp.json +921 -0
  201. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_kgaob37tz2muf3mi.json +548 -0
  202. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_lmnt3uyltk1xffrt.json +75 -0
  203. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_mki13ie507rlry4r.json +456 -0
  204. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_nbumqpv8vz61enji.json +557 -0
  205. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_nlxvjzy1hoeiqsg6.json +75 -0
  206. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_oe0cpnjg.json +224 -0
  207. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_oj4fqh3fo3obgu6a.json +830 -0
  208. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_p06rbu0a9jp37ixo.json +899 -0
  209. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_qoqolwtqzfuhgghq.json +477 -0
  210. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_riwp3k79.json +400 -0
  211. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_tgewj70aowigv8fz.json +140 -0
  212. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_tmsloaroqavbucgn.json +375 -0
  213. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_ufq2xwuzd4nb0qdr.json +333 -0
  214. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_vqwcnabamzrc2kab.json +530 -0
  215. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_xdvitmhhmgefaeuq.json +510 -0
  216. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_xokdfs6kh5ednakk.json +375 -0
  217. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_yfqmcabsid3gkd1y.json +379 -0
  218. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_zakhnlpdiu0ycdxn.json +75 -0
  219. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_zav1pa32pyxray78.json +320 -0
  220. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dj_zputiamzanuk6yky.json +411 -0
  221. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dlq_0tnvg2xaisqdadcf.json +247 -0
  222. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dlq_cnpkf4xdmd9v49iq.json +158 -0
  223. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dlq_dikb3dp6.json +146 -0
  224. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dlq_fygozcnralhwbauo.json +268 -0
  225. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dlq_jdj6ccklup7btq3a.json +216 -0
  226. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dlq_kxdr6su0c55p7bbo.json +135 -0
  227. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dlq_r9kg2g1uhhyicycb.json +143 -0
  228. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dlq_z3jngbyubvwgfrcv.json +222 -0
  229. tuya2ildevice-0.1.0/tests/golden/core_fixtures/dr_pjvxl1wsyqxivsaf.json +185 -0
  230. tuya2ildevice-0.1.0/tests/golden/core_fixtures/fs_g0ewlb1vmwqljzji.json +132 -0
  231. tuya2ildevice-0.1.0/tests/golden/core_fixtures/fs_ibytpo6fpnugft1c.json +21 -0
  232. tuya2ildevice-0.1.0/tests/golden/core_fixtures/fsd_9ecs16c53uqskxw6.json +151 -0
  233. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ggq_7ytb3h8u.json +52 -0
  234. tuya2ildevice-0.1.0/tests/golden/core_fixtures/gyd_lgekqfxdabipm3tn.json +263 -0
  235. tuya2ildevice-0.1.0/tests/golden/core_fixtures/hcdd_expmpw4xxd0kkifb.json +91 -0
  236. tuya2ildevice-0.1.0/tests/golden/core_fixtures/hjjcy_9f8pjxsmaqnk2tzr.json +334 -0
  237. tuya2ildevice-0.1.0/tests/golden/core_fixtures/hps_2aaelwxk.json +184 -0
  238. tuya2ildevice-0.1.0/tests/golden/core_fixtures/hps_wqashyqo.json +41 -0
  239. tuya2ildevice-0.1.0/tests/golden/core_fixtures/hwsb_ircs2n82vgrozoew.json +34 -0
  240. tuya2ildevice-0.1.0/tests/golden/core_fixtures/infrared_ac_47peys.json +96 -0
  241. tuya2ildevice-0.1.0/tests/golden/core_fixtures/infrared_ac_qzktzhehinzsz2je.json +96 -0
  242. tuya2ildevice-0.1.0/tests/golden/core_fixtures/infrared_tv_47pew0.json +129 -0
  243. tuya2ildevice-0.1.0/tests/golden/core_fixtures/infrared_tv_lplun31mo1xaonwz.json +129 -0
  244. tuya2ildevice-0.1.0/tests/golden/core_fixtures/jsq_r492ifwk6f2ssptb.json +86 -0
  245. tuya2ildevice-0.1.0/tests/golden/core_fixtures/jtmspro_xqeob8h6.json +398 -0
  246. tuya2ildevice-0.1.0/tests/golden/core_fixtures/kg_4nqs33emdwJxpQ8O.json +54 -0
  247. tuya2ildevice-0.1.0/tests/golden/core_fixtures/kg_5ftkaulg.json +80 -0
  248. tuya2ildevice-0.1.0/tests/golden/core_fixtures/kg_gbm9ata1zrzaez4a.json +54 -0
  249. tuya2ildevice-0.1.0/tests/golden/core_fixtures/kj_CAjWAxBUZt7QZHfz.json +84 -0
  250. tuya2ildevice-0.1.0/tests/golden/core_fixtures/kj_fsxtzzhujkrak2oy.json +104 -0
  251. tuya2ildevice-0.1.0/tests/golden/core_fixtures/kj_s4uzibibgzdxzowo.json +115 -0
  252. tuya2ildevice-0.1.0/tests/golden/core_fixtures/kj_yrzylxax1qspdgpp.json +77 -0
  253. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ks_j9fa8ahzac8uvlfl.json +105 -0
  254. tuya2ildevice-0.1.0/tests/golden/core_fixtures/kt_5wnlzekkstwcdsvm.json +78 -0
  255. tuya2ildevice-0.1.0/tests/golden/core_fixtures/kt_ibmmirhhq62mmf1g.json +110 -0
  256. tuya2ildevice-0.1.0/tests/golden/core_fixtures/kt_vdadlnmsorlhw4td.json +78 -0
  257. tuya2ildevice-0.1.0/tests/golden/core_fixtures/kt_wxqdp6ecfkd78zzz.json +152 -0
  258. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ktkzq_urzivdhumrwfakie.json +74 -0
  259. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ldcg_9kbbfeho.json +45 -0
  260. tuya2ildevice-0.1.0/tests/golden/core_fixtures/mal_gyitctrjj1kefxp2.json +224 -0
  261. tuya2ildevice-0.1.0/tests/golden/core_fixtures/mc_oSQljE9YDqwCwTUA.json +35 -0
  262. tuya2ildevice-0.1.0/tests/golden/core_fixtures/mcs_6ywsnauy.json +44 -0
  263. tuya2ildevice-0.1.0/tests/golden/core_fixtures/mcs_7jIGJAymiH8OsFFb.json +41 -0
  264. tuya2ildevice-0.1.0/tests/golden/core_fixtures/mcs_8yhypbo7.json +39 -0
  265. tuya2ildevice-0.1.0/tests/golden/core_fixtures/mcs_hx5ztlztij4yxxvg.json +35 -0
  266. tuya2ildevice-0.1.0/tests/golden/core_fixtures/mcs_oxslv1c9.json +39 -0
  267. tuya2ildevice-0.1.0/tests/golden/core_fixtures/mcs_qxu3flpqjsc1kqu3.json +39 -0
  268. tuya2ildevice-0.1.0/tests/golden/core_fixtures/msp_3ddulzljdjjwkhoy.json +149 -0
  269. tuya2ildevice-0.1.0/tests/golden/core_fixtures/msp_5t7esmqqh92ssbe5.json +54 -0
  270. tuya2ildevice-0.1.0/tests/golden/core_fixtures/msp_mzuro9jgjs7uiryn.json +155 -0
  271. tuya2ildevice-0.1.0/tests/golden/core_fixtures/mzj_jlapoy5liocmtdvd.json +21 -0
  272. tuya2ildevice-0.1.0/tests/golden/core_fixtures/mzj_qavcakohisj5adyh.json +117 -0
  273. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ntq_9mqdhwklpvnnvb7t.json +21 -0
  274. tuya2ildevice-0.1.0/tests/golden/core_fixtures/pc_t2afic7i3v1bwhfp.json +42 -0
  275. tuya2ildevice-0.1.0/tests/golden/core_fixtures/pc_trjopo1vdlt9q1tg.json +84 -0
  276. tuya2ildevice-0.1.0/tests/golden/core_fixtures/pc_tsbguim4trl6fa7g.json +188 -0
  277. tuya2ildevice-0.1.0/tests/golden/core_fixtures/pc_yku9wsimasckdt15.json +189 -0
  278. tuya2ildevice-0.1.0/tests/golden/core_fixtures/pir_3amxzozho9xp4mkh.json +42 -0
  279. tuya2ildevice-0.1.0/tests/golden/core_fixtures/pir_fcdjzz3s.json +46 -0
  280. tuya2ildevice-0.1.0/tests/golden/core_fixtures/pir_j5jgnjvdaczeb6dc.json +21 -0
  281. tuya2ildevice-0.1.0/tests/golden/core_fixtures/pir_o1l76njefmksbgkk.json +77 -0
  282. tuya2ildevice-0.1.0/tests/golden/core_fixtures/pir_wqz93nrdomectyoz.json +37 -0
  283. tuya2ildevice-0.1.0/tests/golden/core_fixtures/qccdz_7bvgooyjhiua1yyq.json +103 -0
  284. tuya2ildevice-0.1.0/tests/golden/core_fixtures/qccdz_dsmsam7xpb3ht7rl.json +157 -0
  285. tuya2ildevice-0.1.0/tests/golden/core_fixtures/qn_5ls2jw49hpczwqng.json +21 -0
  286. tuya2ildevice-0.1.0/tests/golden/core_fixtures/qt_TtXKwTMwiPpURWLJ.json +37 -0
  287. tuya2ildevice-0.1.0/tests/golden/core_fixtures/qxj_fsea1lat3vuktbt6.json +410 -0
  288. tuya2ildevice-0.1.0/tests/golden/core_fixtures/qxj_is2indt9nlth6esa.json +63 -0
  289. tuya2ildevice-0.1.0/tests/golden/core_fixtures/qxj_xbwbniyt6bgws9ia.json +265 -0
  290. tuya2ildevice-0.1.0/tests/golden/core_fixtures/rqbj_4iqe2hsfyd86kwwc.json +88 -0
  291. tuya2ildevice-0.1.0/tests/golden/core_fixtures/rs_d7woucobqi8ncacf.json +57 -0
  292. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sd_i6hyjg3af7doaswm.json +64 -0
  293. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sd_lr33znaodtyarrrz.json +474 -0
  294. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sfkzq_1fcnd8xk.json +130 -0
  295. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sfkzq_d4vpmigg.json +130 -0
  296. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sfkzq_ed7frwissyqrejic.json +282 -0
  297. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sfkzq_kcdiut0eqeni7b8n.json +132 -0
  298. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sfkzq_nxquc5lb.json +130 -0
  299. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sfkzq_o6dagifntoafakst.json +54 -0
  300. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sfkzq_rzklytdei8i8vo37.json +100 -0
  301. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sgbj_DYgId0sz6zWlmmYu.json +74 -0
  302. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sgbj_im2eqqhj72suwwko.json +92 -0
  303. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sgbj_ulv4nnue7gqp0rjk.json +67 -0
  304. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sj_rzeSU2h9uoklxEwq.json +41 -0
  305. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sj_tgvtvdoc.json +41 -0
  306. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sjz_ftbc8rp8ipksdfpv.json +143 -0
  307. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sp_6bmk1remyscwyx6i.json +229 -0
  308. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sp_csr2fqitalj5o0tq.json +127 -0
  309. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sp_drezasavompxpcgm.json +180 -0
  310. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sp_ehzbfjrau5lbph4o.json +160 -0
  311. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sp_knkaf1d0dytgyhix.json +289 -0
  312. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sp_nzauwyj3mcnjnf35.json +220 -0
  313. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sp_rjKXWRohlvOTyLBu.json +211 -0
  314. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sp_rudejjigkywujjvs.json +240 -0
  315. tuya2ildevice-0.1.0/tests/golden/core_fixtures/sp_sdd5f5f2dl5wydjf.json +381 -0
  316. tuya2ildevice-0.1.0/tests/golden/core_fixtures/swtz_3rzngbyy.json +116 -0
  317. tuya2ildevice-0.1.0/tests/golden/core_fixtures/szjcy_u5xgcpcngk3pfxb4.json +56 -0
  318. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tdq_1aegphq4yfd50e6b.json +137 -0
  319. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tdq_1ctrc5jx88mtdh9w.json +303 -0
  320. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tdq_9htyiowaf5rtdhrv.json +137 -0
  321. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tdq_cq1p0nt0a4rixnex.json +246 -0
  322. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tdq_emb5khohohihmbxc.json +303 -0
  323. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tdq_gdknjvdpiwoq6smx.json +253 -0
  324. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tdq_nockvv2k39vbrxxk.json +225 -0
  325. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tdq_p6sqiuesvhmhvv4f.json +21 -0
  326. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tdq_pu8uhxhwcp3tgoz7.json +167 -0
  327. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tdq_uoa3mayicscacseb.json +21 -0
  328. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tdq_x3o8epevyeo3z3oa.json +21 -0
  329. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tyndj_pyakuuoc.json +143 -0
  330. tuya2ildevice-0.1.0/tests/golden/core_fixtures/tzc1_5vlawhjm.json +210 -0
  331. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wfcon_b25mh8sxawsgndck.json +21 -0
  332. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wfcon_lieerjyy6l4ykjor.json +21 -0
  333. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wfcon_plp0gnfcacdeqk5o.json +21 -0
  334. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wg2_2gowdgni.json +77 -0
  335. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wg2_haclbl0qkqlf2qds.json +77 -0
  336. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wg2_nwxr8qcu4seltoro.json +88 -0
  337. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wg2_pkhw2vbphv4csrir.json +135 -0
  338. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wg2_setmxeqgs63xwopm.json +68 -0
  339. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wg2_tmwhss6ntjfc7prs.json +21 -0
  340. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wg2_v7owd9tzcaninc36.json +21 -0
  341. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_6kijc7nd.json +187 -0
  342. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_B0eP8qYAdpUo4yR9.json +53 -0
  343. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_IAYz2WK1th0cMLmL.json +93 -0
  344. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_aqoouq7x.json +100 -0
  345. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_ccpwojhalfxryigz.json +121 -0
  346. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_cpmgn2cf.json +85 -0
  347. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_fi6dne5tu4t1nm6j.json +186 -0
  348. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_gc1bxoq2hafxpa35.json +110 -0
  349. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_gogb05wrtredz3bs.json +195 -0
  350. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_t94pit6zjbask9qo.json +168 -0
  351. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_tfbhw0mg.json +109 -0
  352. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wk_y5obtqhuztqsf2mj.json +74 -0
  353. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wkcz_gc4b1mdw7kebtuyz.json +227 -0
  354. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wkf_9xfjixap.json +85 -0
  355. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wkf_p3dbf6qs.json +85 -0
  356. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wnykq_kzwdw5bpxlbs9h9g.json +40 -0
  357. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wnykq_npbbca46yiug8ysk.json +21 -0
  358. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wnykq_om518smspsaltzdi.json +21 -0
  359. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wnykq_rqhxdyusjrwxyff6.json +21 -0
  360. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wnykq_x0lyfgjuguuh1vof.json +22 -0
  361. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_g2y6z3p3ja2qhyav.json +155 -0
  362. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_iq4ygaai.json +45 -0
  363. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_iv7hudlj.json +168 -0
  364. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_krlcihrpzpc8olw9.json +66 -0
  365. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_lf36y5nwb8jkxwgg.json +66 -0
  366. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_qrztc3ev.json +210 -0
  367. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_s5l7qidyapl1rbrs.json +59 -0
  368. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_vlzqwckk.json +348 -0
  369. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_vtA4pDd6PLUZzXgZ.json +56 -0
  370. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_xflodz7oja0pndk3.json +428 -0
  371. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_xpxdr5q6vc8aztq0.json +59 -0
  372. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_xr3htd96.json +56 -0
  373. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdcg_yqiqbaldtr0i7mru.json +259 -0
  374. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wsdykq_ay30hrndaogxclh0.json +22 -0
  375. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wxkg_ja5osu5g.json +64 -0
  376. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wxkg_l8yaz4um5b3pwyvf.json +50 -0
  377. tuya2ildevice-0.1.0/tests/golden/core_fixtures/wxnbq_5l1ht8jygsyr1wn1.json +21 -0
  378. tuya2ildevice-0.1.0/tests/golden/core_fixtures/xdd_shx9mmadyyeaq88t.json +139 -0
  379. tuya2ildevice-0.1.0/tests/golden/core_fixtures/xfj_pjabraecffsfrmxz.json +75 -0
  380. tuya2ildevice-0.1.0/tests/golden/core_fixtures/xktyd_3djw12ln4xtvv8eq.json +175 -0
  381. tuya2ildevice-0.1.0/tests/golden/core_fixtures/xnyjcn_pb0tc75khaik8qbg.json +794 -0
  382. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ydkt_jevroj5aguwdbs2e.json +21 -0
  383. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ygsb_l6ax0u6jwbz82atk.json +63 -0
  384. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ykq_bngwdjsr.json +70 -0
  385. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ywbj_arywmw6h6vesoz5t.json +37 -0
  386. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ywbj_cjlutkuuvxnie17o.json +37 -0
  387. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ywbj_gf9dejhmzffgdyfj.json +63 -0
  388. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ywbj_kscbebaf3s1eogvt.json +51 -0
  389. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ywbj_rccxox8p.json +68 -0
  390. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ywcgq_h8lvyoahr6s6aybf.json +146 -0
  391. tuya2ildevice-0.1.0/tests/golden/core_fixtures/ywcgq_wtzwyhkev3b4ubns.json +139 -0
  392. tuya2ildevice-0.1.0/tests/golden/core_fixtures/zjq_nkkl7uzv.json +21 -0
  393. tuya2ildevice-0.1.0/tests/golden/core_fixtures/zndb_4ggkyflayu1h1ho9.json +227 -0
  394. tuya2ildevice-0.1.0/tests/golden/core_fixtures/zndb_gqmmtjclqb7reg5p.json +22 -0
  395. tuya2ildevice-0.1.0/tests/golden/core_fixtures/zndb_iow5ux77dxy3yrpj.json +129 -0
  396. tuya2ildevice-0.1.0/tests/golden/core_fixtures/zndb_uqzhc4bx5zqwpg2m.json +74 -0
  397. tuya2ildevice-0.1.0/tests/golden/core_fixtures/zndb_v5jlnn5hwyffkhp3.json +77 -0
  398. tuya2ildevice-0.1.0/tests/golden/core_fixtures/zndb_z95s7p3z54xbsjnl.json +136 -0
  399. tuya2ildevice-0.1.0/tests/golden/core_fixtures/zndb_ze8faryrxr0glqnn.json +77 -0
  400. tuya2ildevice-0.1.0/tests/golden/core_fixtures/znjdq_au6dqazvkxqnpaak.json +269 -0
  401. tuya2ildevice-0.1.0/tests/golden/core_fixtures/znnbq_0kllybtbzftaee7y.json +70 -0
  402. tuya2ildevice-0.1.0/tests/golden/core_fixtures/znnbq_6b3pbbuqbfabhfiq.json +56 -0
  403. tuya2ildevice-0.1.0/tests/golden/core_fixtures/znrb_8ln34bg8u4y6rdda.json +419 -0
  404. tuya2ildevice-0.1.0/tests/golden/core_fixtures/znrb_db81ge24jctwx8lo.json +172 -0
  405. tuya2ildevice-0.1.0/tests/golden/core_fixtures/znrb_gpzittzfnzhduquz.json +265 -0
  406. tuya2ildevice-0.1.0/tests/golden/core_fixtures/zwjcy_gvygg3m8.json +77 -0
  407. tuya2ildevice-0.1.0/tests/golden/core_fixtures/zwjcy_myd45weu.json +77 -0
  408. tuya2ildevice-0.1.0/tests/golden/fixtures.py +18 -0
  409. tuya2ildevice-0.1.0/tests/golden/golden.json +32909 -0
  410. tuya2ildevice-0.1.0/tests/golden/quirk_golden.json +960 -0
  411. tuya2ildevice-0.1.0/tests/golden/quirk_synthetic_golden.json +1132 -0
  412. tuya2ildevice-0.1.0/tests/helpers.py +33 -0
  413. tuya2ildevice-0.1.0/tests/test_adapter.py +88 -0
  414. tuya2ildevice-0.1.0/tests/test_delta.py +25 -0
  415. tuya2ildevice-0.1.0/tests/test_driver.py +312 -0
  416. tuya2ildevice-0.1.0/tests/test_golden.py +178 -0
  417. tuya2ildevice-0.1.0/tests/test_host.py +216 -0
  418. tuya2ildevice-0.1.0/tests/test_mqtt.py +139 -0
  419. tuya2ildevice-0.1.0/tests/test_platforms.py +30 -0
  420. tuya2ildevice-0.1.0/tests/test_quirks.py +87 -0
  421. tuya2ildevice-0.1.0/tests/test_vectors.py +74 -0
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .pytest_cache/
4
+ dist/
5
+ *.egg-info/
6
+ .venv/
7
+ venv/
8
+ .coverage
9
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 3735943886
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.5
2
+ Name: tuya2ildevice
3
+ Version: 0.1.0
4
+ Summary: Sans-IO converter: Tuya (rustuya / rustuya-bridge) device + DPS packets <-> ildevice descriptor, values and commands
5
+ Project-URL: Repository, https://github.com/3735943886/tuya2ildevice
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Topic :: Home Automation
10
+ Requires-Python: >=3.10
11
+ Provides-Extra: host
12
+ Requires-Dist: paho-mqtt>=2.0; extra == 'host'
13
+ Provides-Extra: test
14
+ Requires-Dist: jsonschema; extra == 'test'
15
+ Requires-Dist: paho-mqtt>=2.0; extra == 'test'
16
+ Requires-Dist: pytest; extra == 'test'
17
+ Requires-Dist: pytest-asyncio; extra == 'test'
18
+ Description-Content-Type: text/markdown
19
+
20
+ # tuya2ildevice
21
+
22
+ The one place that interprets Tuya. Sans-IO Python: takes a Tuya device as [rustuya](https://github.com/3735943886/rustuya) /
23
+ [rustuya-bridge](https://github.com/3735943886/rustuya-bridge) know it and produces an
24
+ [ildevice](https://github.com/3735943886/ildevice): descriptor, live values and events from dps packets, and dps for
25
+ ildevice commands. It opens no sockets and reads no clock. Other projects
26
+ ([rustuya-homeassistant](https://github.com/3735943886/rustuya-homeassistant), ildevice hosts,
27
+ [rustuya-manager](https://github.com/3735943886/rustuya-manager)) import this instead of carrying their own Tuya knowledge.
28
+
29
+ ```
30
+ pip install tuya2ildevice # no dependencies; tuya2ildevice[host] adds paho-mqtt for `tuya2ildevice.host`, [test] for the tests
31
+ ```
32
+
33
+ ```python
34
+ from tuya2ildevice import TuyaDriver, Connected, Message, Command, descriptor_of
35
+
36
+ descriptor_of(device) # just the ildevice descriptor of a tuyadevices.json entry
37
+ d = TuyaDriver(device) # the state machine (il.md section 8)
38
+ d.handle(now, Connected()) # -> [Descriptor]
39
+ d.handle(now, Message("active", {"data": {"dps": {"1": True}}})) # -> [Value(...), Event(...)]
40
+ d.handle(now, Command("switch_1", "off")) # -> [SendMessage("set", {"dps": {"1": False}})] or [Reject(...)]
41
+ ```
42
+
43
+ ## Packets and commands
44
+
45
+ - `Message(channel, json)`: `active` (device push: fires events, accumulates `add_ele`-style deltas) or `passive` /
46
+ `state` (readback, snapshot: values only). Payload: `{"dps":{}}`, `{"data":{"dps":{}}}` or bare `{"1":true}`.
47
+ - `Command(prop, value)` is checked as il.md section 5 says before anything is sent; failures come back as `Reject`.
48
+ Values convert as in Home Assistant core (brightness goes through 0..255; cover position is reversed unless
49
+ `control_back_mode` is `back`), so a written value can differ slightly from what is read back.
50
+ - Covers of class garage/gate are read only unless `TuyaDriver(..., allow_hazardous=True)` (il.md S-1).
51
+ - A dp no platform table claims gets no property, as in Home Assistant core; `TuyaDriver(..., expose_unused=True)` gives
52
+ each one a property chosen by its Tuya type (rustuya-homeassistant v1 did that). Integer, Enum and Boolean are writable only if the dp is
53
+ in `function`; String, Raw, Json and Bitmap are read-only. `config` if writable, else `diagnostic`.
54
+ - Assembled: switch, button, select, number, sensor, binary_sensor, event, light, cover, fan, siren, valve,
55
+ humidifier, climate, alarm (kind `alarm`), vacuum. Not assembled: camera (a stream is outside the IL; `driver.unsupported` lists it).
56
+ A doorbell `alarm_message` event loses its message text (an ildevice event has only a kind).
57
+
58
+ ## User overrides
59
+
60
+ `TuyaDriver(device, overrides=mapping)` / `Hub(devices, overrides=mapping)`; `mapping` is `{product_id or device id: block}`,
61
+ already loaded (the host reads files; `merge_all([...])` merges several, later wins). Details and the block format are in
62
+ [overrides.py](src/tuya2ildevice/overrides.py):
63
+
64
+ ```json
65
+ { "5rta89nj": {
66
+ "dp": {"104": {"code": "percent_control", "type": "Integer", "values": {"min": 0, "max": 100, "scale": 0, "step": 1}}},
67
+ "remove": ["cycle_time"],
68
+ "props": {"countdown_1": {"label": "Timer", "category": "config", "rw": false}},
69
+ "device": {"model": "Sliding Window Opener"} } }
70
+ ```
71
+
72
+ `dp`, `remove`, `category` patch the schema before classification (a defined dp is classified like any other);
73
+ `props` (by property name) and `device` patch the descriptor. Unknown keys raise `OverrideError`.
74
+ `Hub.reload(mapping)` applies new overrides live: republishes changed descriptors and clears removed properties.
75
+ `from_v1(custom_converters)` converts rustuya-homeassistant `dp_meta`; `discovery_overrides` (HA payload fields) are
76
+ dropped with a warning.
77
+
78
+ ## Code converters
79
+
80
+ The equivalent of v1's `custom_converters/*.py`: a per-device `Converter` object sees the driver's dp state on every
81
+ packet and returns derived property values (and timer requests, since it cannot read a clock). See
82
+ [converters.py](src/tuya2ildevice/converters.py).
83
+
84
+ ```python
85
+ class MyConverter(Converter):
86
+ def props(self): return {"motion": {"type": "select", "role": "motion", "options": ["opening", "closing", "stopped"]}}
87
+ def update(self, now, codes, changed, active): return {"motion": "stopped"} # or Result(values=..., timers=...)
88
+
89
+ TuyaDriver(device, converters={"<product_id or device id>": [lambda device: MyConverter()]})
90
+ ```
91
+
92
+ Built-in ones are named in an override block: `{"<product_id>": {"converters": {"cover_motion": {"settle": 5}}}}`.
93
+ `cover_motion` (ported from v1's `00_curtain.py`) derives the cover's `motion` role (opening / closing / stopped) from the
94
+ control, set-position and position dps; a snapshot never starts motion. Timers come out as `SetTimer` (driver) or
95
+ `Schedule` (`Hub`); the host calls back with `Timer` / `hub.on_timer(now, id, name)`. Loading a user's `.py` file is the
96
+ host's job; the code runs in-process.
97
+
98
+ ## rustuya-bridge <-> tuya2ildevice <-> an IL host over MQTT
99
+
100
+ `Hub` ([mqtt.py](src/tuya2ildevice/mqtt.py)) owns one driver per device and maps both sides. Its methods take what was
101
+ received and return `Publish(side, topic, payload, retain, qos)`; the host only executes them.
102
+ `tuya2ildevice.host` is the host: `Runner` drives a `Hub` on two transports (`MqttTransport` over paho, or the in-process
103
+ `InProcessTransport`), keeps the Last Will presence (M-12), reconnects, adds/removes devices while running
104
+ (`set_device`, `remove_device`, `sync_devices`) and follows rustuya-manager's `tuyadevices.json` (`DeviceWatcher`).
105
+ `read_bridge_config` + `BridgeTopics.from_config` take the topic layout the bridge announces on `{root}/bridge/config`.
106
+
107
+ | direction | topic |
108
+ |---|---|
109
+ | bridge -> hub | `rustuya/event/{active,passive,state}/<id>` (dps JSON, or single-DP), `rustuya/error/<id>` (`errorCode` 0 = connected) |
110
+ | hub -> bridge | `rustuya/command` `{"action":"set"/"get",...}` (a `get` after each connect) |
111
+ | hub -> IL host | il-mqtt.md: retained `il/<id>` and `il/<id>/<prop>`; events and `il/<id>/reject` not retained; `il/_producer/tuya` presence |
112
+ | IL host -> hub | `il/<id>/<prop>/set` (retained writes ignored) |
113
+
114
+ Run the bridge with `mqtt_retain: true` and register the devices in it yourself (`add`); the hub never touches keys.
115
+
116
+ ## Layout
117
+
118
+ ```
119
+ src/tuya2ildevice/
120
+ driver.py TuyaDriver: packets/commands <-> outputs io.py inputs and outputs as data
121
+ assemble.py engine entity plans -> ildevice props/roles checks.py il.md section 5 command checks
122
+ mqtt.py Hub, BridgeTopics, IlTopics tuya/ the DP engine (see below)
123
+ tuya/ classify + platforms, adapter (raw dps <-> values), quirks, ops, codecs, units
124
+ tuya/tables/ per-platform description tables, generated from HA core tuya/quirks/ from tuya-device-handlers
125
+ tuya/data/ HA's allowed units per device class
126
+ scripts/ generators for those data files, and golden/ (builds the golden data; needs HA core + oracle venvs)
127
+ docs/ engine-spec.md (the engine's behaviour), analysis/ (how it was derived from HA core)
128
+ tests/ golden/ = 324 HA core fixtures + core's own snapshots; chain/ = the same through an IL host's planner
129
+ ```
130
+
131
+ The engine reproduces Home Assistant core's `tuya` integration exactly, including its quirks, and the golden tests
132
+ pin it: `tests/golden/golden.json` is core's own entity snapshots for every fixture. To follow a new HA core /
133
+ tuya-device-handlers release, run the generators in `scripts/` against it, then the tests; a difference is either
134
+ a real change to adopt or a regression.
135
+
136
+ ## Tests
137
+
138
+ ```
139
+ pip install -e .[test] && python -m pytest
140
+ ```
141
+
142
+ `tests/test_adapter.py` compares the raw-dps adapter with the Tuya SDK and is skipped unless `tuya-device-sharing-sdk==0.2.15`
143
+ is installed. The spec repository (`../ildevice`, or `$ILDEVICE`) supplies the schema and the language-neutral vectors
144
+ (commands, wire values, topics) read directly from its checkout; those tests are skipped if it is not there. `tests/chain/`
145
+ compares every Home Assistant core tuya fixture with core's entity snapshots through an IL host's HA-free planner
146
+ (needs that host's `ildevice.core` on `sys.path`; not collected without it).
@@ -0,0 +1,127 @@
1
+ # tuya2ildevice
2
+
3
+ The one place that interprets Tuya. Sans-IO Python: takes a Tuya device as [rustuya](https://github.com/3735943886/rustuya) /
4
+ [rustuya-bridge](https://github.com/3735943886/rustuya-bridge) know it and produces an
5
+ [ildevice](https://github.com/3735943886/ildevice): descriptor, live values and events from dps packets, and dps for
6
+ ildevice commands. It opens no sockets and reads no clock. Other projects
7
+ ([rustuya-homeassistant](https://github.com/3735943886/rustuya-homeassistant), ildevice hosts,
8
+ [rustuya-manager](https://github.com/3735943886/rustuya-manager)) import this instead of carrying their own Tuya knowledge.
9
+
10
+ ```
11
+ pip install tuya2ildevice # no dependencies; tuya2ildevice[host] adds paho-mqtt for `tuya2ildevice.host`, [test] for the tests
12
+ ```
13
+
14
+ ```python
15
+ from tuya2ildevice import TuyaDriver, Connected, Message, Command, descriptor_of
16
+
17
+ descriptor_of(device) # just the ildevice descriptor of a tuyadevices.json entry
18
+ d = TuyaDriver(device) # the state machine (il.md section 8)
19
+ d.handle(now, Connected()) # -> [Descriptor]
20
+ d.handle(now, Message("active", {"data": {"dps": {"1": True}}})) # -> [Value(...), Event(...)]
21
+ d.handle(now, Command("switch_1", "off")) # -> [SendMessage("set", {"dps": {"1": False}})] or [Reject(...)]
22
+ ```
23
+
24
+ ## Packets and commands
25
+
26
+ - `Message(channel, json)`: `active` (device push: fires events, accumulates `add_ele`-style deltas) or `passive` /
27
+ `state` (readback, snapshot: values only). Payload: `{"dps":{}}`, `{"data":{"dps":{}}}` or bare `{"1":true}`.
28
+ - `Command(prop, value)` is checked as il.md section 5 says before anything is sent; failures come back as `Reject`.
29
+ Values convert as in Home Assistant core (brightness goes through 0..255; cover position is reversed unless
30
+ `control_back_mode` is `back`), so a written value can differ slightly from what is read back.
31
+ - Covers of class garage/gate are read only unless `TuyaDriver(..., allow_hazardous=True)` (il.md S-1).
32
+ - A dp no platform table claims gets no property, as in Home Assistant core; `TuyaDriver(..., expose_unused=True)` gives
33
+ each one a property chosen by its Tuya type (rustuya-homeassistant v1 did that). Integer, Enum and Boolean are writable only if the dp is
34
+ in `function`; String, Raw, Json and Bitmap are read-only. `config` if writable, else `diagnostic`.
35
+ - Assembled: switch, button, select, number, sensor, binary_sensor, event, light, cover, fan, siren, valve,
36
+ humidifier, climate, alarm (kind `alarm`), vacuum. Not assembled: camera (a stream is outside the IL; `driver.unsupported` lists it).
37
+ A doorbell `alarm_message` event loses its message text (an ildevice event has only a kind).
38
+
39
+ ## User overrides
40
+
41
+ `TuyaDriver(device, overrides=mapping)` / `Hub(devices, overrides=mapping)`; `mapping` is `{product_id or device id: block}`,
42
+ already loaded (the host reads files; `merge_all([...])` merges several, later wins). Details and the block format are in
43
+ [overrides.py](src/tuya2ildevice/overrides.py):
44
+
45
+ ```json
46
+ { "5rta89nj": {
47
+ "dp": {"104": {"code": "percent_control", "type": "Integer", "values": {"min": 0, "max": 100, "scale": 0, "step": 1}}},
48
+ "remove": ["cycle_time"],
49
+ "props": {"countdown_1": {"label": "Timer", "category": "config", "rw": false}},
50
+ "device": {"model": "Sliding Window Opener"} } }
51
+ ```
52
+
53
+ `dp`, `remove`, `category` patch the schema before classification (a defined dp is classified like any other);
54
+ `props` (by property name) and `device` patch the descriptor. Unknown keys raise `OverrideError`.
55
+ `Hub.reload(mapping)` applies new overrides live: republishes changed descriptors and clears removed properties.
56
+ `from_v1(custom_converters)` converts rustuya-homeassistant `dp_meta`; `discovery_overrides` (HA payload fields) are
57
+ dropped with a warning.
58
+
59
+ ## Code converters
60
+
61
+ The equivalent of v1's `custom_converters/*.py`: a per-device `Converter` object sees the driver's dp state on every
62
+ packet and returns derived property values (and timer requests, since it cannot read a clock). See
63
+ [converters.py](src/tuya2ildevice/converters.py).
64
+
65
+ ```python
66
+ class MyConverter(Converter):
67
+ def props(self): return {"motion": {"type": "select", "role": "motion", "options": ["opening", "closing", "stopped"]}}
68
+ def update(self, now, codes, changed, active): return {"motion": "stopped"} # or Result(values=..., timers=...)
69
+
70
+ TuyaDriver(device, converters={"<product_id or device id>": [lambda device: MyConverter()]})
71
+ ```
72
+
73
+ Built-in ones are named in an override block: `{"<product_id>": {"converters": {"cover_motion": {"settle": 5}}}}`.
74
+ `cover_motion` (ported from v1's `00_curtain.py`) derives the cover's `motion` role (opening / closing / stopped) from the
75
+ control, set-position and position dps; a snapshot never starts motion. Timers come out as `SetTimer` (driver) or
76
+ `Schedule` (`Hub`); the host calls back with `Timer` / `hub.on_timer(now, id, name)`. Loading a user's `.py` file is the
77
+ host's job; the code runs in-process.
78
+
79
+ ## rustuya-bridge <-> tuya2ildevice <-> an IL host over MQTT
80
+
81
+ `Hub` ([mqtt.py](src/tuya2ildevice/mqtt.py)) owns one driver per device and maps both sides. Its methods take what was
82
+ received and return `Publish(side, topic, payload, retain, qos)`; the host only executes them.
83
+ `tuya2ildevice.host` is the host: `Runner` drives a `Hub` on two transports (`MqttTransport` over paho, or the in-process
84
+ `InProcessTransport`), keeps the Last Will presence (M-12), reconnects, adds/removes devices while running
85
+ (`set_device`, `remove_device`, `sync_devices`) and follows rustuya-manager's `tuyadevices.json` (`DeviceWatcher`).
86
+ `read_bridge_config` + `BridgeTopics.from_config` take the topic layout the bridge announces on `{root}/bridge/config`.
87
+
88
+ | direction | topic |
89
+ |---|---|
90
+ | bridge -> hub | `rustuya/event/{active,passive,state}/<id>` (dps JSON, or single-DP), `rustuya/error/<id>` (`errorCode` 0 = connected) |
91
+ | hub -> bridge | `rustuya/command` `{"action":"set"/"get",...}` (a `get` after each connect) |
92
+ | hub -> IL host | il-mqtt.md: retained `il/<id>` and `il/<id>/<prop>`; events and `il/<id>/reject` not retained; `il/_producer/tuya` presence |
93
+ | IL host -> hub | `il/<id>/<prop>/set` (retained writes ignored) |
94
+
95
+ Run the bridge with `mqtt_retain: true` and register the devices in it yourself (`add`); the hub never touches keys.
96
+
97
+ ## Layout
98
+
99
+ ```
100
+ src/tuya2ildevice/
101
+ driver.py TuyaDriver: packets/commands <-> outputs io.py inputs and outputs as data
102
+ assemble.py engine entity plans -> ildevice props/roles checks.py il.md section 5 command checks
103
+ mqtt.py Hub, BridgeTopics, IlTopics tuya/ the DP engine (see below)
104
+ tuya/ classify + platforms, adapter (raw dps <-> values), quirks, ops, codecs, units
105
+ tuya/tables/ per-platform description tables, generated from HA core tuya/quirks/ from tuya-device-handlers
106
+ tuya/data/ HA's allowed units per device class
107
+ scripts/ generators for those data files, and golden/ (builds the golden data; needs HA core + oracle venvs)
108
+ docs/ engine-spec.md (the engine's behaviour), analysis/ (how it was derived from HA core)
109
+ tests/ golden/ = 324 HA core fixtures + core's own snapshots; chain/ = the same through an IL host's planner
110
+ ```
111
+
112
+ The engine reproduces Home Assistant core's `tuya` integration exactly, including its quirks, and the golden tests
113
+ pin it: `tests/golden/golden.json` is core's own entity snapshots for every fixture. To follow a new HA core /
114
+ tuya-device-handlers release, run the generators in `scripts/` against it, then the tests; a difference is either
115
+ a real change to adopt or a regression.
116
+
117
+ ## Tests
118
+
119
+ ```
120
+ pip install -e .[test] && python -m pytest
121
+ ```
122
+
123
+ `tests/test_adapter.py` compares the raw-dps adapter with the Tuya SDK and is skipped unless `tuya-device-sharing-sdk==0.2.15`
124
+ is installed. The spec repository (`../ildevice`, or `$ILDEVICE`) supplies the schema and the language-neutral vectors
125
+ (commands, wire values, topics) read directly from its checkout; those tests are skipped if it is not there. `tests/chain/`
126
+ compares every Home Assistant core tuya fixture with core's entity snapshots through an IL host's HA-free planner
127
+ (needs that host's `ildevice.core` on `sys.path`; not collected without it).
@@ -0,0 +1,85 @@
1
+ # Phase 1 synthesis: what HA core's tuya integration actually does
2
+
3
+ Sources: HA core dev @ 949a484 (2026-09-19), tuya-device-handlers 0.0.29,
4
+ tuya-device-sharing-sdk 0.2.15. Per-area catalogs (with file:line evidence) are
5
+ catalog/A..F. Headline claims were spot-checked against source by the
6
+ coordinator (PLATFORMS list, siren features, local_strategy usage, quirk count).
7
+
8
+ ## 1. Shape of the system
9
+
10
+ CustomerDevice (cloud schema: function / status_range / status)
11
+ -> quirk stage (by product_id; mutates schema/status/category) [handlers]
12
+ -> category -> per-platform description tables [core]
13
+ -> definition (resolves dp codes + types into wrappers) [handlers]
14
+ -> wrapper: read(status)->value ; write(value)->[{code,value}] [handlers]
15
+ -> HA entity (thin) [core]
16
+
17
+ Handlers (7.1k lines) has NO homeassistant imports. Core (9.7k lines) holds the
18
+ tables + thin entities. 18 platforms; lock / media_player / water_heater are NOT
19
+ among them (lock-category devices register but create zero entities).
20
+
21
+ ## 2. Numbers
22
+
23
+ - DeviceCategory 139 members (98 referenced; categories are open strings in fixtures)
24
+ - DPCode 415 members
25
+ - 617 literal entity descriptions (834 expanded); sensor alone 250/450
26
+ - 32 quirk files (14 override kinds; 30 pure data, 3 code hooks)
27
+ - 324 test fixtures, 285 produce entities (1205 total, quirks disabled), 39 produce none
28
+ - only 16/324 fixtures carry local_strategy (numeric dp ids)
29
+
30
+ ## 3. Facts that constrain the IL
31
+
32
+ 1. Everything is keyed by dp CODE, never dp id. Schema = function + status_range
33
+ (type, range, scale, step, enum values). local_strategy is touched only by quirks.
34
+ 2. Entity existence = category table AND required dp codes present with required
35
+ type (tuple-of-candidates fallback, prefer_function toggle). No product_id
36
+ selection outside quirks. Some platforms have degenerate rules (climate: every
37
+ dbl/kt/qn/rs/wk/wkf device gets one even with no dps; vacuum: always for `sd`).
38
+ 3. Reads are pure; invalid raw values become None (unknown), not errors. One
39
+ stateful reader (delta accumulator, needs dp_timestamps).
40
+ 4. Writes are pure: value -> list of {code,value}; validated against schema.
41
+ Multi-dp writes exist only in light (ordered color+mode) and a few climate paths.
42
+ 5. Cross-dp rules exist: cover inversion depends on control_back_mode; alarm
43
+ TRIGGERED depends on master_state + decoded alarm_msg; light color mode depends
44
+ on work_mode; climate hvac_mode from switch+mode. Some read dps NOT in schema.
45
+ 6. Named fixed transforms needed: linear remap (with inversion), mired/Kelvin,
46
+ HSV json/hex codecs, unit conversion, electricity raw/json parsers, wind lookup,
47
+ bitmap bit/in-set, base64 utf8/raw, enum<->HA maps, many-to-one status maps.
48
+ 7. No optimistic state, no debounce; dp_timestamps only for the delta accumulator.
49
+ Availability = device online flag only.
50
+ 8. Quirks: keyed product_id; run before classification; add/replace/remove dp,
51
+ retype/rescale, category override, initial status map, TypeInformation class swap
52
+ per dpcode, apply_when predicate (code), feeder wrapper (code). Custom user
53
+ quirks are arbitrary Python files (out of scope for a data IL).
54
+ 9. Hard-coded literals live in code ("Sensor Low Battery", FZ/ZZ/STOP, chargego,
55
+ back) -- IL must carry them as data.
56
+ 10. Documented quirks of core itself: climate hvac_mode reads an unfiltered map (can
57
+ report a mode not in hvac_modes); cover open/close with a position dp sends only
58
+ position; unverified paths: cover tilt, mach_operate (no fixtures).
59
+
60
+ ## 4. Fit with our situation
61
+
62
+ - Our registration cache already stores local_strategy + function + status_range
63
+ (const.py CONF_LOCAL_STRATEGY/FUNCTION/STATUS_RANGE), so core's actual required
64
+ input (function/status_range) IS available to us; tuya2ha today classifies from
65
+ local_strategy alone and ignores function/status_range types.
66
+ - We need dp code <-> dp id translation on top (bridge speaks numeric dp ids);
67
+ the SDK also has 24 value-convert strategies (local raw -> cloud value) that
68
+ core assumes already applied. Whether the bridge's values need those is UNKNOWN
69
+ (SDK strategy implementations were not read).
70
+ - Lock is outside "reuse of core knowledge": core has none. Needs another source.
71
+ - Removable from IL scope: cloud auth/MQ, scenes, camera streaming, feeder
72
+ services, user-quirk plugins, optimistic state, debounce.
73
+
74
+ ## 5. Decisions the IL design needs from the user
75
+
76
+ D1. Fidelity target: reproduce core exactly (including its quirks like the climate
77
+ unfiltered map) vs. reproduce intended behavior.
78
+ D2. Schema source contract: require function/status_range (like core) with
79
+ local_strategy for dp-id mapping, vs. keep tuya2ha's local_strategy-only mode too.
80
+ D3. Do SDK value-convert strategies need porting (blocked on live verification).
81
+ D4. Quirk scope: data-only quirks in IL (30/32) + small declarative predicate
82
+ language, or also code hooks.
83
+ D5. Lock/media_player/etc: out of scope, or source knowledge elsewhere (tuya-local
84
+ yaml corpus / own design).
85
+ D6. Golden tests: use core's snapshots as-is (quirks off) and add quirk-on cases.