rustuya-local 0.1.0.dev5__tar.gz → 0.1.0.dev6__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 (102) hide show
  1. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/.github/workflows/_test.yml +6 -6
  2. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/.github/workflows/release.yml +1 -1
  3. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/CHANGELOG.md +6 -0
  4. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/PKG-INFO +13 -13
  5. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/README.md +10 -10
  6. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/bridge_supervisor.py +1 -1
  7. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/const.py +1 -1
  8. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/manifest.json +3 -3
  9. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/www/rustuya-panel.js +4 -4
  10. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/docs/MIGRATING.md +4 -4
  11. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/docs/ROADMAP.md +2 -2
  12. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/pyproject.toml +3 -3
  13. rustuya_local-0.1.0.dev6/release-notes.md +3 -0
  14. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/scripts/build_dropin.py +5 -5
  15. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/__init__.py +2 -2
  16. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/bridge_client.py +1 -1
  17. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/config.py +1 -1
  18. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/host/__init__.py +1 -1
  19. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/host/devices.py +1 -1
  20. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/host/hub.py +9 -2
  21. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/host/il.py +2 -2
  22. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/host/overrides.py +2 -2
  23. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/host/pack.py +4 -4
  24. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/host/rules.py +3 -3
  25. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/host/runner.py +2 -2
  26. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/manager_plugin/__init__.py +1 -1
  27. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/manager_plugin/static/index.js +1 -1
  28. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/service.py +4 -4
  29. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/devices.py +1 -1
  30. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/test_full_stack_devices.py +3 -3
  31. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/test_manager_plugin.py +6 -6
  32. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/ha/test_init.py +2 -2
  33. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_cover_settings.py +1 -1
  34. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_dropin.py +9 -9
  35. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_host.py +2 -2
  36. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_hub.py +2 -2
  37. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_il_vectors.py +2 -2
  38. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_pack.py +4 -4
  39. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_rule_files.py +7 -7
  40. rustuya_local-0.1.0.dev5/release-notes.md +0 -8
  41. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/.github/dependabot.yml +0 -0
  42. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/.github/workflows/ci.yml +0 -0
  43. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/.github/workflows/hacs.yml +0 -0
  44. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/.github/workflows/hassfest.yml +0 -0
  45. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/.gitignore +0 -0
  46. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/LICENSE +0 -0
  47. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/__init__.py +0 -0
  48. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/brand/icon.png +0 -0
  49. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/brand/icon.svg +0 -0
  50. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/brand/icon@2x.png +0 -0
  51. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/brand/logo.png +0 -0
  52. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/brand/logo.svg +0 -0
  53. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/brand/logo@2x.png +0 -0
  54. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/bridge_sync.py +0 -0
  55. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/broker.py +0 -0
  56. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/config_flow.py +0 -0
  57. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/manager_registry.py +0 -0
  58. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/manager_session.py +0 -0
  59. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/panel.py +0 -0
  60. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/panel_bridge.py +0 -0
  61. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/services.yaml +0 -0
  62. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/strings.json +0 -0
  63. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/translations/en.json +0 -0
  64. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/custom_components/rustuya/translations/ko.json +0 -0
  65. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/docs/REDESIGN.md +0 -0
  66. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/docs/STATUS.md +0 -0
  67. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/hacs.json +0 -0
  68. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/scripts/release_notes.py +0 -0
  69. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/__main__.py +0 -0
  70. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/async_tools.py +0 -0
  71. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/cli.py +0 -0
  72. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/files.py +0 -0
  73. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/host/memory.py +0 -0
  74. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/host/mqtt.py +0 -0
  75. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/host/transport.py +0 -0
  76. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/manager_plugin/api.py +0 -0
  77. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/src/rustuya_local/validation.py +0 -0
  78. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/conftest.py +0 -0
  79. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/test_bridge_registration.py +0 -0
  80. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/test_chain_in_process.py +0 -0
  81. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/test_chain_mqtt.py +0 -0
  82. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/test_daemon.py +0 -0
  83. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/test_full_stack.py +0 -0
  84. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/test_full_stack_custom_templates.py +0 -0
  85. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/test_purge.py +0 -0
  86. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/e2e/test_service.py +0 -0
  87. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/ha/conftest.py +0 -0
  88. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/ha/fake_manager.py +0 -0
  89. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/ha/test_bridge_probe.py +0 -0
  90. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/ha/test_config_flow.py +0 -0
  91. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/ha/test_manager_registry.py +0 -0
  92. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/ha/test_manager_session.py +0 -0
  93. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/ha/test_migrate.py +0 -0
  94. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/ha/test_panel.py +0 -0
  95. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_config.py +0 -0
  96. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_files.py +0 -0
  97. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_hazardous.py +0 -0
  98. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_link_watcher.py +0 -0
  99. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_panel_js.py +0 -0
  100. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_plugin_api.py +0 -0
  101. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/test_release_notes.py +0 -0
  102. {rustuya_local-0.1.0.dev5 → rustuya_local-0.1.0.dev6}/tests/unit/tuya_samples.py +0 -0
@@ -38,14 +38,14 @@ jobs:
38
38
  repository: 3735943886/ildevice-homeassistant
39
39
  path: ildevice-homeassistant
40
40
 
41
- # tuya2ildevice is on PyPI (installed below via uv), so this isn't for dependency
41
+ # tuya-interpreter is on PyPI (installed below via uv), so this isn't for dependency
42
42
  # resolution -- it's so tests/e2e/test_full_stack_devices.py can reach its sibling
43
43
  # checkout's tests/golden fixture data, which isn't shipped in the published package.
44
- - name: Check out tuya2ildevice
44
+ - name: Check out tuya-interpreter
45
45
  uses: actions/checkout@v7
46
46
  with:
47
- repository: 3735943886/tuya2ildevice
48
- path: tuya2ildevice
47
+ repository: 3735943886/tuya-interpreter
48
+ path: tuya-interpreter
49
49
 
50
50
  - name: Set up Python ${{ matrix.python-version }}
51
51
  uses: actions/setup-python@v7
@@ -114,7 +114,7 @@ jobs:
114
114
  "$RUNNER_TEMP/smoke/bin/python" -c "
115
115
  import rustuya_local.cli, rustuya_local.manager_plugin, rustuya_local.service
116
116
  from rustuya_local import register
117
- import tuya2ildevice
118
- tuya2ildevice.preload()
117
+ import tuya_interpreter
118
+ tuya_interpreter.preload()
119
119
  print('ok')"
120
120
  "$RUNNER_TEMP/smoke/bin/rustuya-local" --help
@@ -96,7 +96,7 @@ jobs:
96
96
  run: twine check --strict dist/* # --strict: a missing README (long description) fails the release
97
97
 
98
98
  - name: Build the rustuya-manager drop-in zip
99
- # The manager's plugin catalog installs this asset (it cannot pip-install): rustuya_local with the tuya2ildevice
99
+ # The manager's plugin catalog installs this asset (it cannot pip-install): rustuya_local with the tuya-interpreter
100
100
  # the wheel resolves to vendored inside. Kept out of dist/ so it is not uploaded to PyPI.
101
101
  run: |
102
102
  python -m pip install dist/*.whl
@@ -8,6 +8,12 @@ stable release.
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.1.0.dev6] — 2026-10-12
12
+
13
+ ### Changed
14
+ - Require tuya-interpreter 0.1.0a1 (tuya2ildevice renamed) in place of tuya2ildevice, in the package, the Home Assistant integration and the manager drop-in archive.
15
+ - Fetch builtin rule updates from tuya-interpreter's `master` branch.
16
+
11
17
  ## [0.1.0.dev5] — 2026-10-11
12
18
 
13
19
  ### Fixed
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: rustuya-local
3
- Version: 0.1.0.dev5
4
- Summary: Local Tuya control: rustuya-bridge -> tuya2ildevice -> IL (ildevice). HA-independent core.
3
+ Version: 0.1.0.dev6
4
+ Summary: Local Tuya control: rustuya-bridge -> tuya-interpreter -> IL (ildevice). HA-independent core.
5
5
  Project-URL: Homepage, https://github.com/3735943886/rustuya-local
6
6
  Project-URL: Repository, https://github.com/3735943886/rustuya-local
7
7
  Project-URL: Issues, https://github.com/3735943886/rustuya-local/issues
@@ -10,7 +10,7 @@ License-File: LICENSE
10
10
  Requires-Python: >=3.13
11
11
  Requires-Dist: paho-mqtt>=2.0
12
12
  Requires-Dist: pyrustuyabridge>=0.4
13
- Requires-Dist: tuya2ildevice>=0.4.0.dev4
13
+ Requires-Dist: tuya-interpreter>=0.1.0a1
14
14
  Provides-Extra: fullstack
15
15
  Requires-Dist: tuyamock; extra == 'fullstack'
16
16
  Provides-Extra: manager
@@ -37,7 +37,7 @@ rustuya-bridge ──MQTT──► rustuya-local ──MQTT (il/…)──► il
37
37
  BridgeClient + rustuya_local.host.Hub
38
38
  ```
39
39
 
40
- - **[tuya2ildevice](https://github.com/3735943886/tuya2ildevice)** is the only place that interprets Tuya: Home Assistant core's `tuya` behaviour and
40
+ - **[tuya-interpreter](https://github.com/3735943886/tuya-interpreter)** is the only place that interprets Tuya: Home Assistant core's `tuya` behaviour and
41
41
  user overrides for non-standard devices, through its Sans-I/O Rust engine and Python wrapper.
42
42
  - **rustuya-local** is one `Service` (`src/rustuya_local/service.py`) and three thin shells that run it:
43
43
  the `rustuya-local run` daemon, the `custom_components/rustuya` Home Assistant integration, and a rustuya-manager
@@ -62,7 +62,7 @@ Stopping the daemon only marks it `offline`; its devices stay in IL (retained) f
62
62
  and run `rustuya-local purge --config config.json`: the retained descriptors, values and presence of its IL prefix and
63
63
  source are cleared (other sources on the prefix are left alone), so IL consumers drop the devices.
64
64
 
65
- ## tuya2ildevice 0.4 host boundary
65
+ ## tuya-interpreter host boundary
66
66
 
67
67
  The shared Rust core interprets one device and has no MQTT or rule-file loading API.
68
68
  `rustuya_local.host.Hub` owns the device registry and maps `TuyaDriver` outputs to IL MQTT wire data;
@@ -96,16 +96,16 @@ everything on an external bridge, are left as they are.
96
96
  Tuya's cloud schemas are fragmented; fixes go in a `custom_converters/` directory (daemon: `custom_converters` in the
97
97
  config; integration: `<config>/rustuya_converters`; manager plugin: its data dir), followed live:
98
98
 
99
- - `*.json`: tuya2ildevice override blocks by product or device id: rename a dp, define one the schema lacks, map the
99
+ - `*.json`: tuya-interpreter override blocks by product or device id: rename a dp, define one the schema lacks, map the
100
100
  device's words to the standard ones (`remap.alias`), fix labels and classes, define a declarative converter. A cover's
101
101
  direction is not set here but with its settings (below). Each file is a rule object with fixes under `overrides`, for example
102
102
  `{"overrides": {"product_id": {"cover": {"invert_position": true}}}}`.
103
103
  - Converters are JSON programs under `converters.declarative`; Python code plugins are not loaded.
104
104
 
105
- See tuya2ildevice's README ("User overrides") for the format. Official builtin rules, including `00-default.json`,
106
- ship with tuya2ildevice and update when that package is upgraded. They are applied before your own rule files.
105
+ See tuya-interpreter's [device customization guide](https://github.com/3735943886/tuya-interpreter/blob/master/docs/device-customization.md#user-overrides) for the format. Official builtin rules, including `00-default.json`,
106
+ ship with tuya-interpreter and update when that package is upgraded. They are applied before your own rule files.
107
107
 
108
- Online updates fetch the latest [builtin rules](https://github.com/3735943886/tuya2ildevice/tree/feat/rust-rule-engine/rules/builtin)
108
+ Online updates fetch the latest [builtin rules](https://github.com/3735943886/tuya-interpreter/tree/master/rules/builtin)
109
109
  into `rules/builtin/` inside the overrides directory at start and daily. In the Rustuya panel, use *Update builtin rules*
110
110
  to fetch them now or *Automatically update builtin rules* to control automatic updates. Opening the panel checks for
111
111
  updates: with automatic updates on, available changes are installed immediately without a yellow dot. With automatic
@@ -158,7 +158,7 @@ language: Korean, or English.
158
158
  ## rustuya-manager plugin
159
159
 
160
160
  Installed next to rustuya-manager, as a pip package (`pip install rustuya-local` in the manager's environment) or as
161
- the drop-in zip each release carries (`rustuya_local-<version>-dropin.zip`, tuya2ildevice binding, native library and builtin rules vendored inside, built by
161
+ the drop-in zip each release carries (`rustuya_local-<version>-dropin.zip`, tuya-interpreter binding, native library and builtin rules vendored inside, built by
162
162
  `scripts/build_dropin.py`; unpack it into the manager's plugin directory, or install it from the manager's plugin
163
163
  catalog once listed there), it appears as a **Tuya (IL)** tab and runs the service under the manager: the manager's broker and bridge root, the manager's device
164
164
  list (followed). Its data dir (`rustuya-local/` next to the manager's plugins) holds `settings.json` (`il`,
@@ -166,7 +166,7 @@ list (followed). Its data dir (`rustuya-local/` next to the manager's plugins) h
166
166
  converter files are picked up while it runs. A settings file it cannot use is shown on the tab until it is fixed.
167
167
 
168
168
  The drop-in zip includes native code for the platform on which it was built; use a matching OS and architecture,
169
- or install with pip to select the appropriate wheel. It freezes the tuya2ildevice it was built with: a tuya2ildevice fix reaches manager users with the next
169
+ or install with pip to select the appropriate wheel. It freezes the tuya-interpreter it was built with: a tuya-interpreter fix reaches manager users with the next
170
170
  rustuya-local release (bump the patch version and tag; the manager's catalog follows the release). Installed both ways
171
171
  (pip and the plugin directory), the plugin runs once.
172
172
 
@@ -178,7 +178,7 @@ rustuya-local release (bump the patch version and tag; the manager's catalog fol
178
178
 
179
179
  Everything here needs the sibling repos and, for the last two groups, `mosquitto`, `pyrustuya-bridge` and `tuyamock`
180
180
  (`pip install -e ".[test,fullstack]"`); those are skipped when missing. Parity with Home Assistant core's fixtures lives in
181
- `tuya2ildevice/tests/chain`, the wire and topic vectors in `ildevice/vectors`.
181
+ `tuya-interpreter/tests/chain`, the wire and topic vectors in `ildevice/vectors`.
182
182
 
183
183
  - `tests/unit/`: the configuration.
184
184
  - `tests/e2e/test_service.py`: the service on in-memory brokers (overrides directory, a failed start).
@@ -188,7 +188,7 @@ Everything here needs the sibling repos and, for the last two groups, `mosquitto
188
188
  - `tests/ha/`: the integration (config flow, setup).
189
189
  - `tests/e2e/test_full_stack*.py`: the real rustuya-bridge (`pyrustuyabridge`, in process) and Tuya device emulators
190
190
  (`tuyamock`) around the daemon: state, commands, rejections, a device dropping off and returning, a daemon restart, and a
191
- differential check that 38 real device shapes come out of the whole chain exactly as `tuya2ildevice` computes them.
191
+ differential check that 38 real device shapes come out of the whole chain exactly as `tuya-interpreter` computes them.
192
192
 
193
193
  ## Status
194
194
 
@@ -11,7 +11,7 @@ rustuya-bridge ──MQTT──► rustuya-local ──MQTT (il/…)──► il
11
11
  BridgeClient + rustuya_local.host.Hub
12
12
  ```
13
13
 
14
- - **[tuya2ildevice](https://github.com/3735943886/tuya2ildevice)** is the only place that interprets Tuya: Home Assistant core's `tuya` behaviour and
14
+ - **[tuya-interpreter](https://github.com/3735943886/tuya-interpreter)** is the only place that interprets Tuya: Home Assistant core's `tuya` behaviour and
15
15
  user overrides for non-standard devices, through its Sans-I/O Rust engine and Python wrapper.
16
16
  - **rustuya-local** is one `Service` (`src/rustuya_local/service.py`) and three thin shells that run it:
17
17
  the `rustuya-local run` daemon, the `custom_components/rustuya` Home Assistant integration, and a rustuya-manager
@@ -36,7 +36,7 @@ Stopping the daemon only marks it `offline`; its devices stay in IL (retained) f
36
36
  and run `rustuya-local purge --config config.json`: the retained descriptors, values and presence of its IL prefix and
37
37
  source are cleared (other sources on the prefix are left alone), so IL consumers drop the devices.
38
38
 
39
- ## tuya2ildevice 0.4 host boundary
39
+ ## tuya-interpreter host boundary
40
40
 
41
41
  The shared Rust core interprets one device and has no MQTT or rule-file loading API.
42
42
  `rustuya_local.host.Hub` owns the device registry and maps `TuyaDriver` outputs to IL MQTT wire data;
@@ -70,16 +70,16 @@ everything on an external bridge, are left as they are.
70
70
  Tuya's cloud schemas are fragmented; fixes go in a `custom_converters/` directory (daemon: `custom_converters` in the
71
71
  config; integration: `<config>/rustuya_converters`; manager plugin: its data dir), followed live:
72
72
 
73
- - `*.json`: tuya2ildevice override blocks by product or device id: rename a dp, define one the schema lacks, map the
73
+ - `*.json`: tuya-interpreter override blocks by product or device id: rename a dp, define one the schema lacks, map the
74
74
  device's words to the standard ones (`remap.alias`), fix labels and classes, define a declarative converter. A cover's
75
75
  direction is not set here but with its settings (below). Each file is a rule object with fixes under `overrides`, for example
76
76
  `{"overrides": {"product_id": {"cover": {"invert_position": true}}}}`.
77
77
  - Converters are JSON programs under `converters.declarative`; Python code plugins are not loaded.
78
78
 
79
- See tuya2ildevice's README ("User overrides") for the format. Official builtin rules, including `00-default.json`,
80
- ship with tuya2ildevice and update when that package is upgraded. They are applied before your own rule files.
79
+ See tuya-interpreter's [device customization guide](https://github.com/3735943886/tuya-interpreter/blob/master/docs/device-customization.md#user-overrides) for the format. Official builtin rules, including `00-default.json`,
80
+ ship with tuya-interpreter and update when that package is upgraded. They are applied before your own rule files.
81
81
 
82
- Online updates fetch the latest [builtin rules](https://github.com/3735943886/tuya2ildevice/tree/feat/rust-rule-engine/rules/builtin)
82
+ Online updates fetch the latest [builtin rules](https://github.com/3735943886/tuya-interpreter/tree/master/rules/builtin)
83
83
  into `rules/builtin/` inside the overrides directory at start and daily. In the Rustuya panel, use *Update builtin rules*
84
84
  to fetch them now or *Automatically update builtin rules* to control automatic updates. Opening the panel checks for
85
85
  updates: with automatic updates on, available changes are installed immediately without a yellow dot. With automatic
@@ -132,7 +132,7 @@ language: Korean, or English.
132
132
  ## rustuya-manager plugin
133
133
 
134
134
  Installed next to rustuya-manager, as a pip package (`pip install rustuya-local` in the manager's environment) or as
135
- the drop-in zip each release carries (`rustuya_local-<version>-dropin.zip`, tuya2ildevice binding, native library and builtin rules vendored inside, built by
135
+ the drop-in zip each release carries (`rustuya_local-<version>-dropin.zip`, tuya-interpreter binding, native library and builtin rules vendored inside, built by
136
136
  `scripts/build_dropin.py`; unpack it into the manager's plugin directory, or install it from the manager's plugin
137
137
  catalog once listed there), it appears as a **Tuya (IL)** tab and runs the service under the manager: the manager's broker and bridge root, the manager's device
138
138
  list (followed). Its data dir (`rustuya-local/` next to the manager's plugins) holds `settings.json` (`il`,
@@ -140,7 +140,7 @@ list (followed). Its data dir (`rustuya-local/` next to the manager's plugins) h
140
140
  converter files are picked up while it runs. A settings file it cannot use is shown on the tab until it is fixed.
141
141
 
142
142
  The drop-in zip includes native code for the platform on which it was built; use a matching OS and architecture,
143
- or install with pip to select the appropriate wheel. It freezes the tuya2ildevice it was built with: a tuya2ildevice fix reaches manager users with the next
143
+ or install with pip to select the appropriate wheel. It freezes the tuya-interpreter it was built with: a tuya-interpreter fix reaches manager users with the next
144
144
  rustuya-local release (bump the patch version and tag; the manager's catalog follows the release). Installed both ways
145
145
  (pip and the plugin directory), the plugin runs once.
146
146
 
@@ -152,7 +152,7 @@ rustuya-local release (bump the patch version and tag; the manager's catalog fol
152
152
 
153
153
  Everything here needs the sibling repos and, for the last two groups, `mosquitto`, `pyrustuya-bridge` and `tuyamock`
154
154
  (`pip install -e ".[test,fullstack]"`); those are skipped when missing. Parity with Home Assistant core's fixtures lives in
155
- `tuya2ildevice/tests/chain`, the wire and topic vectors in `ildevice/vectors`.
155
+ `tuya-interpreter/tests/chain`, the wire and topic vectors in `ildevice/vectors`.
156
156
 
157
157
  - `tests/unit/`: the configuration.
158
158
  - `tests/e2e/test_service.py`: the service on in-memory brokers (overrides directory, a failed start).
@@ -162,7 +162,7 @@ Everything here needs the sibling repos and, for the last two groups, `mosquitto
162
162
  - `tests/ha/`: the integration (config flow, setup).
163
163
  - `tests/e2e/test_full_stack*.py`: the real rustuya-bridge (`pyrustuyabridge`, in process) and Tuya device emulators
164
164
  (`tuyamock`) around the daemon: state, commands, rejections, a device dropping off and returning, a daemon restart, and a
165
- differential check that 38 real device shapes come out of the whole chain exactly as `tuya2ildevice` computes them.
165
+ differential check that 38 real device shapes come out of the whole chain exactly as `tuya-interpreter` computes them.
166
166
 
167
167
  ## Status
168
168
 
@@ -1,6 +1,6 @@
1
1
  """An embedded rustuya-bridge: `pyrustuyabridge.PyBridgeServer` run in a background thread, tied to this config
2
2
  entry's lifecycle instead of a separate rustuya-bridge process. Same class our own end-to-end tests drive
3
- (tuya2ildevice/rustuya-local tests/e2e/test_full_stack.py) — proven against a real broker and real Tuya-protocol
3
+ (tuya-interpreter/rustuya-local tests/e2e/test_full_stack.py) — proven against a real broker and real Tuya-protocol
4
4
  devices, just supervised here instead of by a test fixture.
5
5
 
6
6
  The embedded bridge still needs a real MQTT broker to talk through (it manages its own native MQTT client); it does
@@ -28,7 +28,7 @@ CONF_DEVICES_PATH = "devices_path" # tuyadevices.json; the cloud wi
28
28
  # --- entry options (changed any time through the options flow) -------------------------
29
29
  CONF_ALLOW_HAZARDOUS = "allow_hazardous"
30
30
  CONF_EXPOSE_UNUSED = "expose_unused"
31
- CONF_PACK = "pack" # sync tuya2ildevice's override pack into CONVERTERS_DIR
31
+ CONF_PACK = "pack" # sync tuya-interpreter's override pack into CONVERTERS_DIR
32
32
  CONF_PANEL = "panel" # the sidebar page (panel.py); Configure adds / removes it
33
33
 
34
34
  DEFAULT_OPTIONS = {CONF_ALLOW_HAZARDOUS: False, CONF_EXPOSE_UNUSED: False, CONF_PACK: True}
@@ -9,12 +9,12 @@
9
9
  "iot_class": "local_push",
10
10
  "issue_tracker": "https://github.com/3735943886/rustuya-local/issues",
11
11
  "requirements": [
12
- "tuya2ildevice>=0.4.0.dev4",
12
+ "tuya-interpreter>=0.1.0a1",
13
13
  "paho-mqtt>=2.0",
14
14
  "rustuya-manager>=0.2.2",
15
15
  "pyrustuyabridge>=0.4",
16
- "rustuya-local>=0.1.0.dev5"
16
+ "rustuya-local>=0.1.0.dev6"
17
17
  ],
18
18
  "single_config_entry": true,
19
- "version": "0.1.0.dev5"
19
+ "version": "0.1.0.dev6"
20
20
  }
@@ -195,9 +195,9 @@ const I18N = {
195
195
  settings_unreadable: "Cannot read the settings: {error}", confirm_settings: "Save {names} and restart Rustuya?",
196
196
  sync_now: "Update builtin rules", hide_title: "Remove this panel from the sidebar; the integration's Configure adds it back",
197
197
  hide: "Hide panel", pack_title: "Builtin rules",
198
- pack_intro: "Official rules included with tuya2ildevice. Fetch the latest rules without updating the integration.",
198
+ pack_intro: "Official rules included with tuya-interpreter. Fetch the latest rules without updating the integration.",
199
199
  converters_title: "Custom converters",
200
- converters_intro: "Rule files (*.json: override blocks and declarative converters) in rustuya_converters/. Saved files apply within seconds. See tuya2ildevice's README, \"User overrides\". Drop files here to copy them in.",
200
+ converters_intro: "Rule files (*.json: override blocks and declarative converters) in rustuya_converters/. Saved files apply within seconds. See tuya-interpreter docs/device-customization.md, \"User overrides\". Drop files here to copy them in.",
201
201
  new_file: "New file", save: "Save", delete: "Delete",
202
202
  only_converters: "{name} (only *.json files are converters)",
203
203
  confirm_replace_pack: "{name} comes from the override pack. Replaced, it is yours: the pack no longer updates or removes it.",
@@ -266,9 +266,9 @@ const I18N = {
266
266
  settings_unreadable: "설정을 읽을 수 없습니다: {error}", confirm_settings: "{names}을(를) 저장하고 Rustuya를 재시작할까요?",
267
267
  sync_now: "Builtin 규칙 업데이트", hide_title: "사이드바에서 이 패널을 없앱니다. 통합구성요소의 구성(Configure)에서 다시 추가할 수 있습니다",
268
268
  hide: "패널 숨기기", pack_title: "Builtin 규칙",
269
- pack_intro: "tuya2ildevice에 포함된 공식 규칙입니다. 통합구성요소 업데이트 없이 최신 규칙을 가져옵니다.",
269
+ pack_intro: "tuya-interpreter에 포함된 공식 규칙입니다. 통합구성요소 업데이트 없이 최신 규칙을 가져옵니다.",
270
270
  converters_title: "커스텀 컨버터",
271
- converters_intro: "rustuya_converters/ 안의 규칙 파일(*.json: 오버라이드 블록과 선언형 컨버터). 저장한 파일은 몇 초 안에 적용됩니다. tuya2ildevice README의 \"User overrides\"를 참고하세요. 여기에 파일을 끌어다 놓으면 복사됩니다.",
271
+ converters_intro: "rustuya_converters/ 안의 규칙 파일(*.json: 오버라이드 블록과 선언형 컨버터). 저장한 파일은 몇 초 안에 적용됩니다. tuya-interpreter docs/device-customization.md의 \"User overrides\"를 참고하세요. 여기에 파일을 끌어다 놓으면 복사됩니다.",
272
272
  new_file: "새 파일", save: "저장", delete: "삭제",
273
273
  only_converters: "{name} (*.json 파일만 컨버터입니다)",
274
274
  confirm_replace_pack: "{name}은(는) 오버라이드 팩의 파일입니다. 바꾸면 내 파일이 되어 팩이 더 이상 갱신하거나 지우지 않습니다.",
@@ -1,4 +1,4 @@
1
- # Moving to tuya2ildevice 0.4
1
+ # Moving to tuya-interpreter
2
2
 
3
3
  The device file, MQTT configuration and IL topics stay the same. Custom files in the converters directory now use
4
4
  the rule-layer format. Wrap an existing product/device override mapping in `{"overrides": ...}`. For example:
@@ -30,7 +30,7 @@ rustuya-manager plugin. It is retired. Its replacement is two pieces:
30
30
  `ildevice`, and Home Assistant keeps the two apart. Automations, scripts and dashboards that name the old entities
31
31
  need the new ids. If you clear the old discovery first (step 1), the old ids are free and you can rename the new
32
32
  entities to them in Home Assistant.
33
- - **Entities follow Home Assistant core's `tuya` integration** (tuya2ildevice reproduces it), so a device can come out
33
+ - **Entities follow Home Assistant core's `tuya` integration** (tuya-interpreter reproduces it), so a device can come out
34
34
  with more, fewer or differently split entities than v1 made.
35
35
  - **Availability** comes from rustuya-local's presence: when it stops, its devices show unavailable.
36
36
 
@@ -61,7 +61,7 @@ rustuya-manager plugin. It is retired. Its replacement is two pieces:
61
61
  | daemon | `custom_converters` in its `config.json` |
62
62
 
63
63
  - `*.json` files are rule layers, with product/device fixes under `overrides`
64
- ([User overrides](https://github.com/3735943886/tuya2ildevice#user-overrides)); the old ones are not read, so rewrite them.
64
+ ([User overrides](https://github.com/3735943886/tuya-interpreter/blob/master/docs/device-customization.md#user-overrides)); the old ones are not read, so rewrite them.
65
65
  A property the tables do not build is defined from its dp in `props`.
66
66
  - A curtain's `invert_position` / `invert_set_position`, reversed command words and derived state are not files any
67
67
  more: each cover has configuration switches for them (README, *Cover settings*).
@@ -69,7 +69,7 @@ rustuya-manager plugin. It is retired. Its replacement is two pieces:
69
69
  - `converters.cover_motion` and a cover's `infer_motion` are read as the cover's `state_source` (`inferred`, or
70
70
  `none` for `infer_motion: false`), and a `cover_motion` `settle` as the cover's `settle`; its other keys are
71
71
  dropped with a warning. `zz_settings.json` is rewritten in the new form the next time a setting is saved.
72
- - Leave the old pack (`00_default.json`, `00_curtain.py`, `.rustuya_pack.json`) out. Official rules ship with tuya2ildevice; online updates arrive under
72
+ - Leave the old pack (`00_default.json`, `00_curtain.py`, `.rustuya_pack.json`) out. Official rules ship with tuya-interpreter; online updates arrive under
73
73
  `rules/builtin/` automatically. User files are applied after all official rules.
74
74
 
75
75
  Changes to the directory are picked up while running, no restart needed.
@@ -1,6 +1,6 @@
1
- # 남은 일 (2026-10-11 갱신)
1
+ # 남은 일 (2026-10-12 갱신)
2
2
 
3
- 현재 작업 트리는 `rustuya-local 0.1.0.dev2`이며 `tuya2ildevice>=0.4.0.dev3`, `pyrustuyabridge>=0.4`를 요구한다.
3
+ 현재 작업 트리는 `rustuya-local 0.1.0.dev6`이며 `tuya-interpreter>=0.1.0a1`, `pyrustuyabridge>=0.4`를 요구한다.
4
4
  HA 통합과 매니저 플러그인 테스트는 `rustuya-manager>=0.2.2`를 사용한다. 변환은 Sans-I/O Rust 드라이버가 맡고,
5
5
  기기 레지스트리·IL MQTT 어댑터·전송·타이머·규칙 파일 로딩은 `rustuya_local.host`로 옮겼다.
6
6
  버전별 변경은 [CHANGELOG.md](../CHANGELOG.md)에 기록한다. 이 문서는 실제 배포 서버의 최신 상태를 확인하는 자료가 아니다.
@@ -4,12 +4,12 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "rustuya-local"
7
- version = "0.1.0.dev5"
8
- description = "Local Tuya control: rustuya-bridge -> tuya2ildevice -> IL (ildevice). HA-independent core."
7
+ version = "0.1.0.dev6"
8
+ description = "Local Tuya control: rustuya-bridge -> tuya-interpreter -> IL (ildevice). HA-independent core."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
11
11
  license = "MIT"
12
- dependencies = ["tuya2ildevice>=0.4.0.dev4", "pyrustuyabridge>=0.4", "paho-mqtt>=2.0"]
12
+ dependencies = ["tuya-interpreter>=0.1.0a1", "pyrustuyabridge>=0.4", "paho-mqtt>=2.0"]
13
13
  # rustuya-manager (custom_components/rustuya's config flow) is optional at the package level (the HA manifest
14
14
  # pulls it in); declared here too so the venv used for this repo's tests has it. pyrustuyabridge is a base dependency
15
15
  # now (not just for the embedded bridge): rustuya-local's own bridge_client uses it to interpret rustuya-bridge's
@@ -0,0 +1,3 @@
1
+ ### Changed
2
+ - Require tuya-interpreter 0.1.0a1 (tuya2ildevice renamed) in place of tuya2ildevice, in the package, the Home Assistant integration and the manager drop-in archive.
3
+ - Fetch builtin rule updates from tuya-interpreter's `master` branch.
@@ -3,7 +3,7 @@
3
3
 
4
4
  The manager downloads the zip, checks its SHA-256 against its catalog, unpacks it into its plugin directory and calls
5
5
  the top-level package's `register(ctx)`. A dropped-in plugin cannot pip-install, so the zip has one top-level entry,
6
- `rustuya_local/`, with tuya2ildevice (Python binding, native library and rule pack) vendored under `rustuya_local/_vendor/`. paho-mqtt and
6
+ `rustuya_local/`, with tuya-interpreter (Python binding, native library and rule pack) vendored under `rustuya_local/_vendor/`. paho-mqtt and
7
7
  pyrustuyabridge are not vendored: the manager depends on both.
8
8
 
9
9
  The bytes depend only on the file contents (sorted entries, fixed timestamps and modes, no compression), so the same
@@ -11,7 +11,7 @@ sources give the same SHA-256.
11
11
 
12
12
  python scripts/build_dropin.py [--outdir dist]
13
13
 
14
- tuya2ildevice is taken from the environment the script runs in (install rustuya-local first).
14
+ tuya-interpreter is taken from the environment the script runs in (install rustuya-local first).
15
15
  """
16
16
 
17
17
  from __future__ import annotations
@@ -28,7 +28,7 @@ from pathlib import Path
28
28
  REPO_ROOT = Path(__file__).resolve().parent.parent
29
29
  PKG_DIR = REPO_ROOT / "src" / "rustuya_local"
30
30
  FIXED_DATE_TIME = (1980, 1, 1, 0, 0, 0)
31
- VENDORED = ("tuya2ildevice",)
31
+ VENDORED = ("tuya_interpreter",)
32
32
 
33
33
 
34
34
  def _files(root: Path) -> list[Path]:
@@ -46,10 +46,10 @@ def _members() -> list[tuple[str, Path]]:
46
46
  sys.exit(f"error: {name} is not installed; install rustuya-local first")
47
47
  root = Path(next(iter(spec.submodule_search_locations)))
48
48
  out += [(f"rustuya_local/_vendor/{name}/{p.relative_to(root).as_posix()}", p) for p in _files(root)]
49
- if name == "tuya2ildevice":
49
+ if name == "tuya_interpreter":
50
50
  # Editable checkouts keep build outputs and rule artifacts outside the Python package.
51
51
  # Installed wheels already contain them; include equivalent assets when building locally.
52
- from tuya2ildevice.native import library
52
+ from tuya_interpreter.native import library
53
53
 
54
54
  from rustuya_local.host.rules import rule_files, rule_paths
55
55
 
@@ -3,8 +3,8 @@
3
3
  import sys
4
4
  from pathlib import Path
5
5
 
6
- # The rustuya-manager drop-in zip (scripts/build_dropin.py) carries tuya2ildevice here, since a dropped-in plugin cannot
7
- # pip-install. Appended, not prepended: an installed tuya2ildevice wins.
6
+ # The rustuya-manager drop-in zip (scripts/build_dropin.py) carries tuya-interpreter here, since a dropped-in plugin cannot
7
+ # pip-install. Appended, not prepended: an installed tuya-interpreter wins.
8
8
  _VENDOR = Path(__file__).parent / "_vendor"
9
9
  if _VENDOR.is_dir() and str(_VENDOR) not in sys.path:
10
10
  sys.path.append(str(_VENDOR))
@@ -30,7 +30,7 @@ from dataclasses import dataclass
30
30
  from typing import Any
31
31
 
32
32
  import pyrustuyabridge as pb
33
- from tuya2ildevice import Connected, Disconnected, Message
33
+ from tuya_interpreter import Connected, Disconnected, Message
34
34
 
35
35
  from rustuya_local.host import BridgeCommand, Runner
36
36
  from rustuya_local.host.transport import Message as TransportMessage
@@ -15,7 +15,7 @@
15
15
  (overrides and declarative converters, see `rustuya_local.host.load_overrides`), followed the same
16
16
  way; `options.overrides` is merged over it. A device's settings written through IL (a cover's direction switches) are
17
17
  kept in that directory too; `options.device_settings: false` stops offering them. `pack` (on by default) copies
18
- tuya2ildevice's override pack, fixes published between releases, into that directory daily. Every key but `devices`
18
+ tuya-interpreter's override pack, fixes published between releases, into that directory daily. Every key but `devices`
19
19
  has a default. The bridge's own topic templates are read from its retained `{root}/bridge/config` at start.
20
20
  """
21
21
 
@@ -1,4 +1,4 @@
1
- """Run the host-owned `Hub` over tuya2ildevice 0.4 drivers: MQTT (or in-process) transports, timers, Last Will presence, reconnects,
1
+ """Run the host-owned `Hub` over tuya-interpreter drivers: MQTT (or in-process) transports, timers, Last Will presence, reconnects,
2
2
  runtime device changes, following rustuya-manager's `tuyadevices.json` and a directory of user rule files. TuyaDriver is Sans-I/O; this package owns file loading, clocks and transport operations.
3
3
 
4
4
  from rustuya_local.host import MqttTransport, Runner
@@ -1,5 +1,5 @@
1
1
  """The device list: `tuyadevices.json`, which rustuya-manager keeps (its QR-login wizard writes it, atomically). Each
2
- entry is a Tuya cloud record with the schema tuya2ildevice needs (`category`, `product_id`, `function`,
2
+ entry is a Tuya cloud record with the schema tuya-interpreter needs (`category`, `product_id`, `function`,
3
3
  `status_range`, `local_strategy`). rustuya-local reads it and follows it as it changes; it never writes it."""
4
4
 
5
5
  from __future__ import annotations
@@ -7,8 +7,15 @@ from collections import Counter
7
7
  from collections.abc import Sequence
8
8
  from typing import Any
9
9
 
10
- from tuya2ildevice import Command, Connected, Disconnected, Message, Timer, TuyaDriver
11
- from tuya2ildevice.native import register_rules, unregister_rules
10
+ from tuya_interpreter import (
11
+ Command,
12
+ Connected,
13
+ Disconnected,
14
+ Message,
15
+ Timer,
16
+ TuyaDriver,
17
+ )
18
+ from tuya_interpreter.native import register_rules, unregister_rules
12
19
 
13
20
  from .il import (
14
21
  IL,
@@ -1,11 +1,11 @@
1
- """IL MQTT wire mapping and host actions. Tuya interpretation stays in tuya2ildevice."""
1
+ """IL MQTT wire mapping and host actions. Tuya interpretation stays in tuya-interpreter."""
2
2
  from __future__ import annotations
3
3
 
4
4
  import json
5
5
  from dataclasses import dataclass
6
6
  from typing import Any
7
7
 
8
- from tuya2ildevice import (
8
+ from tuya_interpreter import (
9
9
  Absent,
10
10
  CancelTimer,
11
11
  Descriptor,
@@ -1,7 +1,7 @@
1
1
  """User rule files: a directory (or one `.json` file) of partial rule objects, loaded and followed as it changes.
2
2
 
3
3
  Each `*.json` is a rule layer (product/device fixes under `overrides`), merged in filename order over the rules
4
- tuya2ildevice ships and validated by its engine. `SETTINGS_FILE` (``zz_settings.json``) holds the settings written
4
+ tuya-interpreter ships and validated by its engine. `SETTINGS_FILE` (``zz_settings.json``) holds the settings written
5
5
  through IL, a block per device (`OverrideWatcher.save_settings`); it can be edited like any other file.
6
6
 
7
7
  Files starting with `.` or `_` are skipped. Nothing here raises for a bad file: a file that does
@@ -18,7 +18,7 @@ from dataclasses import dataclass, field
18
18
  from pathlib import Path
19
19
  from typing import Any
20
20
 
21
- from tuya2ildevice import OverrideError, merge_all
21
+ from tuya_interpreter import OverrideError, merge_all
22
22
 
23
23
  from rustuya_local.host.rules import load_rules_tolerant, rule_files, upgrade_overrides
24
24
 
@@ -1,4 +1,4 @@
1
- """The override pack: fixes for non-standard devices published on tuya2ildevice's `feat/rust-rule-engine` branch (`rules/builtin/`) and copied into
1
+ """The override pack: fixes for non-standard devices published on tuya-interpreter's `master` branch (`rules/builtin/`) and copied into
2
2
  the host's rule directory, so a fix reaches users without a release. `OverrideWatcher` then loads the copied files
3
3
  like the user's own. The files are rule layers (JSON); fetching them is the host's, the engine only merges them.
4
4
 
@@ -37,10 +37,10 @@ from .overrides import SETTINGS_FILE
37
37
 
38
38
  _LOGGER = logging.getLogger(__name__)
39
39
 
40
- LEVEL = 4 # 2: `cover` settings; 3: `delta`; 4: rule-layer files (tuya2ildevice 0.4)
41
- BASE_URL = "https://raw.githubusercontent.com/3735943886/tuya2ildevice/feat/rust-rule-engine/rules/builtin/"
40
+ LEVEL = 4 # 2: `cover` settings; 3: `delta`; 4: rule-layer files (tuya2ildevice 0.4, tuya-interpreter)
41
+ BASE_URL = "https://raw.githubusercontent.com/3735943886/tuya-interpreter/master/rules/builtin/"
42
42
  MANIFEST = "manifest.json"
43
- LEDGER = ".tuya2ildevice_pack.json"
43
+ LEDGER = ".tuya2ildevice_pack.json" # kept across the rename: existing installs own their files by it
44
44
  MAX_BYTES = 1024 * 1024
45
45
  TIMEOUT = 15
46
46
  _NAME = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.-]*\.json$")
@@ -8,8 +8,8 @@ import logging
8
8
  import os
9
9
  from pathlib import Path
10
10
 
11
- import tuya2ildevice
12
- from tuya2ildevice import merge_rules
11
+ import tuya_interpreter
12
+ from tuya_interpreter import merge_rules
13
13
 
14
14
  _LOGGER = logging.getLogger(__name__)
15
15
 
@@ -63,7 +63,7 @@ def _upgrade_layer(data, where):
63
63
 
64
64
 
65
65
  def rule_paths(paths=(), *, bundled_path=None):
66
- package = Path(tuya2ildevice.__file__).resolve().parent
66
+ package = Path(tuya_interpreter.__file__).resolve().parent
67
67
  bundled = package / 'rules' / 'builtin'
68
68
  checkout = package.parents[1] / 'rules' / 'builtin'
69
69
  location = bundled_path or (bundled if bundled.is_dir() else checkout)
@@ -13,8 +13,8 @@ import secrets
13
13
  import time
14
14
  from collections.abc import Awaitable, Callable, Sequence
15
15
 
16
- from tuya2ildevice import Connected, Disconnected
17
- from tuya2ildevice import Message as DriverInput
16
+ from tuya_interpreter import Connected, Disconnected
17
+ from tuya_interpreter import Message as DriverInput
18
18
 
19
19
  from rustuya_local.host.il import (
20
20
  IL,
@@ -15,7 +15,7 @@ its documented contract (api_version >= 4). What it takes from the manager:
15
15
  {"il": {"prefix": "il", "source": "tuya"},
16
16
  "options": {"allow_hazardous": false, "expose_unused": false, "use_quirks": true, "pack": true}}
17
17
 
18
- `pack` copies tuya2ildevice's override pack (fixes published between releases) into `custom_converters/` daily.
18
+ `pack` copies tuya-interpreter's override pack (fixes published between releases) into `custom_converters/` daily.
19
19
 
20
20
  The tab shows what the service is doing (the plugin's state namespace) and edits the settings and the
21
21
  `custom_converters/` files through `/api/rustuya-local/...` (`api.py`). A settings change restarts the service in place;
@@ -228,7 +228,7 @@ async function convertersBox(ctx) {
228
228
  box.append(
229
229
  el("p", { class: "text-sm text-gray-500 mb-2" },
230
230
  "Rule files (*.json: override blocks and declarative converters) for non-standard devices. ",
231
- "See tuya2ildevice's README, \"User overrides\". Drop files here to copy them in."),
231
+ "See tuya-interpreter docs/device-customization.md, \"User overrides\". Drop files here to copy them in."),
232
232
  list, warnings,
233
233
  el("div", { class: "flex gap-2 mb-2 items-center" }, el("label", {}, "File ", name),
234
234
  el("button", { class: BTN, onclick: save }, "Save"), el("button", { class: BTN, onclick: remove }, "Delete"),
@@ -16,10 +16,10 @@ integration, the rustuya-manager plugin or a daemon) serves them, since every de
16
16
  `online` that nobody answers for (a Last Will lost with the broker, or a producer on tuya2ildevice < 0.3.5) does not
17
17
  stop the start.
18
18
 
19
- With `pack` on, the override pack (tuya2ildevice's `rules/builtin/`) is copied into the overrides directory in the background at
19
+ With `pack` on, the override pack (tuya-interpreter's `rules/builtin/`) is copied into the overrides directory in the background at
20
20
  start and every `pack_interval` seconds; the directory watcher loads what it brings. Manual requests work with `pack` off.
21
21
 
22
- A device's settings (a cover's direction toggles, tuya2ildevice's `device_settings`) are IL properties like any other;
22
+ A device's settings (a cover's direction toggles, tuya-interpreter's `device_settings`) are IL properties like any other;
23
23
  writing one saves it into the overrides directory (`rustuya_local.host.SETTINGS_FILE`), which the watcher applies at
24
24
  once. Without an overrides directory there is nowhere to keep them, so the Hub does not offer them.
25
25
  """
@@ -36,7 +36,7 @@ from dataclasses import dataclass, field
36
36
  from pathlib import Path
37
37
  from typing import Any
38
38
 
39
- from tuya2ildevice import preload
39
+ from tuya_interpreter import preload
40
40
 
41
41
  from rustuya_local.host import (
42
42
  BridgeCommand,
@@ -117,7 +117,7 @@ class Settings:
117
117
  watch_interval: float = 5.0
118
118
  pack: bool = False # automatically sync rules; manual sync remains available
119
119
  pack_interval: float = 86400.0
120
- pack_url: str | None = None # the pack's base URL; tuya2ildevice's `master` when None
120
+ pack_url: str | None = None # the pack's base URL; tuya-interpreter's `master` when None
121
121
  hub_options: dict[str, Any] = field(default_factory=dict)
122
122
  """`rustuya_local.host.Hub` keyword arguments: `allow_hazardous`, `expose_unused`, `use_quirks`, `device_settings` (on
123
123
  by default, and only with an overrides directory), `overrides` (inline, merged over the directory's), `rules`."""
@@ -48,7 +48,7 @@ def status_reply(ids, offset=0, has_more=False, total=None):
48
48
  "returned": len(ids), "has_more": has_more, **({"device_count": total} if total is not None else {})})
49
49
 
50
50
 
51
- GOLDEN = pathlib.Path(__file__).resolve().parents[3] / "tuya2ildevice/tests/golden" # the sibling checkout
51
+ GOLDEN = pathlib.Path(__file__).resolve().parents[3] / "tuya-interpreter/tests/golden" # the sibling checkout
52
52
  WIRE = {"Boolean": "Boolean", "Integer": "Integer", "Enum": "Enum", "String": "String", "Raw": "Raw", "Json": "Json",
53
53
  "Bitmap": "Bitmap"}
54
54
 
@@ -1,6 +1,6 @@
1
1
  """Differential test over the real bridge: many real device shapes (Home Assistant core's tuya fixtures) each get a
2
2
  tuyamock device with the fixture's dps, go through the real rustuya-bridge and the rustuya-local daemon, and the IL values
3
- that come out must equal what tuya2ildevice produces when it is fed the same dps directly.
3
+ that come out must equal what tuya-interpreter produces when it is fed the same dps directly.
4
4
 
5
5
  What this catches that the in-process tests cannot: how the bridge serialises each Tuya type on the wire (booleans,
6
6
  scaled integers, enums, strings, raw/base64, json), and anything the daemon does to a message on the way through.
@@ -20,12 +20,12 @@ import pytest
20
20
  pyrustuyabridge = pytest.importorskip("pyrustuyabridge")
21
21
  tuyamock = pytest.importorskip("tuyamock")
22
22
 
23
- GOLDEN = pathlib.Path(__file__).resolve().parents[3] / "tuya2ildevice/tests/golden" # the sibling checkout
23
+ GOLDEN = pathlib.Path(__file__).resolve().parents[3] / "tuya-interpreter/tests/golden" # the sibling checkout
24
24
  sys.path.insert(0, str(GOLDEN))
25
25
  import fixtures
26
26
  from devices import fixture_record as record
27
27
  from test_full_stack import Observer, wait
28
- from tuya2ildevice import Connected, Message, TuyaDriver, Value
28
+ from tuya_interpreter import Connected, Message, TuyaDriver, Value
29
29
 
30
30
  from rustuya_local.host.il import encode_value
31
31
  from rustuya_local.host.rules import rules
@@ -99,9 +99,9 @@ plugin_dir = Path(sys.argv[1])
99
99
  vendor = plugin_dir / "rustuya_local" / "_vendor"
100
100
 
101
101
  class OnlyVendored:
102
- # tuya2ildevice may be installed here; a manager's environment has none, so resolve it from the zip only
102
+ # tuya-interpreter may be installed here; a manager's environment has none, so resolve it from the zip only
103
103
  def find_spec(self, name, path=None, target=None):
104
- if name.split(".")[0] != "tuya2ildevice" or path is not None:
104
+ if name.split(".")[0] != "tuya_interpreter" or path is not None:
105
105
  return None
106
106
  spec = importlib.machinery.PathFinder.find_spec(name, [str(vendor)])
107
107
  if spec is None:
@@ -118,12 +118,12 @@ ctx = plugins.PluginContext(plugins.PluginRegistry(), state=state, data_root=Pat
118
118
  bridge_client=BridgeClient("mqtt://127.0.0.1:1", "r", state))
119
119
  for r in registers:
120
120
  r(ctx)
121
- import rustuya_local, tuya2ildevice
121
+ import rustuya_local, tuya_interpreter
122
122
  from rustuya_local.service import Service
123
123
  from rustuya_local.host import MqttTransport
124
124
  assert Path(rustuya_local.__file__).is_relative_to(plugin_dir), rustuya_local.__file__
125
- assert Path(tuya2ildevice.__file__).is_relative_to(vendor), tuya2ildevice.__file__
126
- from tuya2ildevice import TuyaDriver, Connected, Command, SendMessage
125
+ assert Path(tuya_interpreter.__file__).is_relative_to(vendor), tuya_interpreter.__file__
126
+ from tuya_interpreter import TuyaDriver, Connected, Command, SendMessage
127
127
  from rustuya_local.host.rules import rules
128
128
  check = TuyaDriver({"id": "vendored", "category": "kg",
129
129
  "function": {"switch_1": {"type": "Boolean", "values": {}}}},
@@ -135,7 +135,7 @@ print(len(registers), [p["id"] for p in ctx._registry.pages], len(ctx._registry.
135
135
  """
136
136
 
137
137
 
138
- def test_the_drop_in_zip_loads_in_the_manager_with_its_vendored_tuya2ildevice(tmp_path):
138
+ def test_the_drop_in_zip_loads_in_the_manager_with_its_vendored_tuya_interpreter(tmp_path):
139
139
  import importlib.util
140
140
  import subprocess
141
141
  import sys
@@ -162,7 +162,7 @@ async def test_driving_the_first_device_does_no_blocking_io_in_the_event_loop(ha
162
162
  monkeypatch):
163
163
  """The host reads rule files and the binding loads its engine: the service preloads them in a worker
164
164
  thread, so Home Assistant sees no blocking call when the first device's driver is made."""
165
- from tuya2ildevice import native
165
+ from tuya_interpreter import native
166
166
 
167
167
  from rustuya_local.host.rules import rules
168
168
 
@@ -175,7 +175,7 @@ async def test_driving_the_first_device_does_no_blocking_io_in_the_event_loop(ha
175
175
  real_read = pathlib.Path.read_text
176
176
 
177
177
  def read_text(self, *args, **kwargs): # what Home Assistant's blocking-call detector flags, recorded instead
178
- if threading.current_thread() is loop_thread and "tuya2ildevice" in str(self):
178
+ if threading.current_thread() is loop_thread and "tuya_interpreter" in str(self):
179
179
  in_loop.append(self.name)
180
180
  return real_read(self, *args, **kwargs)
181
181
  monkeypatch.setattr(pathlib.Path, "read_text", read_text)
@@ -5,7 +5,7 @@ import json
5
5
  import threading
6
6
 
7
7
  import pytest
8
- from tuya2ildevice import Command, Connected, Message
8
+ from tuya_interpreter import Command, Connected, Message
9
9
 
10
10
  from rustuya_local.host import (
11
11
  SETTINGS_FILE,
@@ -1,4 +1,4 @@
1
- """The rustuya-manager drop-in zip: one top-level package with tuya2ildevice vendored, byte-identical rebuilds."""
1
+ """The rustuya-manager drop-in zip: one top-level package with tuya-interpreter vendored, byte-identical rebuilds."""
2
2
  import hashlib
3
3
  import importlib.util
4
4
  import os
@@ -14,15 +14,15 @@ sys.modules["build_dropin"] = build_dropin
14
14
  spec.loader.exec_module(build_dropin)
15
15
 
16
16
 
17
- def test_one_package_with_tuya2ildevice_inside(tmp_path):
17
+ def test_one_package_with_tuya_interpreter_inside(tmp_path):
18
18
  zf = zipfile.ZipFile(build_dropin.build(tmp_path))
19
19
  names = zf.namelist()
20
20
  assert {n.split("/", 1)[0] for n in names} == {"rustuya_local"} # the manager imports each top-level entry
21
21
  for needed in ("rustuya_local/__init__.py", "rustuya_local/manager_plugin/static/index.js",
22
- "rustuya_local/_vendor/tuya2ildevice/__init__.py", "rustuya_local/_vendor/tuya2ildevice/native.py"):
22
+ "rustuya_local/_vendor/tuya_interpreter/__init__.py", "rustuya_local/_vendor/tuya_interpreter/native.py"):
23
23
  assert needed in names
24
- assert "rustuya_local/_vendor/tuya2ildevice/rules/builtin/00-default.json" in names
25
- assert any(n.startswith("rustuya_local/_vendor/tuya2ildevice/") and n.endswith((".so", ".dll", ".dylib"))
24
+ assert "rustuya_local/_vendor/tuya_interpreter/rules/builtin/00-default.json" in names
25
+ assert any(n.startswith("rustuya_local/_vendor/tuya_interpreter/") and n.endswith((".so", ".dll", ".dylib"))
26
26
  for n in names)
27
27
  assert not any("__pycache__" in n or n.startswith("rustuya_local/_vendor/paho") for n in names)
28
28
 
@@ -33,7 +33,7 @@ def test_rebuilds_are_byte_identical(tmp_path):
33
33
  assert hashlib.sha256(a).digest() == hashlib.sha256(b).digest()
34
34
 
35
35
 
36
- def test_archive_runs_driver_without_installed_tuya2ildevice(tmp_path):
36
+ def test_archive_runs_driver_without_installed_tuya_interpreter(tmp_path):
37
37
  with zipfile.ZipFile(build_dropin.build(tmp_path)) as archive:
38
38
  archive.extractall(tmp_path)
39
39
  # -I -S excludes editable installs and site-packages: both native code and rules
@@ -43,9 +43,9 @@ import sys
43
43
  from pathlib import Path
44
44
  sys.path.insert(0, sys.argv[1])
45
45
  from rustuya_local.host import Hub, BridgeCommand
46
- from tuya2ildevice import Connected, Message
47
- import tuya2ildevice
48
- assert Path(tuya2ildevice.__file__).is_relative_to(Path(sys.argv[1]))
46
+ from tuya_interpreter import Connected, Message
47
+ import tuya_interpreter
48
+ assert Path(tuya_interpreter.__file__).is_relative_to(Path(sys.argv[1]))
49
49
  device = {'id': 'd', 'category': 'kg',
50
50
  'function': {'switch_1': {'type': 'Boolean', 'values': {}}},
51
51
  'local_strategy': {'1': {'value_convert': 'default', 'status_code': 'switch_1',
@@ -1,4 +1,4 @@
1
- """The host-owned Hub around tuya2ildevice drivers (`rustuya_local.host`): Runner on the IL transport, the device file, the rule
1
+ """The host-owned Hub around tuya-interpreter drivers (`rustuya_local.host`): Runner on the IL transport, the device file, the rule
2
2
  directory, and paho against a real broker (mosquitto, skipped when it is not installed). The bridge side is simulated
3
3
  with `runner.on_bridge_message`; `BridgeCommand` outputs are captured via the injected `on_bridge_command` callback."""
4
4
  import asyncio
@@ -9,7 +9,7 @@ import subprocess
9
9
  import time
10
10
 
11
11
  import pytest
12
- from tuya2ildevice import Connected, Message, OverrideError
12
+ from tuya_interpreter import Connected, Message, OverrideError
13
13
 
14
14
  from rustuya_local.host import (
15
15
  BridgeCommand,
@@ -1,7 +1,7 @@
1
1
  import json
2
2
 
3
3
  import pytest
4
- from tuya2ildevice import Connected, Disconnected, Message
4
+ from tuya_interpreter import Connected, Disconnected, Message
5
5
 
6
6
  from rustuya_local.host import BridgeCommand, Hub, Publish
7
7
  from tests.unit.tuya_samples import curtain, light
@@ -75,7 +75,7 @@ def test_a_multi_segment_il_prefix_still_parses_writes():
75
75
 
76
76
 
77
77
  def test_reload_overrides_republishes_and_clears_removed_props():
78
- from tuya2ildevice import OverrideError
78
+ from tuya_interpreter import OverrideError
79
79
 
80
80
  hub = Hub([curtain()])
81
81
  hub.start()
@@ -1,11 +1,11 @@
1
1
  """The host wire mapping follows ildevice conformance vectors (../ildevice/vectors, or $ILDEVICE): payloads on the
2
- wire and topics. (Command checks and descriptor schemas are exercised by tuya2ildevice.)"""
2
+ wire and topics. (Command checks and descriptor schemas are exercised by tuya-interpreter.)"""
3
3
  import json
4
4
  import os
5
5
  from pathlib import Path
6
6
 
7
7
  import pytest
8
- from tuya2ildevice import Rejected, check_command
8
+ from tuya_interpreter import Rejected, check_command
9
9
 
10
10
  from rustuya_local.host import Hub, IlTopics
11
11
  from rustuya_local.host.il import decode_write, encode_value
@@ -1,4 +1,4 @@
1
- """The override pack: `host.pack.sync` against a pack served from a directory (file://), and the one tuya2ildevice
1
+ """The override pack: `host.pack.sync` against a pack served from a directory (file://), and the one tuya-interpreter
2
2
  publishes (its sibling checkout, when there is one)."""
3
3
 
4
4
  import hashlib
@@ -10,7 +10,7 @@ import pytest
10
10
  from rustuya_local.host import load_overrides, pack
11
11
  from rustuya_local.host.pack import LEDGER, PackError, read_ledger, sync
12
12
 
13
- PUBLISHED = Path(__file__).resolve().parents[3] / "tuya2ildevice" / "rules" / "builtin" # the sibling checkout
13
+ PUBLISHED = Path(__file__).resolve().parents[3] / "tuya-interpreter" / "rules" / "builtin" # the sibling checkout
14
14
 
15
15
 
16
16
  def sha(text: str) -> str:
@@ -104,7 +104,7 @@ def test_a_bad_file_is_skipped_and_the_copy_there_stays(served):
104
104
 
105
105
  def test_files_are_bounded_by_level(served):
106
106
  src, dest = served
107
- src.put("00_pack_new.json", FIX, requires=pack.LEVEL + 1) # needs a newer tuya2ildevice
107
+ src.put("00_pack_new.json", FIX, requires=pack.LEVEL + 1) # needs a newer tuya-interpreter
108
108
  src.put("00_pack_old.json", FIX, until=pack.LEVEL) # built into this one
109
109
  src.put("00_pack_now.json", FIX, requires=pack.LEVEL, until=pack.LEVEL + 1)
110
110
  assert sync(dest, base_url=src.url).added == ["00_pack_now.json"]
@@ -130,7 +130,7 @@ def test_unsafe_names_in_the_manifest_are_ignored(served):
130
130
  assert not r.changed and not (dest.parent / "escape.json").exists()
131
131
 
132
132
 
133
- @pytest.mark.skipif(not PUBLISHED.is_dir(), reason="no tuya2ildevice checkout next to this one")
133
+ @pytest.mark.skipif(not PUBLISHED.is_dir(), reason="no tuya-interpreter checkout next to this one")
134
134
  def test_the_published_pack_loads(tmp_path):
135
135
  r = sync(tmp_path / "d", base_url=PUBLISHED.as_uri() + "/")
136
136
  assert not r.failed
@@ -5,7 +5,7 @@ import json
5
5
  import weakref
6
6
 
7
7
  import pytest
8
- from tuya2ildevice import Connected, TuyaDriver, merge_rules
8
+ from tuya_interpreter import Connected, TuyaDriver, merge_rules
9
9
 
10
10
  from rustuya_local.host import Hub, OverrideWatcher, load_overrides
11
11
  from rustuya_local.host.hub import _pack_users
@@ -84,7 +84,7 @@ def test_inline_overrides_with_older_keys_are_upgraded():
84
84
 
85
85
 
86
86
  def test_a_rule_pack_the_hub_moves_off_is_released_once_no_hub_uses_it():
87
- from tuya2ildevice.native import unregister_rules
87
+ from tuya_interpreter.native import unregister_rules
88
88
 
89
89
  own, other = labelled('only this test'), labelled('Other')
90
90
  first, second = Hub([dict(DEVICE)], rules=own), Hub([dict(DEVICE, id='e')], rules=own)
@@ -101,7 +101,7 @@ def labelled(label):
101
101
 
102
102
 
103
103
  def test_close_releases_only_the_last_owner_and_is_idempotent():
104
- from tuya2ildevice.native import unregister_rules
104
+ from tuya_interpreter.native import unregister_rules
105
105
 
106
106
  pack = labelled('shared close regression')
107
107
  first, second = Hub([DEVICE], rules=pack), Hub([DEVICE], rules=pack)
@@ -121,7 +121,7 @@ def test_close_releases_only_the_last_owner_and_is_idempotent():
121
121
 
122
122
 
123
123
  def test_a_discarded_hub_releases_its_pack():
124
- from tuya2ildevice.native import unregister_rules
124
+ from tuya_interpreter.native import unregister_rules
125
125
 
126
126
  hub = Hub([DEVICE], rules=labelled('garbage collection regression'))
127
127
  key, reference = hub._rules_id, weakref.ref(hub)
@@ -132,8 +132,8 @@ def test_a_discarded_hub_releases_its_pack():
132
132
 
133
133
 
134
134
  def test_failed_construction_releases_its_pack():
135
- from tuya2ildevice import OverrideError
136
- from tuya2ildevice.native import register_rules, unregister_rules
135
+ from tuya_interpreter import OverrideError
136
+ from tuya_interpreter.native import register_rules, unregister_rules
137
137
 
138
138
  pack = labelled('failed construction regression')
139
139
  key = register_rules(pack)
@@ -145,7 +145,7 @@ def test_failed_construction_releases_its_pack():
145
145
 
146
146
 
147
147
  def test_failed_adoption_releases_the_candidate_and_keeps_the_existing_drivers(monkeypatch):
148
- from tuya2ildevice.native import register_rules, unregister_rules
148
+ from tuya_interpreter.native import register_rules, unregister_rules
149
149
 
150
150
  hub = Hub([DEVICE, dict(DEVICE, id='e')], rules=labelled('before failed adoption'))
151
151
  pack = labelled('failed adoption regression')
@@ -1,8 +0,0 @@
1
- ### Fixed
2
- - Share the running service's complete bridge registry and MQTT command connection with the panel, so panel listing and edits do not open a second registry requester. Require complete contiguous registry pages for standalone setup sessions.
3
- - Keep explicit offline connection errors from being overwritten by replayed device state snapshots in the panel.
4
-
5
- ### Changed
6
- - Split the HA panel synced filter into online and offline, with live sub-device/gateway state and migration of saved filters.
7
- - Check builtin rules when opening the HA panel; automatically install available updates when enabled, or enable the manual update button with a yellow dot when automatic updates are off.
8
- - Allow manual builtin rule updates while automatic updates are disabled.