# Tuya: Integration von Heizung und Klimaanlage

**URL:** <https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983>\
**Category:** Demandes livrées\
**Created:** [10. Februar 2026 um 06:42 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983 "2026-02-10T06:42:29Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [26. Februar 2026 um 10:45 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/41 "2026-02-26T10:45:21Z")

</div>

Hallo @pierre-gilles,

Ich denke, ich bin bereit für eine Überprüfung dieses PR, der die Tuya-Integration aktualisiert, indem er die Grundlage für die neue Verbindung und die lokale Erkennung legt:

> <https://github.com/GladysAssistant/Gladys/pull/2434>
>
> \### Pull Request check-list
> 
> To ensure your Pull Request can be accepted as fa…st as possible, make sure to review and check all of these items:
> 
> \- \[x\] If your changes affect the code, did you write the tests?
> \- \[x\] Are tests passing? (\`npm test\` on both front/server)
> \- \[x\] Is the linter passing? (\`npm run eslint\` on both front/server)
> \- \[x\] Did you run prettier? (\`npm run prettier\` on both front/server)
> \- \[x\] If you are adding a new feature/service, did you run the integration comparator? (\`npm run compare-translations\` on front)
> \- \[x\] Did you test this pull request in real life? With real devices? If this development is a big feature or a new service, we recommend that you provide a Docker image to the community (\[forum\](https://community.gladysassistant.com/)) for testing before merging.
> \- \[\] If you are adding a new features/services which needs explanation, did you modify the user documentation? See \[the GitHub repo\](https://github.com/GladysAssistant/v4-website) and the \[website\](https://gladysassistant.com).
> \- \[\] Did you add fake requests data for the demo mode (\`front/src/config/demo.js\`) so that the demo website is working without a backend? (if needed) See \[https://demo.gladysassistant.com\](https://demo.gladysassistant.com).
> 
> NOTE: these things are not required to open a PR and can be done afterwards / while the PR is open.
> 
> \### Description of change
> 
> \## Scope
> \* \*\*Translate\*\*
> \* +193 lines / -52 lines
> 
> \* \*\*Front\*\*
> \* +1072 lines / -71 lines
> 
> \* \*\*Server\*\*
> \* +1278 lines / -38 lines
> 
> \* \*\*Server Tests\*\*
> \* +2315 lines / -37 lines
> 
> \* \*\*Package\*\*
> \* +103 lines / -2 lines
> 
> \## Before
> 
> \<img width="1100" height="749" alt="image" src="https://github.com/user-attachments/assets/57742051-84b4-4fcd-8447-b6b0069f67e3" /\>\<img width="1093" height="705" alt="image" src="https://github.com/user-attachments/assets/24718a52-4320-4da8-baa4-35a70f155418" /\>
> 
> 
> 
> \## After
> 
> \- Added new fields required for Tuya cloud connection.
> \- Client Secret is now masked in UI.
> \- Added clearer setup guidance for users.
> \- Added local-mode workflow and related user information.
> \- Added specific logs when Tuya is not configured.
> 
> \<img width="894" height="920" alt="image" src="https://github.com/user-attachments/assets/80eb8ec5-5a4e-4acd-b8d1-50c9fc37e331" /\>
> 
> \- Added connection lifecycle logs.
> 
> \<img width="896" height="920" alt="image" src="https://github.com/user-attachments/assets/e5d637c9-1305-420c-8955-d65257187db1" /\>
> 
> \- Added explicit error logs for invalid Client ID / Client Secret cases.
> 
> \<img width="904" height="306" alt="image" src="https://github.com/user-attachments/assets/4835591a-060e-4263-af46-bf2fe42d359b" /\>
> \<img width="897" height="302" alt="image" src="https://github.com/user-attachments/assets/99bd8154-e6e7-4472-bd02-609c0e285d9c" /\>
> 
> \- Added a manual cloud disconnect button (with logs) so users can stay disconnected once their devices are configured for local usage.
> 
> \<img width="906" height="937" alt="image" src="https://github.com/user-attachments/assets/e5896c92-73c8-4354-a143-7a51639584e0" /\>
> 
> \- Added cloud scan to discover devices linked to Tuya/Smart Life apps, with loader/status feedback.
> 
> \<img width="901" height="402" alt="image" src="https://github.com/user-attachments/assets/ac79d7c2-1480-408f-b3f1-ffbfd280444b" /\>
> 
> \- Added automatic local scan to discover matching LAN devices and auto-fill local parameters (IP address and protocol version), required for local control.
> 
> \<img width="896" height="370" alt="image" src="https://github.com/user-attachments/assets/ee33c000-d551-4e24-922a-3f4bedd5761e" /\>
> 
> \- Reworked discovered devices list (Tasmota-like ordering): new creatable devices first, then already-created devices requiring updates, then unsupported/new devices, then already-created up-to-date devices.
> \- Added clearer user instructions for cloud-only and local flows.
> \- For cloud usage: one click on \*\*Save\*\* is enough.
> \- For local usage: user guidance from the \*\*IP Address\*\* field explains what to do when auto local scan cannot find the device (different subnet, etc.).
> 
> \<img width="629" height="856" alt="image" src="https://github.com/user-attachments/assets/e49729ed-6389-40d9-a0f3-f560f671bea6" /\>
> 
> \- To switch an existing cloud device to local mode: click the Cloud/Local toggle in the \*\*IP Address\*\* field.
> \- The field is cleared, and a valid local IP must be entered.
> \- \*\*Update\*\* (or \*\*Save\*\* from the Devices tab) remains disabled until local DP validation is successful using \*\*Poll local DP\*\*.
> \- If protocol version is unknown, users can run poll without selecting one (all supported versions are tested, slower). If protocol is known, selecting it first is faster.
> \- If no protocol works, either the IP is wrong or the device uses an unsupported protocol.
> 
> \<img width="308" height="795" alt="image" src="https://github.com/user-attachments/assets/aa4467c4-aad1-42ef-837e-3ffb2b945cf1" /\>
> \<img width="313" height="523" alt="image" src="https://github.com/user-attachments/assets/008603c7-78be-4c60-817c-79dfc57cccb0" /\>
> \<img width="316" height="265" alt="image" src="https://github.com/user-attachments/assets/7cfd08da-70d1-440f-968c-3bbf8f0b0f25" /\>
> \<img width="314" height="280" alt="image" src="https://github.com/user-attachments/assets/7c5780d8-e999-4b9f-aff9-e6d5f69fae0a" /\>
> 
> \- Once \*\*Local poll OK\*\* is returned, users can update/save safely.
> 
> \<img width="318" height="323" alt="image" src="https://github.com/user-attachments/assets/2247e1bc-8954-4820-bc85-51027281a5a5" /\>
> 
> 
> \## Summary by CodeRabbit
> 
> \* \*\*New Features\*\*
> \* Local UDP discovery and TCP local polling with in‑UI poll controls, device details (IDs, keys, IP, protocol), GitHub issue helper, and service status/disconnect endpoints.
> 
> \* \*\*Improvements\*\*
> \* Enhanced cloud vs local setup flow and connection state messaging, auto-reconnect, protocol 3.5 handling, UDP port/scan feedback, IP masking, and local-first write fallback.
> 
> \* \*\*Documentation\*\*
> \* Expanded EN/DE/FR translations and updated setup labels/placeholders.
> 
> \* \*\*Tests\*\*
> \* Extensive new tests for local scan/poll, config, status, device param utilities, and disconnect flows.

Vielen Dank im Voraus.

**EDIT** : Nach einer vollständigen Überprüfung habe ich festgestellt, dass der PR in mehr Elemente aufgeteilt werden sollte. Ich habe ihn daher lieber in Wartestellung versetzt. Ich habe ihn gerade wieder geöffnet. @pierre-gilles, er ist bereit zur Überprüfung.

**EDIT 2** : Pierre-Gilles, um alle Tuya-PRs zu testen, kann ich dir gerne meinen Account teilen, falls du das möchtest.

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [27. Februar 2026 um 15:38 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/42 "2026-02-27T15:38:05Z")

</div>

Sobald die vorherige gültig ist, werde ich die folgenden PRs aktualisieren:

- Hinzufügen des Protokolls 3.5, das für neue Geräte erforderlich ist. Ein großer Vorteil gegenüber HA: Dies wird fester Bestandteil von Gladys sein, während HA eine externe Integration über HACS erfordert:

> <https://github.com/GladysAssistant/Gladys/pull/2438>
>
> \### Pull Request check-list
> 
> To ensure your Pull Request can be accepted as fa…st as possible, make sure to review and check all of these items:
> 
> \- \[x\] If your changes affect the code, did you write the tests?
> \- \[x\] Are tests passing? (\`npm test\` on both front/server)
> \- \[x\] Is the linter passing? (\`npm run eslint\` on both front/server)
> \- \[x\] Did you run prettier? (\`npm run prettier\` on both front/server)
> \- \[x\] If you are adding a new feature/service, did you run the integration comparator? (\`npm run compare-translations\` on front)
> \- \[x\] Did you test this pull request in real life? With real devices? If this development is a big feature or a new service, we recommend that you provide a Docker image to the community (\[forum\](https://community.gladysassistant.com/)) for testing before merging.
> \- \[\] If your changes modify the API (REST or Node.js), did you modify the API documentation? (Documentation is based on comments in code)
> \- \[\] If you are adding a new features/services which needs explanation, did you modify the user documentation? See \[the GitHub repo\](https://github.com/GladysAssistant/v4-website) and the \[website\](https://gladysassistant.com).
> \- \[\] Did you add fake requests data for the demo mode (\`front/src/config/demo.js\`) so that the demo website is working without a backend? (if needed) See \[https://demo.gladysassistant.com\](https://demo.gladysassistant.com).
> 
> NOTE: these things are not required to open a PR and can be done afterwards / while the PR is open.
> 
> \### Description of change
> 
> \## Summary
> 
> Adds support for \*\*Tuya local protocols 3.4 and 3.5\*\* to the Tuya integration. Stacks on top of \[PR #2434\](https://github.com/GladysAssistant/Gladys/pull/2434) which is now merged into \`master\`.
> 
> The official \`tuyapi@7.2.0\` only supports protocols 3.1 and 3.3 — it has \*\*no cipher or parser\*\* for 3.4 (the "3.4" dropdown option was pointing to a non-functional path) and obviously none for 3.5. A second client (\`@demirdeniz/tuyapi-newgen\`) is added and used \*\*only\*\* when \`protocolVersion === '3.4'\` or \`'3.5'\`. Protocols 3.1 and 3.3 keep using the original \`tuyapi\` client and are not impacted.
> 
> \## Details
> 
> \*\*Protocol routing\*\*
> \- \`tuya.localPoll.js\` and \`tuya.setValue.js\` pick the local API class based on an \`isNewGenProtocol\` flag (\`isProtocol34 || isProtocol35\`).
> \- For 3.5 only: \`keepAlive\` is disabled and \`socketTimeout\` is floored at 5 s because the 3.5 handshake takes longer than the others.
> \- For 3.5 only: a small fallback chain (\`{schema:true}\` → \`{schema:true, dps:\[1\]}\` → \`{}\`) because some firmwares reject a bare schema get on first contact. 3.4 uses a single schema attempt.
> \- Protocol 3.4 reuses the existing \`tuyapi-newgen\` \`\_decrypt34\` cipher and \`0x6699/0x9966\` UDP framing.
> 
> \*\*UDP local scan\*\*
> \- \`tuya.localScan.js\` now parses incoming packets with three \`MessageParser\` instances in order \`\[3.1, 3.4, 3.5\]\` and keeps the first one that succeeds.
> \- \`localScan(input)\` accepts either a number or an object so existing callers passing \`{ timeoutSeconds: N }\` still work.
> \- \`timeoutSeconds\` is sanitized into \`\[1, 30\] s\`.
> 
> \*\*Robustness improvements (touched along the way)\*\*
> \- \`localPoll.timeoutMs\` is sanitized into \`\[500, 30000\] ms\` to prevent immediate timeouts or pathologically long hangs.
> \- \`setValue\` now throws \`BadParameters\` when the external\_id has no command instead of silently falling back to the cloud.
> 
> \*\*Front (\`TuyaDeviceBox.jsx\`)\*\*
> \- Protocol 3.5 is enabled in the dropdown (3.4 was already listed but non-functional before this PR).
> \- \`pollLocal()\` adds 3.5 to the fallback list and captures \`currentDevice\` once at the start of the async loop to avoid stale \`this.state.device\` reads across protocol attempts.
> \- Obsolete i18n keys \`protocol35OptionUnsupported\` and \`protocolVersionRequired\` removed (en/fr/de).
> 
> \*\*Dependency\*\*
> \- \`@demirdeniz/tuyapi-newgen\` is \*\*pinned\*\* to exact version \`8.1.5\` (no caret), since it is a single-maintainer scoped fork. License MIT, integrity hash present in lockfile.
> 
> \## Scope
> 
> Computed against \`master\` (PR #2434 already merged).
> 
> \- \*\*server (prod)\*\* : ~150 lines (3 files: \`tuya.localPoll.js\`, \`tuya.localScan.js\`, \`tuya.setValue.js\`)
> \- \*\*server (tests)\*\* : ~325 lines (3 files: \`tuya.localPoll.test.js\`, \`tuya.localScan.test.js\`, \`tuya.setValue.test.js\`)
> \- \*\*front (prod)\*\* : ~29 lines (\`TuyaDeviceBox.jsx\`)
> \- \*\*translations\*\* : ~18 lines (\`en.json\`, \`fr.json\`, \`de.json\`)
> \- \*\*packages / lockfiles\*\* : ~75 lines (\`package.json\`, \`package-lock.json\`)
> 
> Total : ~597 lines across 12 files.
> 
> \## Validation
> 
> \- \`npm run test-service --service=tuya\` → \*\*159 passing, 0 failing\*\*
> \- \`eslint server/services/tuya server/test/services/tuya\` → clean
> \- \`eslint front/src/routes/integration/all/tuya\` → clean
> 
> 
> 
> 
> \## Summary by CodeRabbit
> 
> \* \*\*New Features\*\*
> \* Local device polling with multi-protocol fallback, UDP local discovery, connection status, manual disconnect, reconnect logic, and cloud/local mode controls.
> 
> \* \*\*UI\*\*
> \* Richer Tuya setup UI with new credential fields and connection states; device view shows masked IP, product/device identifiers, protocol/IP controls, local-poll actions, GitHub issue shortcut, and improved discovery ordering/status.
> 
> \* \*\*Localization\*\*
> \* Expanded DE/EN/FR translations for setup, discovery, devices, statuses, errors, and guidance.
> 
> \* \*\*Tests\*\*
> \* Extensive new and updated tests for local poll/scan, discovery, config, status, setValue, and lifecycle.

- Einrichtung der Mapping-Basis für Cloud- vs. lokale Geräte. Ich habe die Smart Steckdosen für diese Basis verwendet, die das Hinzufügen zukünftiger Geräte/Funktionen vereinfacht:

> <https://github.com/GladysAssistant/Gladys/pull/2466>
>
> \### Pull Request check-list
> 
> To ensure your Pull Request can be accepted as fa…st as possible, make sure to review and check all of these items:
> 
> \- \[x\] If your changes affect the code, did you write the tests?
> \- \[x\] Are tests passing? (\`npm test\` on both front/server)
> \- \[x\] Is the linter passing? (\`npm run eslint\` on both front/server)
> \- \[x\] Did you run prettier? (\`npm run prettier\` on both front/server)
> \- \[x\] If you are adding a new feature/service, did you run the integration comparator? (\`npm run compare-translations\` on front)
> \- \[x\] Did you test this pull request in real life? With real devices? If this development is a big feature or a new service, we recommend that you provide a Docker image to the community (\[forum\](https://community.gladysassistant.com/)) for testing before merging.
> \- \[\] If your changes modify the API (REST or Node.js), did you modify the API documentation? (Documentation is based on comments in code)
> \- \[\] If you are adding a new features/services which needs explanation, did you modify the user documentation? See \[the GitHub repo\](https://github.com/GladysAssistant/v4-website) and the \[website\](https://gladysassistant.com).
> \- \[\] Did you add fake requests data for the demo mode (\`front/src/config/demo.js\`) so that the demo website is working without a backend? (if needed) See \[https://demo.gladysassistant.com\](https://demo.gladysassistant.com).
> 
> NOTE: these things are not required to open a PR and can be done afterwards / while the PR is open.
> 
> \### Description of change
> 
> This PR introduces a mapping core for Tuya devices to make local/cloud handling more consistent and future device integrations easier.
> 
> \## Summary
> 
> Brings PR3 in sync with master + PR1/PR2 review fixes (PR1 was squash-merged
> in \`bf8bbff1\`; PR2 carries the master merge and its own review-feedback
> batch). PR3's own contribution — Tuya mapping core, \`convertDevice\` /
> \`convertFeature\` refactor, \`tuya.deviceMapping\` / \`tuya.localMapping\`,
> poll hardening, and Smart Socket reference implementation — is preserved
> on top of the aligned base.
> 
> \## Details
> 
> Merge of \`tuya-local-protocol-3.5\` (PR2) into PR3 brings forward:
> 
> \- master alignment via PR2's merge commit (\`0c457670\`): Gladys 4.73.0,
> Matter.js 0.16.11, Airplay sender rewrite, energy/i18n updates
> \- PR1 review fixes baked-in via the master squash (single
> \`/configuration\` endpoint, reconnect prototype refactor moved to
> \`lib/tuya.reconnect.js\` with proper wiring in \`lib/index.js\`,
> \`stopReconnect()\` call in \`lib/tuya.disconnect.js\`, \`addSelector\`
> in \`convertDevice\` / \`convertFeature\`, \`MarkupText\` invalid-paragraph
> fix in \`SetupTab.jsx\`, \`discoverDevices\` JSDoc fix, \`bridge minimal\`
> \`services/tuya/index.js\`)
> \- PR2 review feedback (\`6b760790\`): exact \`@demirdeniz/tuyapi-newgen\`
> pin to \`8.1.5\`, \`socketTimeout\`/\`keepAlive\` documented for protocol
> 3.5, DPS fallback chain documented, dropped redundant \`localKey\`
> guard in \`updateDiscoveredDeviceAfterLocalPoll\`, dropped redundant
> double-disconnect in \`localPoll\` outer catch
> \- PR2 protocol 3.4 newgen routing (\`2679dba6\`): \`localScan\` ordered
> parsers \`\[3.1, 3.4, 3.5\]\`, \`localPoll\` / \`setValue\` route 3.4 via
> \`isNewGenProtocol\`
> 
> Conflict resolutions (manual, then validated via tests + lint):
> 
> \- \`tuya.localPoll.js\`: PR2 base (proto 3.4 routing + comments) +
> PR3 add-on reposed (\`logDps\`, \`addFallbackBinaryFeature\`, \`dps\` passing)
> \- \`tuya.poll.js\`: PR3 refactor kept; obsolete PR2 baseline snippet dropped
> \- \`tuya.convertFeature.js\`: PR3 imports + PR1 \`addSelector\` combined
> \- \`SetupTab.jsx\` and \`i18n/fr.json\`: PR3 pre-PR1-fix workarounds dropped
> \- \`tuya.poll.test.js\`: PR3 tests kept (cover PR2 baseline by equivalence)
> \- \`tuya.localScan.test.js\`: PR2 added test
> \`should instantiate parsers for protocols 3.1, 3.4 and 3.5\` kept
> \- \`tuya.convertFeature.test.js\`: selector expectation harmonised to
> the slugified form (consistent with the rest of the file)
> 
> Validation:
> 
> \- \`npm run test-service --service=tuya\`: \*\*209 passing\*\*
> \- \`npx nyc --include='services/tuya/\*\*'\`: \*\*99.59% lines / 99.60% stmts /
> 99.39% functions / 88.94% branches\*\*
> \- \`eslint server/services/tuya server/test/services/tuya\`: clean
> \- \`eslint front/src/routes/integration/all/tuya\`: clean
> 
> \## Scope
> 
> Scope vs the immediate parent branch in the stack
> (\`tuya-local-protocol-3.5\`, PR #2438):
> 
> | Area | Insertions | Deletions |
> |---|---:|---:|
> | \`server/services/tuya\` (prod) | +987 | -178 |
> | \`server/test/services/tuya\` (tests) | +1313 | -26 |
> | \`front/src/routes/integration/all/tuya\` (prod) | +13 | -8 |
> | \*\*Total\*\* | \*\*+2313\*\* | \*\*-212\*\* |
> 
> No translation, package or lockfile changes (the \`localModeLimitInfo\`
> restoration in commit \`865e2cc3\` was a fix for a key dropped during the
> merge of PR2, with zero net delta vs PR2).
> 
> 27 files changed, 0 leak outside the Tuya scope.
> 
> 
> 
> 
> 
> \## Summary by CodeRabbit
> 
> \* \*\*New Features\*\*
> \* Local UDP discovery and local polling for Tuya devices; cloud/local mode toggle, manual cloud disconnect, and explicit Save → Connect flow.
> \* Real-time connection status and disconnect controls with improved reconnect handling.
> 
> \* \*\*Improvements\*\*
> \* Updated setup copy and field labels (Client ID/Client Secret, App UID, App Username) with validation and user-friendly error messages.
> \* Device panel shows identifiers, IP/protocol, product info, local-poll controls/progress, success/error indicators and clearer "unknown" value labels.

Sie sind ebenfalls bereit und warten nur auf die erste ^^

Danach habe ich eine PR für die Integration der automatischen Erstellung von GitHub-Issues getrennt.

> <https://github.com/GladysAssistant/Gladys/pull/2467>
>
> \### Pull Request check-list
> 
> To ensure your Pull Request can be accepted as fa…st as possible, make sure to review and check all of these items:
> 
> \- \[\] If your changes affect the code, did you write the tests?
> \- \[\] Are tests passing? (\`npm test\` on both front/server)
> \- \[\] Is the linter passing? (\`npm run eslint\` on both front/server)
> \- \[\] Did you run prettier? (\`npm run prettier\` on both front/server)
> \- \[\] If you are adding a new feature/service, did you run the integration comparator? (\`npm run compare-translations\` on front)
> \- \[\] Did you test this pull request in real life? With real devices? If this development is a big feature or a new service, we recommend that you provide a Docker image to the community (\[forum\](https://community.gladysassistant.com/)) for testing before merging.
> \- \[\] If your changes modify the API (REST or Node.js), did you modify the API documentation? (Documentation is based on comments in code)
> \- \[\] If you are adding a new features/services which needs explanation, did you modify the user documentation? See \[the GitHub repo\](https://github.com/GladysAssistant/v4-website) and the \[website\](https://gladysassistant.com).
> \- \[\] Did you add fake requests data for the demo mode (\`front/src/config/demo.js\`) so that the demo website is working without a backend? (if needed) See \[https://demo.gladysassistant.com\](https://demo.gladysassistant.com).
> 
> NOTE: these things are not required to open a PR and can be done afterwards / while the PR is open.
> 
> \### Description of change
> 
> \## Summary
> \- Add the GitHub issue workflow for unsupported Tuya devices and partially supported functions.
> \- Let users generate a clean device report directly from the Tuya UI, with sensitive values masked.
> \- Improve the device/discovery UI around unsupported-device diagnostics and reporting.
> 
> \## Details
> \- Add GitHub issue generation from the Tuya device UI for:
> - unsupported devices
> - partially supported devices/functions
> \- Add issue search and duplicate detection before opening a new issue.
> \- Add payload generation helpers so device data can be:
> - inserted directly in a GitHub issue URL when short enough
> - copied to clipboard when too long
> \- Mask sensitive values in generated reports:
> - local key
> - local/cloud IP
> \- Improve device-box UX around:
> - unsupported-function display
> - partial support counts
> - issue-open state / duplicate issue state
> - popup opening behavior after async checks
> \- Keep this branch focused on the reporting workflow on top of the baseline/local/mapping stack.
> 
> \## Scope
> 
> Scope vs the immediate parent branch in the stack
> (\`tuya-local-mapping-core\`, PR #2466):
> 
> | Area | Insertions | Deletions |
> |---|---:|---:|
> | \`server/services/tuya\` (prod) | +187 | -2 |
> | \`server/test/services/tuya\` (tests) | +469 | -1 |
> | \`front/src/routes/integration/all/tuya\` (prod) | +1788 | -399 |
> | \`front/src/config/i18n\` (translations) | +45 | -3 |
> | \*\*Total\*\* | \*\*+2489\*\* | \*\*-405\*\* |
> 
> No package or lockfile changes. The translations delta covers the new
> i18n keys for the GitHub issue assistant flow (\`unmanagedModelButton\`,
> \`partiallyManagedModelButton\`, popup labels) and the cross-stack
> \`localModeLimitInfo\` disclaimer surfaced through the PR3 merge.
> 
> 20 files changed, 0 leak outside the Tuya scope.
> 
> 
> \## Notes
> \- This PR is intended as a stacked step after mapping-core work.
> \- If compared directly against \`master\`, GitHub may show additional changes from previous stacked PRs.
> 
> 
> 
> 
> \## Summary by CodeRabbit
> 
> \* \*\*New Features\*\*
> \* Local network scan & polling for Tuya devices, hybrid local/cloud control, manual cloud disconnect and live connection status.
> 
> \* \*\*Improvements\*\*
> \* GitHub issue helper and partial-support indicators for devices.
> \* More device metadata shown (IDs, keys, protocol, IP), protocol selection, IP mode toggle, secret visibility and richer validation/status messages.
> \* Improved discovery ordering and scan feedback (UDP/cloud) with clearer setup flows.
> 
> \* \*\*Localization\*\*
> \* Extensive EN/FR/DE translations added for Tuya flows and messages.

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [2. März 2026 um 16:13 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/43 "2026-03-02T16:13:52Z")

</div>

Vielen Dank für die PRs, ich halte dich auf dem Laufenden, sobald ich sie mir angesehen habe!

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [3. März 2026 um 07:15 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/44 "2026-03-03T07:15:00Z")

</div>

@Papashultz und @GBoulvin, ich habe gerade einen neuen Build mit demselben Testbild gestartet. Ich wäre sehr an euren neuen Tests und eurem Feedback interessiert.

Für Info @GBoulvin, ich habe die Unterstützung für diese Issues hinzugefügt:

> <https://github.com/GladysAssistant/Gladys/issues/2460>
>
> \`\`\`json
> {
> "id": "be2e78e9-3b66-413a-966e-cd8c90c5947a",
> "name": "Chauffage c…abinet",
> "selector": "tuya-bf2be3c32ea4d8f561ujmu",
> "model": "LSC Power Plug FR incl. Power meter",
> "external\_id": "tuya:bf2be3c32ea4d8f561ujmu",
> "service\_id": "966ff9b2-7d5d-4c88-aa54-80c406d5743d",
> "product\_id": "b61eihfqeaexn54g",
> "product\_key": null,
> "online": true,
> "protocol\_version": "3.5",
> "local\_override": true,
> "specifications": {
> "functions": \[
> {
> "code": "switch\_1",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Switch 1",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "countdown\_1",
> "lang\_config": {
> "unit": "Second"
> },
> "name": "Countdown 1",
> "type": "Integer",
> "values": "{\\"unit\\":\\"s\\",\\"min\\":0,\\"max\\":86400,\\"scale\\":0,\\"step\\":1}"
> },
> {
> "code": "relay\_status",
> "lang\_config": {
> "last": "Remember last status",
> "power\_off": "OFF",
> "power\_on": ""
> },
> "name": "Relay Status",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"power\_off\\",\\"power\_on\\",\\"last\\"\]}"
> },
> {
> "code": "overcharge\_switch",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Overcharge Switch",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "light\_mode",
> "lang\_config": {
> "none": "OFF",
> "pos": "Indicate switch location",
> "relay": "Indicate switch on/off"
> },
> "name": "Light Mode",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"relay\\",\\"pos\\",\\"none\\"\]}"
> },
> {
> "code": "child\_lock",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Child Lock",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "cycle\_time",
> "lang\_config": {
> "unit": ""
> },
> "name": "Cycle Time",
> "type": "String",
> "values": "{}"
> },
> {
> "code": "random\_time",
> "lang\_config": {
> "unit": ""
> },
> "name": "Random Time",
> "type": "String",
> "values": "{}"
> },
> {
> "code": "switch\_inching",
> "lang\_config": {
> "unit": ""
> },
> "name": "Switch Inching",
> "type": "String",
> "values": "{}"
> }
> \],
> "status": \[
> {
> "code": "switch\_1",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Switch 1",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "countdown\_1",
> "lang\_config": {
> "unit": "Second"
> },
> "name": "Countdown 1",
> "type": "Integer",
> "values": "{\\"unit\\":\\"s\\",\\"min\\":0,\\"max\\":86400,\\"scale\\":0,\\"step\\":1}"
> },
> {
> "code": "add\_ele",
> "lang\_config": {
> "unit": ""
> },
> "name": "Electricity",
> "type": "Integer",
> "values": "{\\"min\\":0,\\"max\\":50000,\\"scale\\":3,\\"step\\":100}"
> },
> {
> "code": "cur\_current",
> "lang\_config": {
> "unit": "Milliampere"
> },
> "name": "Current",
> "type": "Integer",
> "values": "{\\"unit\\":\\"mA\\",\\"min\\":0,\\"max\\":30000,\\"scale\\":0,\\"step\\":1}"
> },
> {
> "code": "cur\_power",
> "lang\_config": {
> "unit": "W"
> },
> "name": "Power",
> "type": "Integer",
> "values": "{\\"unit\\":\\"W\\",\\"min\\":0,\\"max\\":80000,\\"scale\\":1,\\"step\\":1}"
> },
> {
> "code": "cur\_voltage",
> "lang\_config": {
> "unit": "Volt"
> },
> "name": "Voltage",
> "type": "Integer",
> "values": "{\\"unit\\":\\"V\\",\\"min\\":0,\\"max\\":5000,\\"scale\\":1,\\"step\\":1}"
> },
> {
> "code": "voltage\_coe",
> "lang\_config": {
> "unit": ""
> },
> "name": "Voltage Coe",
> "type": "Integer",
> "values": "{\\"min\\":0,\\"max\\":1000000,\\"scale\\":0,\\"step\\":1}"
> },
> {
> "code": "electric\_coe",
> "lang\_config": {
> "unit": ""
> },
> "name": "Electric Coe",
> "type": "Integer",
> "values": "{\\"min\\":0,\\"max\\":1000000,\\"scale\\":0,\\"step\\":1}"
> },
> {
> "code": "power\_coe",
> "lang\_config": {
> "unit": ""
> },
> "name": "Power Coe",
> "type": "Integer",
> "values": "{\\"min\\":0,\\"max\\":1000000,\\"scale\\":0,\\"step\\":1}"
> },
> {
> "code": "electricity\_coe",
> "lang\_config": {
> "unit": ""
> },
> "name": "Electricity Coe",
> "type": "Integer",
> "values": "{\\"min\\":0,\\"max\\":1000000,\\"scale\\":0,\\"step\\":1}"
> },
> {
> "code": "fault",
> "lang\_config": {
> "ls\_cr": "loss of flow fault",
> "ls\_pow": "loss of power fault",
> "ls\_vol": "loss of voltage fault",
> "ov\_cr": "overcurrent fault",
> "ov\_pwr": "over power fault",
> "ov\_vol": "overvoltage fault"
> },
> "name": "Fault",
> "type": "Bitmap",
> "values": "{\\"label\\":\[\\"ov\_cr\\",\\"ov\_vol\\",\\"ov\_pwr\\",\\"ls\_cr\\",\\"ls\_vol\\",\\"ls\_pow\\"\]}"
> },
> {
> "code": "relay\_status",
> "lang\_config": {
> "last": "Remember last status",
> "power\_off": "OFF",
> "power\_on": ""
> },
> "name": "Relay Status",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"power\_off\\",\\"power\_on\\",\\"last\\"\]}"
> },
> {
> "code": "overcharge\_switch",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Overcharge Switch",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "light\_mode",
> "lang\_config": {
> "none": "OFF",
> "pos": "Indicate switch location",
> "relay": "Indicate switch on/off"
> },
> "name": "Light Mode",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"relay\\",\\"pos\\",\\"none\\"\]}"
> },
> {
> "code": "child\_lock",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Child Lock",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "cycle\_time",
> "lang\_config": {
> "unit": ""
> },
> "name": "Cycle Time",
> "type": "String",
> "values": "{}"
> },
> {
> "code": "random\_time",
> "lang\_config": {
> "unit": ""
> },
> "name": "Random Time",
> "type": "String",
> "values": "{}"
> },
> {
> "code": "switch\_inching",
> "lang\_config": {
> "unit": ""
> },
> "name": "Switch Inching",
> "type": "String",
> "values": "{}"
> }
> \]
> },
> "properties": {
> "properties": \[
> {
> "code": "switch\_1",
> "custom\_name": "",
> "dp\_id": 1,
> "time": 1771777823927,
> "type": "bool",
> "value": false
> },
> {
> "code": "countdown\_1",
> "custom\_name": "",
> "dp\_id": 9,
> "time": 1771777824455,
> "type": "value",
> "value": 0
> },
> {
> "code": "add\_ele",
> "custom\_name": "",
> "dp\_id": 17,
> "time": 1771779631214,
> "type": "value",
> "value": 1
> },
> {
> "code": "cur\_current",
> "custom\_name": "",
> "dp\_id": 18,
> "time": 1771777824455,
> "type": "value",
> "value": 0
> },
> {
> "code": "cur\_power",
> "custom\_name": "",
> "dp\_id": 19,
> "time": 1771777824455,
> "type": "value",
> "value": 0
> },
> {
> "code": "cur\_voltage",
> "custom\_name": "",
> "dp\_id": 20,
> "time": 1771949581664,
> "type": "value",
> "value": 2340
> },
> {
> "code": "test\_bit",
> "custom\_name": "",
> "dp\_id": 21,
> "time": 1771777824455,
> "type": "value",
> "value": 1
> },
> {
> "code": "voltage\_coe",
> "custom\_name": "",
> "dp\_id": 22,
> "time": 1771777824455,
> "type": "value",
> "value": 566
> },
> {
> "code": "electric\_coe",
> "custom\_name": "",
> "dp\_id": 23,
> "time": 1771777824455,
> "type": "value",
> "value": 26471
> },
> {
> "code": "power\_coe",
> "custom\_name": "",
> "dp\_id": 24,
> "time": 1771777824455,
> "type": "value",
> "value": 14621
> },
> {
> "code": "electricity\_coe",
> "custom\_name": "",
> "dp\_id": 25,
> "time": 1771777824455,
> "type": "value",
> "value": 2840
> },
> {
> "code": "fault",
> "custom\_name": "",
> "dp\_id": 26,
> "time": 1771777824455,
> "type": "bitmap",
> "value": 0
> },
> {
> "code": "relay\_status",
> "custom\_name": "",
> "dp\_id": 38,
> "time": 1771777824455,
> "type": "enum",
> "value": "memory"
> },
> {
> "code": "overcharge\_switch",
> "custom\_name": "",
> "dp\_id": 39,
> "time": 1771777824455,
> "type": "bool",
> "value": false
> },
> {
> "code": "light\_mode",
> "custom\_name": "",
> "dp\_id": 40,
> "time": 1771777824455,
> "type": "enum",
> "value": "relay"
> },
> {
> "code": "child\_lock",
> "custom\_name": "",
> "dp\_id": 41,
> "time": 1771777824455,
> "type": "bool",
> "value": false
> },
> {
> "code": "cycle\_time",
> "custom\_name": "",
> "dp\_id": 42,
> "time": 1771704520013,
> "type": "string",
> "value": ""
> },
> {
> "code": "random\_time",
> "custom\_name": "",
> "dp\_id": 43,
> "time": 1771704520007,
> "type": "string",
> "value": ""
> },
> {
> "code": "switch\_inching",
> "custom\_name": "",
> "dp\_id": 44,
> "time": 1771777824455,
> "type": "string",
> "value": ""
> }
> \]
> },
> "thing\_model": {
> "modelId": "e1n2e11c",
> "services": \[
> {
> "actions": \[\],
> "code": "",
> "description": "",
> "events": \[\],
> "name": "",
> "properties": \[
> {
> "abilityId": 1,
> "accessMode": "rw",
> "code": "switch\_1",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_power2",
> "attribute": "641"
> },
> "name": "开关1",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 9,
> "accessMode": "rw",
> "code": "countdown\_1",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_time2",
> "attribute": "736"
> },
> "name": "倒计时1",
> "typeSpec": {
> "type": "value",
> "max": 86400,
> "min": 0,
> "scale": 0,
> "step": 1,
> "unit": "s"
> }
> },
> {
> "abilityId": 17,
> "accessMode": "ro",
> "code": "add\_ele",
> "description": "",
> "extensions": {
> "attribute": "736",
> "trigger": "direct"
> },
> "name": "增加电量",
> "typeSpec": {
> "type": "value",
> "max": 50000,
> "min": 0,
> "scale": 3,
> "step": 100
> }
> },
> {
> "abilityId": 18,
> "accessMode": "ro",
> "code": "cur\_current",
> "description": "",
> "extensions": {
> "attribute": "704"
> },
> "name": "电流",
> "typeSpec": {
> "type": "value",
> "max": 30000,
> "min": 0,
> "scale": 0,
> "step": 1,
> "unit": "mA"
> }
> },
> {
> "abilityId": 19,
> "accessMode": "ro",
> "code": "cur\_power",
> "description": "",
> "extensions": {
> "attribute": "704"
> },
> "name": "功率",
> "typeSpec": {
> "type": "value",
> "max": 80000,
> "min": 0,
> "scale": 1,
> "step": 1,
> "unit": "W"
> }
> },
> {
> "abilityId": 20,
> "accessMode": "ro",
> "code": "cur\_voltage",
> "description": "",
> "extensions": {
> "attribute": "704"
> },
> "name": "电压",
> "typeSpec": {
> "type": "value",
> "max": 5000,
> "min": 0,
> "scale": 1,
> "step": 1,
> "unit": "V"
> }
> },
> {
> "abilityId": 21,
> "accessMode": "ro",
> "code": "test\_bit",
> "description": "",
> "extensions": {
> "attribute": "736"
> },
> "name": "产测结果位",
> "typeSpec": {
> "type": "value",
> "max": 5,
> "min": 0,
> "scale": 0,
> "step": 1
> }
> },
> {
> "abilityId": 22,
> "accessMode": "ro",
> "code": "voltage\_coe",
> "description": "",
> "extensions": {
> "attribute": "736"
> },
> "name": "电压校准系数",
> "typeSpec": {
> "type": "value",
> "max": 1000000,
> "min": 0,
> "scale": 0,
> "step": 1
> }
> },
> {
> "abilityId": 23,
> "accessMode": "ro",
> "code": "electric\_coe",
> "description": "",
> "extensions": {
> "attribute": "736"
> },
> "name": "电流校准系数",
> "typeSpec": {
> "type": "value",
> "max": 1000000,
> "min": 0,
> "scale": 0,
> "step": 1
> }
> },
> {
> "abilityId": 24,
> "accessMode": "ro",
> "code": "power\_coe",
> "description": "",
> "extensions": {
> "attribute": "736"
> },
> "name": "功率校准系数",
> "typeSpec": {
> "type": "value",
> "max": 1000000,
> "min": 0,
> "scale": 0,
> "step": 1
> }
> },
> {
> "abilityId": 25,
> "accessMode": "ro",
> "code": "electricity\_coe",
> "description": "",
> "extensions": {
> "attribute": "736"
> },
> "name": "电量校准系数",
> "typeSpec": {
> "type": "value",
> "max": 1000000,
> "min": 0,
> "scale": 0,
> "step": 1
> }
> },
> {
> "abilityId": 26,
> "accessMode": "ro",
> "code": "fault",
> "description": "",
> "extensions": {
> "attribute": "640"
> },
> "name": "故障告警",
> "typeSpec": {
> "type": "bitmap",
> "label": \[
> "ov\_cr",
> "ov\_vol",
> "ov\_pwr",
> "ls\_cr",
> "ls\_vol",
> "ls\_pow"
> \],
> "maxlen": 6
> }
> },
> {
> "abilityId": 38,
> "accessMode": "rw",
> "code": "relay\_status",
> "description": "",
> "extensions": {
> "iconName": "icon-zhuangtai",
> "attribute": "736"
> },
> "name": "上电状态设置",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "off",
> "on",
> "memory"
> \]
> }
> },
> {
> "abilityId": 39,
> "accessMode": "rw",
> "code": "overcharge\_switch",
> "description": "",
> "extensions": {
> "iconName": "",
> "attribute": "128"
> },
> "name": "过充保护",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 40,
> "accessMode": "rw",
> "code": "light\_mode",
> "description": "",
> "extensions": {
> "iconName": "tcl\_function\_light",
> "attribute": "224"
> },
> "name": "指示灯状态设置",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "relay",
> "pos",
> "none",
> "on"
> \]
> }
> },
> {
> "abilityId": 41,
> "accessMode": "rw",
> "code": "child\_lock",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_power2",
> "attribute": "128"
> },
> "name": "童锁开关",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 42,
> "accessMode": "rw",
> "code": "cycle\_time",
> "description": "涂鸦协议",
> "extensions": {
> "iconName": "icon-dp\_time3",
> "attribute": "224"
> },
> "name": "循环定时",
> "typeSpec": {
> "type": "string",
> "maxlen": 255
> }
> },
> {
> "abilityId": 43,
> "accessMode": "rw",
> "code": "random\_time",
> "description": "涂鸦协议",
> "extensions": {
> "iconName": "icon-dp\_time2",
> "attribute": "224"
> },
> "name": "随机定时",
> "typeSpec": {
> "type": "string",
> "maxlen": 255
> }
> },
> {
> "abilityId": 44,
> "accessMode": "rw",
> "code": "switch\_inching",
> "description": "涂鸦协议",
> "extensions": {
> "iconName": "",
> "attribute": "224"
> },
> "name": "点动开关",
> "typeSpec": {
> "type": "string",
> "maxlen": 255
> }
> }
> \]
> }
> \]
> },
> "thing\_model\_raw": "{\\"modelId\\":\\"e1n2e11c\\",\\"services\\":\[{\\"actions\\":\[\],\\"code\\":\\"\\",\\"description\\":\\"\\",\\"events\\":\[\],\\"name\\":\\"\\",\\"properties\\":\[{\\"abilityId\\":1,\\"accessMode\\":\\"rw\\",\\"code\\":\\"switch\_1\\",\\"description\\":\\"\\",\\"extensions\\":{\\"iconName\\":\\"icon-dp\_power2\\",\\"attribute\\":\\"641\\"},\\"name\\":\\"开关1\\",\\"typeSpec\\":{\\"type\\":\\"bool\\"}},{\\"abilityId\\":9,\\"accessMode\\":\\"rw\\",\\"code\\":\\"countdown\_1\\",\\"description\\":\\"\\",\\"extensions\\":{\\"iconName\\":\\"icon-dp\_time2\\",\\"attribute\\":\\"736\\"},\\"name\\":\\"倒计时1\\",\\"typeSpec\\":{\\"type\\":\\"value\\",\\"max\\":86400,\\"min\\":0,\\"scale\\":0,\\"step\\":1,\\"unit\\":\\"s\\"}},{\\"abilityId\\":17,\\"accessMode\\":\\"ro\\",\\"code\\":\\"add\_ele\\",\\"description\\":\\"\\",\\"extensions\\":{\\"attribute\\":\\"736\\",\\"trigger\\":\\"direct\\"},\\"name\\":\\"增加电量\\",\\"typeSpec\\":{\\"type\\":\\"value\\",\\"max\\":50000,\\"min\\":0,\\"scale\\":3,\\"step\\":100}},{\\"abilityId\\":18,\\"accessMode\\":\\"ro\\",\\"code\\":\\"cur\_current\\",\\"description\\":\\"\\",\\"extensions\\":{\\"attribute\\":\\"704\\"},\\"name\\":\\"电流\\",\\"typeSpec\\":{\\"type\\":\\"value\\",\\"max\\":30000,\\"min\\":0,\\"scale\\":0,\\"step\\":1,\\"unit\\":\\"mA\\"}},{\\"abilityId\\":19,\\"accessMode\\":\\"ro\\",\\"code\\":\\"cur\_power\\",\\"description\\":\\"\\",\\"extensions\\":{\\"attribute\\":\\"704\\"},\\"name\\":\\"功率\\",\\"typeSpec\\":{\\"type\\":\\"value\\",\\"max\\":80000,\\"min\\":0,\\"scale\\":1,\\"step\\":1,\\"unit\\":\\"W\\"}},{\\"abilityId\\":20,\\"accessMode\\":\\"ro\\",\\"code\\":\\"cur\_voltage\\",\\"description\\":\\"\\",\\"extensions\\":{\\"attribute\\":\\"704\\"},\\"name\\":\\"电压\\",\\"typeSpec\\":{\\"type\\":\\"value\\",\\"max\\":5000,\\"min\\":0,\\"scale\\":1,\\"step\\":1,\\"unit\\":\\"V\\"}},{\\"abilityId\\":21,\\"accessMode\\":\\"ro\\",\\"code\\":\\"test\_bit\\",\\"description\\":\\"\\",\\"extensions\\":{\\"attribute\\":\\"736\\"},\\"name\\":\\"产测结果位\\",\\"typeSpec\\":{\\"type\\":\\"value\\",\\"max\\":5,\\"min\\":0,\\"scale\\":0,\\"step\\":1}},{\\"abilityId\\":22,\\"accessMode\\":\\"ro\\",\\"code\\":\\"voltage\_coe\\",\\"description\\":\\"\\",\\"extensions\\":{\\"attribute\\":\\"736\\"},\\"name\\":\\"电压校准系数\\",\\"typeSpec\\":{\\"type\\":\\"value\\",\\"max\\":1000000,\\"min\\":0,\\"scale\\":0,\\"step\\":1}},{\\"abilityId\\":23,\\"accessMode\\":\\"ro\\",\\"code\\":\\"electric\_coe\\",\\"description\\":\\"\\",\\"extensions\\":{\\"attribute\\":\\"736\\"},\\"name\\":\\"电流校准系数\\",\\"typeSpec\\":{\\"type\\":\\"value\\",\\"max\\":1000000,\\"min\\":0,\\"scale\\":0,\\"step\\":1}},{\\"abilityId\\":24,\\"accessMode\\":\\"ro\\",\\"code\\":\\"power\_coe\\",\\"description\\":\\"\\",\\"extensions\\":{\\"attribute\\":\\"736\\"},\\"name\\":\\"功率校准系数\\",\\"typeSpec\\":{\\"type\\":\\"value\\",\\"max\\":1000000,\\"min\\":0,\\"scale\\":0,\\"step\\":1}},{\\"abilityId\\":25,\\"accessMode\\":\\"ro\\",\\"code\\":\\"electricity\_coe\\",\\"description\\":\\"\\",\\"extensions\\":{\\"attribute\\":\\"736\\"},\\"name\\":\\"电量校准系数\\",\\"typeSpec\\":{\\"type\\":\\"value\\",\\"max\\":1000000,\\"min\\":0,\\"scale\\":0,\\"step\\":1}},{\\"abilityId\\":26,\\"accessMode\\":\\"ro\\",\\"code\\":\\"fault\\",\\"description\\":\\"\\",\\"extensions\\":{\\"attribute\\":\\"640\\"},\\"name\\":\\"故障告警\\",\\"typeSpec\\":{\\"type\\":\\"bitmap\\",\\"label\\":\[\\"ov\_cr\\",\\"ov\_vol\\",\\"ov\_pwr\\",\\"ls\_cr\\",\\"ls\_vol\\",\\"ls\_pow\\"\],\\"maxlen\\":6}},{\\"abilityId\\":38,\\"accessMode\\":\\"rw\\",\\"code\\":\\"relay\_status\\",\\"description\\":\\"\\",\\"extensions\\":{\\"iconName\\":\\"icon-zhuangtai\\",\\"attribute\\":\\"736\\"},\\"name\\":\\"上电状态设置\\",\\"typeSpec\\":{\\"type\\":\\"enum\\",\\"range\\":\[\\"off\\",\\"on\\",\\"memory\\"\]}},{\\"abilityId\\":39,\\"accessMode\\":\\"rw\\",\\"code\\":\\"overcharge\_switch\\",\\"description\\":\\"\\",\\"extensions\\":{\\"iconName\\":\\"\\",\\"attribute\\":\\"128\\"},\\"name\\":\\"过充保护\\",\\"typeSpec\\":{\\"type\\":\\"bool\\"}},{\\"abilityId\\":40,\\"accessMode\\":\\"rw\\",\\"code\\":\\"light\_mode\\",\\"description\\":\\"\\",\\"extensions\\":{\\"iconName\\":\\"tcl\_function\_light\\",\\"attribute\\":\\"224\\"},\\"name\\":\\"指示灯状态设置\\",\\"typeSpec\\":{\\"type\\":\\"enum\\",\\"range\\":\[\\"relay\\",\\"pos\\",\\"none\\",\\"on\\"\]}},{\\"abilityId\\":41,\\"accessMode\\":\\"rw\\",\\"code\\":\\"child\_lock\\",\\"description\\":\\"\\",\\"extensions\\":{\\"iconName\\":\\"icon-dp\_power2\\",\\"attribute\\":\\"128\\"},\\"name\\":\\"童锁开关\\",\\"typeSpec\\":{\\"type\\":\\"bool\\"}},{\\"abilityId\\":42,\\"accessMode\\":\\"rw\\",\\"code\\":\\"cycle\_time\\",\\"description\\":\\"涂鸦协议\\",\\"extensions\\":{\\"iconName\\":\\"icon-dp\_time3\\",\\"attribute\\":\\"224\\"},\\"name\\":\\"循环定时\\",\\"typeSpec\\":{\\"type\\":\\"string\\",\\"maxlen\\":255}},{\\"abilityId\\":43,\\"accessMode\\":\\"rw\\",\\"code\\":\\"random\_time\\",\\"description\\":\\"涂鸦协议\\",\\"extensions\\":{\\"iconName\\":\\"icon-dp\_time2\\",\\"attribute\\":\\"224\\"},\\"name\\":\\"随机定时\\",\\"typeSpec\\":{\\"type\\":\\"string\\",\\"maxlen\\":255}},{\\"abilityId\\":44,\\"accessMode\\":\\"rw\\",\\"code\\":\\"switch\_inching\\",\\"description\\":\\"涂鸦协议\\",\\"extensions\\":{\\"iconName\\":\\"\\",\\"attribute\\":\\"224\\"},\\"name\\":\\"点动开关\\",\\"typeSpec\\":{\\"type\\":\\"string\\",\\"maxlen\\":255}}\]}\]}",
> "features": \[
> {
> "name": "开关1",
> "external\_id": "tuya:bf2be3c32ea4d8f561ujmu:switch\_1",
> "selector": "tuya-bf2be3c32ea4d8f561ujmu-switch-1",
> "read\_only": false,
> "has\_feedback": false,
> "min": 0,
> "max": 1,
> "category": "switch",
> "type": "binary",
> "keep\_history": true,
> "id": "1bed0439-9362-4739-b4b3-13b8b2f43c66"
> },
> {
> "name": "增加电量",
> "external\_id": "tuya:bf2be3c32ea4d8f561ujmu:add\_ele",
> "selector": "tuya-bf2be3c32ea4d8f561ujmu-add-ele",
> "read\_only": true,
> "has\_feedback": false,
> "min": 0,
> "max": 50000,
> "category": "switch",
> "type": "energy",
> "unit": "kilowatt-hour",
> "keep\_history": true,
> "id": "0c18a42c-6b65-4f57-850b-c2d6243d6481",
> "energy\_parent\_id": "ce42956a-a2e5-495f-a7ab-9a442ab0723f"
> },
> {
> "name": "当前电流",
> "external\_id": "tuya:bf2be3c32ea4d8f561ujmu:cur\_current",
> "selector": "tuya-bf2be3c32ea4d8f561ujmu-cur-current",
> "read\_only": true,
> "has\_feedback": false,
> "min": 0,
> "max": 30000,
> "category": "switch",
> "type": "current",
> "unit": "milliampere",
> "keep\_history": true,
> "id": "b2ccd148-b30a-46df-977d-9c08a72392ec"
> },
> {
> "name": "当前功率",
> "external\_id": "tuya:bf2be3c32ea4d8f561ujmu:cur\_power",
> "selector": "tuya-bf2be3c32ea4d8f561ujmu-cur-power",
> "read\_only": true,
> "has\_feedback": false,
> "min": 0,
> "max": 80000,
> "category": "switch",
> "type": "power",
> "unit": "watt",
> "keep\_history": true,
> "id": "91e773e8-56eb-458e-8cbb-8f51ba432580"
> },
> {
> "name": "当前电压",
> "external\_id": "tuya:bf2be3c32ea4d8f561ujmu:cur\_voltage",
> "selector": "tuya-bf2be3c32ea4d8f561ujmu-cur-voltage",
> "read\_only": true,
> "has\_feedback": false,
> "min": 0,
> "max": 5000,
> "category": "switch",
> "type": "voltage",
> "unit": "volt",
> "keep\_history": true,
> "id": "890d458e-fe70-43d0-a474-e3fa8a50de08"
> }
> \],
> "params": \[
> {
> "name": "DEVICE\_ID",
> "value": "bf2be3c32ea4d8f561ujmu"
> },
> {
> "name": "LOCAL\_KEY",
> "value": "\*\*\*"
> },
> {
> "name": "CLOUD\_IP",
> "value": "91.x.x.x"
> },
> {
> "name": "LOCAL\_OVERRIDE",
> "value": true
> },
> {
> "name": "PRODUCT\_ID",
> "value": "b61eihfqeaexn54g"
> },
> {
> "name": "IP\_ADDRESS",
> "value": "192.x.x.x"
> },
> {
> "name": "PROTOCOL\_VERSION",
> "value": "3.5"
> },
> {
> "name": "LOCAL\_POLL\_DPS",
> "value": "{\\"1\\":false,\\"9\\":0,\\"18\\":0,\\"19\\":0,\\"20\\":2268,\\"21\\":1,\\"22\\":566,\\"23\\":26471,\\"24\\":14621,\\"25\\":2840,\\"26\\":0,\\"38\\":\\"memory\\",\\"39\\":false,\\"40\\":\\"relay\\",\\"41\\":false,\\"44\\":\\"\\"}"
> }
> \],
> "local\_poll": {
> "status": null,
> "error": null,
> "protocol": null,
> "dps": {
> "1": false,
> "9": 0,
> "18": 0,
> "19": 0,
> "20": 2268,
> "21": 1,
> "22": 566,
> "23": 26471,
> "24": 14621,
> "25": 2840,
> "26": 0,
> "38": "memory",
> "39": false,
> "40": "relay",
> "41": false,
> "44": ""
> }
> }
> }
> \`\`\`

[https://github.com/GladysAssistant/Gladys/issues/2464](https://github.com/GladysAssistant/Gladys/issues/2464)  
[https://github.com/GladysAssistant/Gladys/issues/2475](https://github.com/GladysAssistant/Gladys/issues/2475)

Ich hoffe, dass der letzte auch den Pilzfaden von @Papashultz abdeckt.

Und für Info, hier ist, wie die Issues jetzt aussehen:

> <https://github.com/GladysAssistant/Gladys/issues/2479>
>
> \## Summary
> 
> Unsupported or partially supported Tuya device report.
> 
> \- Device nam…e: \`Clim Salle d'attente\`
> \- External ID: \`tuya:bf5638fc7cc3f25e32i45q\`
> \- Product ID: \`f3goccgfj6qino4c\`
> \- Product key: \`keyquxnsj75xc8se\`
> \- Model: \`Air Conditioner\`
> \- Category: \`kt\`
> \- Online: \`true\`
> \- Local override: \`true\`
> \- Local poll status: \`Success\`
> \- Local poll protocol: \`3.3\`
> 
> \## Implementation Guide
> 
> Implement the Tuya support first, then finalize the tests:
> 
> 1. Add or update the Tuya cloud mapping in \`server/services/tuya/lib/mappings/cloud/\`.
> 2. Add or update the Tuya local mapping in \`server/services/tuya/lib/mappings/local/\`.
> 3. Register or update the device definition in \`server/services/tuya/lib/mappings/index.js\`.
> 4. If the new feature needs a new Gladys \`category/type\`, add it in \`server/utils/constants.js\`.
> 5. If the new feature uses a new \`category/type\` not yet handled by Tuya reading, update \`readValues\` in \`server/services/tuya/lib/device/tuya.deviceMapping.js\`.
> 6. If the feature should be writable from Gladys, also update \`writeValues\` in \`server/services/tuya/lib/device/tuya.deviceMapping.js\`.
> 
> \## Maintainer Notes
> 
> This issue contains:
> \- the complete structured Tuya report
> \- suggested fixture input files for onboarding tests
> \- raw cloud responses
> \- local poll DPS when available
> 
> This issue does not contain:
> \- \`expected-device.json\`
> \- \`expected-events.json\` or \`expected-cloud-events.json\` / \`expected-local-events.json\`
> \- \`expected-local-mapping.json\`
> 
> These expected files should still be reviewed and created manually.
> 
> \`poll-device.json\` is only a starting point based on the current support level in Gladys.
> After adding or updating mappings, it should be completed with the final supported features and mapping metadata.
> 
> \## Data Coverage
> 
> \- \`GET /v1.0/users/{sourceId}/devices\` -\> \`Device List Entry\` below
> \- \`GET /v1.2/iot-03/devices/{deviceId}/specification\` -\> \`input-device.json \> specifications\`
> \- \`GET /v1.0/iot-03/devices/{deviceId}\` -\> \`input-device.json\` top-level metadata
> \- \`GET /v2.0/cloud/thing/{deviceId}/shadow/properties\` -\> \`input-device.json \> properties\` and \`cloud-status.json\`
> \- \`GET /v2.0/cloud/thing/{deviceId}/model\` -\> \`input-device.json \> thing\_model\`
> \- local poll -\> \`local-dps.json\` when available
> 
> \## Suggested Fixture Folder
> 
> \`\`\`text
> air-conditioner-f3goccgfj6qino4c
> \`\`\`
> 
> Example:
> 
> \`\`\`text
> server/test/services/tuya/fixtures/devices/air-conditioner-f3goccgfj6qino4c
> \`\`\`
> 
> \## Suggested File: manifest.js
> 
> \`\`\`js
> module.exports = {
> name: 'Clim Salle d\\'attente',
> convertDevice: {
> input: './input-device.json',
> expected: './expected-device.json',
> },
> pollCloud: {
> device: './poll-device.json',
> response: './cloud-status.json',
> expectedEvents: './expected-cloud-events.json',
> },
> pollLocal: {
> device: './poll-device.json',
> dps: './local-dps.json',
> expectedEvents: './expected-local-events.json',
> expectedCloudRequests: 0,
> },
> localMapping: {
> device: './poll-device.json',
> expected: './expected-local-mapping.json',
> },
> };
> \`\`\`
> 
> \## Suggested File: input-device.json
> 
> Use this as the base input for \`convertDevice\`.
> 
> \`\`\`json
> {
> "id": "bf5638fc7cc3f25e32i45q",
> "name": "Clim Salle d'attente",
> "product\_name": "Air Conditioner",
> "model": "Air Conditioner",
> "product\_id": "f3goccgfj6qino4c",
> "product\_key": "keyquxnsj75xc8se",
> "local\_key": "\*\*\*",
> "ip": "10.x.x.x",
> "cloud\_ip": "82.x.x.x",
> "protocol\_version": "3.3",
> "local\_override": true,
> "online": true,
> "specifications": {
> "category": "kt",
> "functions": \[
> {
> "code": "switch",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "开关",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "eco",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "ECO模式",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "drying",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Dry",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "cleaning",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "自清洁",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "temp\_unit\_convert",
> "lang\_config": {
> "c": "℃",
> "f": "℉"
> },
> "name": "Display Units",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"c\\",\\"f\\"\]}"
> },
> {
> "code": "temp\_set",
> "lang\_config": {
> "unit": "℃"
> },
> "name": "Set Temp",
> "type": "Integer",
> "values": "{\\"unit\\":\\"℃\\",\\"min\\":160,\\"max\\":880,\\"scale\\":1,\\"step\\":10}"
> },
> {
> "code": "mode",
> "lang\_config": {
> "auto": "Auto",
> "cold": "Cool",
> "hot": "Heat",
> "wind": "Vent"
> },
> "name": "Mode",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"auto\\",\\"cold\\",\\"wet\\",\\"heat\\",\\"fan\\"\]}"
> },
> {
> "code": "heat",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": " Auxiliary Heat",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "light",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Light",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "sleep",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Sleep",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "health",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Health",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "fan\_speed\_enum",
> "lang\_config": {
> "auto": "Auto",
> "high": "High",
> "level\_2": "Low-Med",
> "level\_4": "Med-High",
> "low": "Low",
> "middle": "Medium",
> "mute": "Quiet",
> "strong": "Turbo"
> },
> "name": "WindSpeed",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"auto\\",\\"low\\",\\"low\_mid\\",\\"mid\\",\\"mid\_high\\",\\"high\\",\\"mute\\",\\"turbo\\"\]}"
> }
> \],
> "status": \[
> {
> "code": "switch",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "开关",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "fan\_speed\_enum",
> "lang\_config": {
> "auto": "Auto",
> "high": "High",
> "level\_2": "Low-Med",
> "level\_4": "Med-High",
> "low": "Low",
> "middle": "Medium",
> "mute": "Quiet",
> "strong": "Turbo"
> },
> "name": "WindSpeed",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"auto\\",\\"low\\",\\"low\_mid\\",\\"mid\\",\\"mid\_high\\",\\"high\\",\\"mute\\",\\"turbo\\"\]}"
> },
> {
> "code": "eco",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "ECO模式",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "drying",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Dry",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "cleaning",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "自清洁",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "temp\_unit\_convert",
> "lang\_config": {
> "c": "℃",
> "f": "℉"
> },
> "name": "Display Units",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"c\\",\\"f\\"\]}"
> },
> {
> "code": "temp\_set",
> "lang\_config": {
> "unit": "℃"
> },
> "name": "Set Temp",
> "type": "Integer",
> "values": "{\\"unit\\":\\"℃\\",\\"min\\":160,\\"max\\":880,\\"scale\\":1,\\"step\\":10}"
> },
> {
> "code": "temp\_current",
> "lang\_config": {
> "unit": "℃"
> },
> "name": "Temp Current",
> "type": "Integer",
> "values": "{\\"unit\\":\\"℃\\",\\"min\\":0,\\"max\\":600,\\"scale\\":1,\\"step\\":1}"
> },
> {
> "code": "mode",
> "lang\_config": {
> "auto": "Auto",
> "cold": "Cool",
> "hot": "Heat",
> "wind": "Vent"
> },
> "name": "Mode",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"auto\\",\\"cold\\",\\"wet\\",\\"heat\\",\\"fan\\"\]}"
> },
> {
> "code": "heat",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": " Auxiliary Heat",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "light",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Light",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "countdown\_left",
> "lang\_config": {
> "unit": "Min"
> },
> "name": "Left Time",
> "type": "Integer",
> "values": "{\\"unit\\":\\"分钟\\",\\"min\\":0,\\"max\\":1440,\\"scale\\":0,\\"step\\":1}"
> },
> {
> "code": "sleep",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Sleep",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "health",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Health",
> "type": "Boolean",
> "values": "{}"
> }
> \]
> },
> "properties": {
> "properties": \[
> {
> "code": "Power",
> "custom\_name": "",
> "dp\_id": 1,
> "time": 1772521207887,
> "type": "bool",
> "value": true
> },
> {
> "code": "temp\_set",
> "custom\_name": "",
> "dp\_id": 2,
> "time": 1772522965366,
> "type": "value",
> "value": 200
> },
> {
> "code": "temp\_current",
> "custom\_name": "",
> "dp\_id": 3,
> "time": 1772553646892,
> "type": "value",
> "value": 230
> },
> {
> "code": "mode",
> "custom\_name": "",
> "dp\_id": 4,
> "time": 1772521207672,
> "type": "enum",
> "value": "heat"
> },
> {
> "code": "windspeed",
> "custom\_name": "",
> "dp\_id": 5,
> "time": 1770803041733,
> "type": "enum",
> "value": "auto"
> },
> {
> "code": "mode\_ECO",
> "custom\_name": "",
> "dp\_id": 8,
> "time": 1770474510177,
> "type": "bool",
> "value": false
> },
> {
> "code": "mode\_dry",
> "custom\_name": "",
> "dp\_id": 9,
> "time": 1770474510177,
> "type": "bool",
> "value": false
> },
> {
> "code": "heat",
> "custom\_name": "",
> "dp\_id": 12,
> "time": 1772522965366,
> "type": "bool",
> "value": true
> },
> {
> "code": "light",
> "custom\_name": "",
> "dp\_id": 13,
> "time": 1770642835259,
> "type": "bool",
> "value": true
> },
> {
> "code": "windshake",
> "custom\_name": "",
> "dp\_id": 15,
> "time": 1770642484099,
> "type": "enum",
> "value": "off"
> },
> {
> "code": "Fault",
> "custom\_name": "",
> "dp\_id": 20,
> "time": 1770474510259,
> "type": "bitmap",
> "value": 0
> },
> {
> "code": "Countdown",
> "custom\_name": "",
> "dp\_id": 21,
> "time": 1770474506674,
> "type": "enum",
> "value": "0"
> },
> {
> "code": "countdown\_left",
> "custom\_name": "",
> "dp\_id": 22,
> "time": 1770474508806,
> "type": "value",
> "value": 0
> },
> {
> "code": "use\_number",
> "custom\_name": "",
> "dp\_id": 101,
> "time": 1770474510421,
> "type": "value",
> "value": 0
> },
> {
> "code": "total\_time",
> "custom\_name": "",
> "dp\_id": 102,
> "time": 1772553334896,
> "type": "value",
> "value": 151
> },
> {
> "code": "electricity",
> "custom\_name": "",
> "dp\_id": 103,
> "time": 1772552853000,
> "type": "value",
> "value": 1
> },
> {
> "code": "electricity\_number",
> "custom\_name": "",
> "dp\_id": 104,
> "time": 1770474506674,
> "type": "value",
> "value": 0
> },
> {
> "code": "unit",
> "custom\_name": "",
> "dp\_id": 105,
> "time": 1771803944077,
> "type": "enum",
> "value": "c"
> },
> {
> "code": "horizontal",
> "custom\_name": "",
> "dp\_id": 106,
> "time": 1770642446631,
> "type": "enum",
> "value": "off"
> },
> {
> "code": "vertical",
> "custom\_name": "",
> "dp\_id": 107,
> "time": 1770642484099,
> "type": "enum",
> "value": "off"
> },
> {
> "code": "swing3d",
> "custom\_name": "",
> "dp\_id": 108,
> "time": 1770474510177,
> "type": "bool",
> "value": false
> },
> {
> "code": "sleep",
> "custom\_name": "",
> "dp\_id": 109,
> "time": 1770641883241,
> "type": "bool",
> "value": false
> },
> {
> "code": "health",
> "custom\_name": "",
> "dp\_id": 110,
> "time": 1770642739109,
> "type": "bool",
> "value": true
> },
> {
> "code": "clean",
> "custom\_name": "",
> "dp\_id": 111,
> "time": 1770474510177,
> "type": "bool",
> "value": false
> },
> {
> "code": "type",
> "custom\_name": "",
> "dp\_id": 112,
> "time": 1770474510177,
> "type": "enum",
> "value": "cold"
> },
> {
> "code": "fault2",
> "custom\_name": "",
> "dp\_id": 113,
> "time": 1770474510259,
> "type": "bitmap",
> "value": 0
> },
> {
> "code": "current\_mode",
> "custom\_name": "",
> "dp\_id": 114,
> "time": 1770474506674,
> "type": "enum",
> "value": "cold"
> },
> {
> "code": "heat8",
> "custom\_name": "",
> "dp\_id": 115,
> "time": 1770642896790,
> "type": "bool",
> "value": false
> }
> \]
> },
> "thing\_model": {
> "modelId": "0000003fy5",
> "services": \[
> {
> "actions": \[\],
> "code": "",
> "description": "",
> "events": \[\],
> "name": "默认服务",
> "properties": \[
> {
> "abilityId": 1,
> "accessMode": "rw",
> "code": "Power",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_power",
> "attribute": "1"
> },
> "name": "开关",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 2,
> "accessMode": "rw",
> "code": "temp\_set",
> "description": "摄氏度：16-31\\n华氏度：61-88",
> "extensions": {
> "iconName": "icon-dp\_temp"
> },
> "name": "设置温度",
> "typeSpec": {
> "type": "value",
> "max": 880,
> "min": 160,
> "scale": 1,
> "step": 10,
> "unit": "℃"
> }
> },
> {
> "abilityId": 3,
> "accessMode": "ro",
> "code": "temp\_current",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_sun"
> },
> "name": "当前温度",
> "typeSpec": {
> "type": "value",
> "max": 600,
> "min": 0,
> "scale": 1,
> "step": 1,
> "unit": "℃"
> }
> },
> {
> "abilityId": 4,
> "accessMode": "rw",
> "code": "mode",
> "description": "自动/制冷/除湿/制热/送风",
> "extensions": {
> "iconName": "icon-dp\_mode"
> },
> "name": "工作模式",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "auto",
> "cold",
> "wet",
> "heat",
> "fan"
> \]
> }
> },
> {
> "abilityId": 5,
> "accessMode": "rw",
> "code": "windspeed",
> "description": "自动/低风/中低风/中风/中高风/高风/静音/超强",
> "extensions": {
> "iconName": "icon-dp\_wind"
> },
> "name": "风速",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "auto",
> "low",
> "low\_mid",
> "mid",
> "mid\_high",
> "high",
> "mute",
> "turbo"
> \]
> }
> },
> {
> "abilityId": 8,
> "accessMode": "rw",
> "code": "mode\_ECO",
> "description": "",
> "extensions": {
> "iconName": "icon-eco"
> },
> "name": "ECO模式",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 9,
> "accessMode": "rw",
> "code": "mode\_dry",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_flower"
> },
> "name": "干燥模式",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 12,
> "accessMode": "rw",
> "code": "heat",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_light2"
> },
> "name": "辅热",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 13,
> "accessMode": "rw",
> "code": "light",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_light"
> },
> "name": "灯光",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 15,
> "accessMode": "rw",
> "code": "windshake",
> "description": "上下/左右/全部/关闭",
> "extensions": {
> "iconName": "icon-dp\_shake"
> },
> "name": "风摆",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "un\_down",
> "left\_right",
> "all",
> "off"
> \]
> }
> },
> {
> "abilityId": 20,
> "accessMode": "ro",
> "code": "Fault",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_warming",
> "scope": "fault"
> },
> "name": "故障告警",
> "typeSpec": {
> "type": "bitmap",
> "label": \[
> "CL",
> "E4",
> "E5",
> "H6",
> "H9",
> "HE",
> "L0",
> "L1",
> "L2",
> "L3",
> "L6",
> "L7",
> "L8",
> "L9",
> "LA",
> "Ld",
> "P0",
> "P1",
> "P6",
> "P8",
> "PA",
> "PC",
> "Pd",
> "PE"
> \],
> "maxlen": 24
> }
> },
> {
> "abilityId": 21,
> "accessMode": "rw",
> "code": "Countdown",
> "description": "0:取消，1-6小时。可根据产品实际功能进行设定。",
> "extensions": {
> "iconName": "icon-dp\_time2"
> },
> "name": "倒计时",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "0",
> "1",
> "2",
> "3",
> "4",
> "5",
> "6",
> "7",
> "8",
> "9",
> "10",
> "11",
> "12",
> "13",
> "14",
> "15",
> "16",
> "17",
> "18",
> "19",
> "20",
> "21",
> "22",
> "23",
> "24"
> \]
> }
> },
> {
> "abilityId": 22,
> "accessMode": "ro",
> "code": "countdown\_left",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_time"
> },
> "name": "倒计时剩余时间",
> "typeSpec": {
> "type": "value",
> "max": 1440,
> "min": 0,
> "scale": 0,
> "step": 1,
> "unit": "分钟"
> }
> },
> {
> "abilityId": 101,
> "accessMode": "ro",
> "code": "use\_number",
> "description": "",
> "name": "使用时间上报次数",
> "typeSpec": {
> "type": "value",
> "max": 100000,
> "min": 0,
> "scale": 0,
> "step": 1,
> "unit": ""
> }
> },
> {
> "abilityId": 102,
> "accessMode": "ro",
> "code": "total\_time",
> "description": "",
> "name": "使用时间",
> "typeSpec": {
> "type": "value",
> "max": 70000,
> "min": 0,
> "scale": 0,
> "step": 1,
> "unit": ""
> }
> },
> {
> "abilityId": 103,
> "accessMode": "ro",
> "code": "electricity",
> "description": "",
> "extensions": {
> "trigger": "direct"
> },
> "name": "耗电量",
> "typeSpec": {
> "type": "value",
> "max": 70000,
> "min": 0,
> "scale": 1,
> "step": 1,
> "unit": ""
> }
> },
> {
> "abilityId": 104,
> "accessMode": "ro",
> "code": "electricity\_number",
> "description": "",
> "name": "耗电量上报次数",
> "typeSpec": {
> "type": "value",
> "max": 10000,
> "min": 0,
> "scale": 0,
> "step": 1,
> "unit": ""
> }
> },
> {
> "abilityId": 105,
> "accessMode": "rw",
> "code": "unit",
> "description": "",
> "name": "温标切换",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "c",
> "f"
> \]
> }
> },
> {
> "abilityId": 106,
> "accessMode": "rw",
> "code": "horizontal",
> "description": "关闭/同相扫风/相向扫风",
> "name": "左右扫风",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "off",
> "same",
> "opposite"
> \]
> }
> },
> {
> "abilityId": 107,
> "accessMode": "rw",
> "code": "vertical",
> "description": "关闭/15扫风/位置1/位置2/位置3/位置4/位置5",
> "name": "上下扫风",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "off",
> "15",
> "1",
> "2",
> "3",
> "4",
> "5"
> \]
> }
> },
> {
> "abilityId": 108,
> "accessMode": "rw",
> "code": "swing3d",
> "description": "",
> "name": "3d扫风",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 109,
> "accessMode": "rw",
> "code": "sleep",
> "description": "",
> "name": "睡眠",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 110,
> "accessMode": "rw",
> "code": "health",
> "description": "",
> "name": "健康",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 111,
> "accessMode": "rw",
> "code": "clean",
> "description": "",
> "name": "清洁",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 112,
> "accessMode": "ro",
> "code": "type",
> "description": "单冷/冷暖",
> "name": "机型",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "cold",
> "cold\_heat"
> \]
> }
> },
> {
> "abilityId": 113,
> "accessMode": "ro",
> "code": "fault2",
> "description": "",
> "extensions": {
> "scope": "fault"
> },
> "name": "故障告警2",
> "typeSpec": {
> "type": "bitmap",
> "label": \[
> "PF",
> "SC",
> "U0",
> "U1",
> "U2",
> "U3",
> "U4",
> "U5",
> "U6",
> "U7",
> "U8",
> "U9",
> "UC",
> "Ud",
> "E1",
> "E2"
> \],
> "maxlen": 16
> }
> },
> {
> "abilityId": 114,
> "accessMode": "ro",
> "code": "current\_mode",
> "description": "",
> "name": "当前模式",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "cold",
> "wet",
> "heat",
> "fan"
> \]
> }
> },
> {
> "abilityId": 115,
> "accessMode": "rw",
> "code": "heat8",
> "description": "",
> "name": "八度制热",
> "typeSpec": {
> "type": "bool"
> }
> }
> \]
> }
> \]
> }
> }
> \`\`\`
> 
> \## Suggested File: poll-device.json
> 
> Use this as a base Gladys device for cloud/local poll tests.
> 
> Important:
> \- this file reflects the support level available when the issue was created
> \- after implementing support in mappings, update \`device\_type\`, \`features\`, and \`tuya\_mapping\` to match the final Gladys support
> \- if the final support changes significantly, prefer rebuilding this file from the resulting converted device
> 
> \`\`\`json
> {
> "external\_id": "tuya:bf5638fc7cc3f25e32i45q",
> "params": \[
> {
> "name": "DEVICE\_ID",
> "value": "bf5638fc7cc3f25e32i45q"
> },
> {
> "name": "LOCAL\_KEY",
> "value": "\*\*\*"
> },
> {
> "name": "CLOUD\_IP",
> "value": "82.x.x.x"
> },
> {
> "name": "LOCAL\_OVERRIDE",
> "value": true
> },
> {
> "name": "PRODUCT\_ID",
> "value": "f3goccgfj6qino4c"
> },
> {
> "name": "CLOUD\_STRATEGY",
> "value": "legacy"
> },
> {
> "name": "IP\_ADDRESS",
> "value": "10.x.x.x"
> },
> {
> "name": "PROTOCOL\_VERSION",
> "value": "3.3"
> },
> {
> "name": "PRODUCT\_KEY",
> "value": "keyquxnsj75xc8se"
> }
> \],
> "features": \[
> {
> "name": "switch",
> "external\_id": "tuya:bf5638fc7cc3f25e32i45q:switch",
> "selector": "tuya:bf5638fc7cc3f25e32i45q:switch",
> "read\_only": false,
> "has\_feedback": true,
> "min": 0,
> "max": 1,
> "category": "switch",
> "type": "binary"
> },
> {
> "name": "Power",
> "external\_id": "tuya:bf5638fc7cc3f25e32i45q:Power",
> "selector": "tuya:bf5638fc7cc3f25e32i45q:Power",
> "read\_only": false,
> "has\_feedback": true,
> "min": 0,
> "max": 1,
> "category": "switch",
> "type": "binary"
> }
> \],
> "tuya\_mapping": {
> "ignored\_local\_dps": \[\],
> "ignored\_cloud\_codes": \[\]
> }
> }
> \`\`\`
> 
> \## Suggested File: cloud-status.json
> 
> Use this as the cloud poll response fixture.
> 
> Derived from \`cloud.assembled.properties\`.
> 
> \`\`\`json
> {
> "result": \[
> {
> "code": "Power",
> "value": true
> },
> {
> "code": "temp\_set",
> "value": 200
> },
> {
> "code": "temp\_current",
> "value": 230
> },
> {
> "code": "mode",
> "value": "heat"
> },
> {
> "code": "windspeed",
> "value": "auto"
> },
> {
> "code": "mode\_ECO",
> "value": false
> },
> {
> "code": "mode\_dry",
> "value": false
> },
> {
> "code": "heat",
> "value": true
> },
> {
> "code": "light",
> "value": true
> },
> {
> "code": "windshake",
> "value": "off"
> },
> {
> "code": "Fault",
> "value": 0
> },
> {
> "code": "Countdown",
> "value": "0"
> },
> {
> "code": "countdown\_left",
> "value": 0
> },
> {
> "code": "use\_number",
> "value": 0
> },
> {
> "code": "total\_time",
> "value": 151
> },
> {
> "code": "electricity",
> "value": 1
> },
> {
> "code": "electricity\_number",
> "value": 0
> },
> {
> "code": "unit",
> "value": "c"
> },
> {
> "code": "horizontal",
> "value": "off"
> },
> {
> "code": "vertical",
> "value": "off"
> },
> {
> "code": "swing3d",
> "value": false
> },
> {
> "code": "sleep",
> "value": false
> },
> {
> "code": "health",
> "value": true
> },
> {
> "code": "clean",
> "value": false
> },
> {
> "code": "type",
> "value": "cold"
> },
> {
> "code": "fault2",
> "value": 0
> },
> {
> "code": "current\_mode",
> "value": "cold"
> },
> {
> "code": "heat8",
> "value": false
> }
> \]
> }
> \`\`\`
> 
> \## Suggested File: local-dps.json
> 
> Use this as the local poll DPS fixture.
> 
> \`\`\`json
> {
> "1": true,
> "2": 200,
> "3": 230,
> "4": "heat",
> "5": "auto",
> "8": false,
> "9": false,
> "12": true,
> "13": true,
> "15": "off",
> "20": 0,
> "22": 0,
> "101": 0,
> "102": 151,
> "103": 1,
> "105": "c",
> "106": "off",
> "107": "off",
> "108": false,
> "109": false,
> "110": true,
> "111": false,
> "112": "cold",
> "113": 0,
> "115": false
> }
> \`\`\`
> 
> \## Suggested File: local-scan.json
> 
> Use this only if a local scan payload exists.
> 
> \`\`\`json
> {
> "ip": "10.x.x.x",
> "version": "3.3",
> "productKey": "keyquxnsj75xc8se"
> }
> \`\`\`
> 
> \## Manual Files Guide
> 
> Build the remaining files manually after the Tuya mappings are in place:
> 
> 1. Paste \`input-device.json\` from this issue, then add or update the Tuya mappings in \`server/services/tuya/lib/mappings/cloud/\`, \`server/services/tuya/lib/mappings/local/\`, and \`server/services/tuya/lib/mappings/index.js\`.
> 2. Create \`expected-device.json\` from the final Gladys device returned by \`convertDevice\`. This corresponds to the Tuya device as it should appear in the Discover page once support is implemented.
> 3. Build or complete \`poll-device.json\` from the final supported Gladys features. It should contain the final \`device\_type\`, \`features\`, params, and \`tuya\_mapping\` metadata.
> 4. Copy \`cloud-status.json\` from the cloud property values and \`local-dps.json\` from the local poll DPS payload when available.
> 5. Create \`expected-events.json\` if cloud and local polling should emit the same states. If they differ, keep separate \`expected-cloud-events.json\` and \`expected-local-events.json\` files instead.
> 6. Create \`expected-local-mapping.json\` from the final supported features present in \`poll-device.json\`, using the resolved DPS returned by the local mapping.
> 
> \## Device List Entry
> 
> Source: \`GET /v1.0/users/{sourceId}/devices\`.
> 
> \`\`\`json
> {
> "active\_time": 1770474506,
> "biz\_type": 18,
> "category": "kt",
> "create\_time": 1770474506,
> "icon": "smart/program\_category\_icon/kt.png",
> "id": "bf5638fc7cc3f25e32i45q",
> "ip": "82.x.x.x",
> "lat": "49.6",
> "local\_key": "\*\*\*",
> "lon": "0.33",
> "model": "",
> "name": "Clim Salle d'attente",
> "online": true,
> "owner\_id": "20747383",
> "product\_id": "f3goccgfj6qino4c",
> "product\_name": "Air Conditioner",
> "status": \[
> {
> "code": "switch",
> "value": true
> },
> {
> "code": "temp\_set",
> "value": 200
> },
> {
> "code": "temp\_current",
> "value": 230
> },
> {
> "code": "mode",
> "value": "hot"
> },
> {
> "code": "fan\_speed\_enum",
> "value": "auto"
> },
> {
> "code": "eco",
> "value": false
> },
> {
> "code": "drying",
> "value": false
> },
> {
> "code": "heat",
> "value": true
> },
> {
> "code": "light",
> "value": true
> },
> {
> "code": "countdown\_left",
> "value": 0
> },
> {
> "code": "temp\_unit\_convert",
> "value": "c"
> },
> {
> "code": "sleep",
> "value": false
> },
> {
> "code": "health",
> "value": true
> },
> {
> "code": "cleaning",
> "value": false
> }
> \],
> "sub": false,
> "time\_zone": "+01:00",
> "uid": "eu16072678921349PYdM",
> "update\_time": 1771984329,
> "uuid": "3a0a51d0530c85aa"
> }
> \`\`\`
> 
> \## Supplemental Diagnostics
> 
> Additional metadata that does not naturally belong to the suggested fixture files.
> 
> \`\`\`json
> {
> "selector": "tuya:bf5638fc7cc3f25e32i45q",
> "service\_id": "f631c437-9b06-4108-9151-4fb27f001e59",
> "device\_type": "unknown",
> "protocol\_version": "3.3",
> "poll\_frequency": 30000,
> "should\_poll": true,
> "local\_poll\_status": "Success",
> "unknown\_specification\_codes": \[
> "eco",
> "drying",
> "cleaning",
> "temp\_unit\_convert",
> "fan\_speed\_enum"
> \],
> "unknown\_local\_dps": \[
> "2",
> "3",
> "4",
> "5",
> "8",
> "9",
> "12",
> "13",
> "15",
> "20",
> "22",
> "101",
> "102",
> "103",
> "105",
> "106",
> "107",
> "108",
> "109",
> "110",
> "111",
> "112",
> "113",
> "115"
> \]
> }
> \`\`\`
> 
> Note:
> 
> \- The raw \`thing\_model.response.result.model\` string is intentionally omitted here because it is already represented in a readable object form in \`input-device.json \> thing\_model\`.
> 
> \## Remaining Files To Create Manually
> 
> \`\`\`text
> mapping file(s) in \`server/services/tuya/lib/mappings/cloud/\` and/or \`server/services/tuya/lib/mappings/local/\`
> \`server/services/tuya/lib/mappings/index.js\`
> \`server/utils/constants.js\` when a new Gladys category/type is required
> \`server/services/tuya/lib/device/tuya.deviceMapping.js\` when new read/write handlers are required
> poll-device.json (completed with final supported features)
> expected-device.json
> expected-events.json or expected-cloud-events.json / expected-local-events.json
> expected-local-mapping.json
> \`\`\`
> 
> \## Validation Checklist
> 
> \- Confirm the inferred \`device\_type\`
> \- Create or update the mapping files in \`server/services/tuya/lib/mappings/cloud/\` and/or \`server/services/tuya/lib/mappings/local/\`
> \- Register the mapping in \`server/services/tuya/lib/mappings/index.js\`
> \- Update \`server/utils/constants.js\` if the feature introduces a new Gladys \`category/type\`
> \- Update \`server/services/tuya/lib/device/tuya.deviceMapping.js\` if new \`readValues\` or \`writeValues\` handlers are needed
> \- Rebuild \`poll-device.json\` so it matches the final supported Gladys features
> \- Build \`expected-device.json\` from the final converted Gladys device shown in Discover
> \- Confirm the expected Gladys features
> \- Use a shared \`expected-events.json\` only when cloud and local polling should emit the same states
> \- Confirm cloud polling behavior
> \- Confirm local polling behavior
> \- Confirm local mapping
> \- Add or update mapping files if needed

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [5. März 2026 um 07:14 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/45 "2026-03-05T07:14:46Z")

</div>

Neues Problem in PR behandelt:

> <https://github.com/GladysAssistant/Gladys/issues/2479>
>
> \## Summary
> 
> Unsupported or partially supported Tuya device report.
> 
> \- Device nam…e: \`Clim Salle d'attente\`
> \- External ID: \`tuya:bf5638fc7cc3f25e32i45q\`
> \- Product ID: \`f3goccgfj6qino4c\`
> \- Product key: \`keyquxnsj75xc8se\`
> \- Model: \`Air Conditioner\`
> \- Category: \`kt\`
> \- Online: \`true\`
> \- Local override: \`true\`
> \- Local poll status: \`Success\`
> \- Local poll protocol: \`3.3\`
> 
> \## Implementation Guide
> 
> Implement the Tuya support first, then finalize the tests:
> 
> 1. Add or update the Tuya cloud mapping in \`server/services/tuya/lib/mappings/cloud/\`.
> 2. Add or update the Tuya local mapping in \`server/services/tuya/lib/mappings/local/\`.
> 3. Register or update the device definition in \`server/services/tuya/lib/mappings/index.js\`.
> 4. If the new feature needs a new Gladys \`category/type\`, add it in \`server/utils/constants.js\`.
> 5. If the new feature uses a new \`category/type\` not yet handled by Tuya reading, update \`readValues\` in \`server/services/tuya/lib/device/tuya.deviceMapping.js\`.
> 6. If the feature should be writable from Gladys, also update \`writeValues\` in \`server/services/tuya/lib/device/tuya.deviceMapping.js\`.
> 
> \## Maintainer Notes
> 
> This issue contains:
> \- the complete structured Tuya report
> \- suggested fixture input files for onboarding tests
> \- raw cloud responses
> \- local poll DPS when available
> 
> This issue does not contain:
> \- \`expected-device.json\`
> \- \`expected-events.json\` or \`expected-cloud-events.json\` / \`expected-local-events.json\`
> \- \`expected-local-mapping.json\`
> 
> These expected files should still be reviewed and created manually.
> 
> \`poll-device.json\` is only a starting point based on the current support level in Gladys.
> After adding or updating mappings, it should be completed with the final supported features and mapping metadata.
> 
> \## Data Coverage
> 
> \- \`GET /v1.0/users/{sourceId}/devices\` -\> \`Device List Entry\` below
> \- \`GET /v1.2/iot-03/devices/{deviceId}/specification\` -\> \`input-device.json \> specifications\`
> \- \`GET /v1.0/iot-03/devices/{deviceId}\` -\> \`input-device.json\` top-level metadata
> \- \`GET /v2.0/cloud/thing/{deviceId}/shadow/properties\` -\> \`input-device.json \> properties\` and \`cloud-status.json\`
> \- \`GET /v2.0/cloud/thing/{deviceId}/model\` -\> \`input-device.json \> thing\_model\`
> \- local poll -\> \`local-dps.json\` when available
> 
> \## Suggested Fixture Folder
> 
> \`\`\`text
> air-conditioner-f3goccgfj6qino4c
> \`\`\`
> 
> Example:
> 
> \`\`\`text
> server/test/services/tuya/fixtures/devices/air-conditioner-f3goccgfj6qino4c
> \`\`\`
> 
> \## Suggested File: manifest.js
> 
> \`\`\`js
> module.exports = {
> name: 'Clim Salle d\\'attente',
> convertDevice: {
> input: './input-device.json',
> expected: './expected-device.json',
> },
> pollCloud: {
> device: './poll-device.json',
> response: './cloud-status.json',
> expectedEvents: './expected-cloud-events.json',
> },
> pollLocal: {
> device: './poll-device.json',
> dps: './local-dps.json',
> expectedEvents: './expected-local-events.json',
> expectedCloudRequests: 0,
> },
> localMapping: {
> device: './poll-device.json',
> expected: './expected-local-mapping.json',
> },
> };
> \`\`\`
> 
> \## Suggested File: input-device.json
> 
> Use this as the base input for \`convertDevice\`.
> 
> \`\`\`json
> {
> "id": "bf5638fc7cc3f25e32i45q",
> "name": "Clim Salle d'attente",
> "product\_name": "Air Conditioner",
> "model": "Air Conditioner",
> "product\_id": "f3goccgfj6qino4c",
> "product\_key": "keyquxnsj75xc8se",
> "local\_key": "\*\*\*",
> "ip": "10.x.x.x",
> "cloud\_ip": "82.x.x.x",
> "protocol\_version": "3.3",
> "local\_override": true,
> "online": true,
> "specifications": {
> "category": "kt",
> "functions": \[
> {
> "code": "switch",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "开关",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "eco",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "ECO模式",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "drying",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Dry",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "cleaning",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "自清洁",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "temp\_unit\_convert",
> "lang\_config": {
> "c": "℃",
> "f": "℉"
> },
> "name": "Display Units",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"c\\",\\"f\\"\]}"
> },
> {
> "code": "temp\_set",
> "lang\_config": {
> "unit": "℃"
> },
> "name": "Set Temp",
> "type": "Integer",
> "values": "{\\"unit\\":\\"℃\\",\\"min\\":160,\\"max\\":880,\\"scale\\":1,\\"step\\":10}"
> },
> {
> "code": "mode",
> "lang\_config": {
> "auto": "Auto",
> "cold": "Cool",
> "hot": "Heat",
> "wind": "Vent"
> },
> "name": "Mode",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"auto\\",\\"cold\\",\\"wet\\",\\"heat\\",\\"fan\\"\]}"
> },
> {
> "code": "heat",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": " Auxiliary Heat",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "light",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Light",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "sleep",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Sleep",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "health",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Health",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "fan\_speed\_enum",
> "lang\_config": {
> "auto": "Auto",
> "high": "High",
> "level\_2": "Low-Med",
> "level\_4": "Med-High",
> "low": "Low",
> "middle": "Medium",
> "mute": "Quiet",
> "strong": "Turbo"
> },
> "name": "WindSpeed",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"auto\\",\\"low\\",\\"low\_mid\\",\\"mid\\",\\"mid\_high\\",\\"high\\",\\"mute\\",\\"turbo\\"\]}"
> }
> \],
> "status": \[
> {
> "code": "switch",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "开关",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "fan\_speed\_enum",
> "lang\_config": {
> "auto": "Auto",
> "high": "High",
> "level\_2": "Low-Med",
> "level\_4": "Med-High",
> "low": "Low",
> "middle": "Medium",
> "mute": "Quiet",
> "strong": "Turbo"
> },
> "name": "WindSpeed",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"auto\\",\\"low\\",\\"low\_mid\\",\\"mid\\",\\"mid\_high\\",\\"high\\",\\"mute\\",\\"turbo\\"\]}"
> },
> {
> "code": "eco",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "ECO模式",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "drying",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Dry",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "cleaning",
> "lang\_config": {
> "false": "",
> "true": ""
> },
> "name": "自清洁",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "temp\_unit\_convert",
> "lang\_config": {
> "c": "℃",
> "f": "℉"
> },
> "name": "Display Units",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"c\\",\\"f\\"\]}"
> },
> {
> "code": "temp\_set",
> "lang\_config": {
> "unit": "℃"
> },
> "name": "Set Temp",
> "type": "Integer",
> "values": "{\\"unit\\":\\"℃\\",\\"min\\":160,\\"max\\":880,\\"scale\\":1,\\"step\\":10}"
> },
> {
> "code": "temp\_current",
> "lang\_config": {
> "unit": "℃"
> },
> "name": "Temp Current",
> "type": "Integer",
> "values": "{\\"unit\\":\\"℃\\",\\"min\\":0,\\"max\\":600,\\"scale\\":1,\\"step\\":1}"
> },
> {
> "code": "mode",
> "lang\_config": {
> "auto": "Auto",
> "cold": "Cool",
> "hot": "Heat",
> "wind": "Vent"
> },
> "name": "Mode",
> "type": "Enum",
> "values": "{\\"range\\":\[\\"auto\\",\\"cold\\",\\"wet\\",\\"heat\\",\\"fan\\"\]}"
> },
> {
> "code": "heat",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": " Auxiliary Heat",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "light",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Light",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "countdown\_left",
> "lang\_config": {
> "unit": "Min"
> },
> "name": "Left Time",
> "type": "Integer",
> "values": "{\\"unit\\":\\"分钟\\",\\"min\\":0,\\"max\\":1440,\\"scale\\":0,\\"step\\":1}"
> },
> {
> "code": "sleep",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Sleep",
> "type": "Boolean",
> "values": "{}"
> },
> {
> "code": "health",
> "lang\_config": {
> "false": "OFF",
> "true": "ON"
> },
> "name": "Health",
> "type": "Boolean",
> "values": "{}"
> }
> \]
> },
> "properties": {
> "properties": \[
> {
> "code": "Power",
> "custom\_name": "",
> "dp\_id": 1,
> "time": 1772521207887,
> "type": "bool",
> "value": true
> },
> {
> "code": "temp\_set",
> "custom\_name": "",
> "dp\_id": 2,
> "time": 1772522965366,
> "type": "value",
> "value": 200
> },
> {
> "code": "temp\_current",
> "custom\_name": "",
> "dp\_id": 3,
> "time": 1772553646892,
> "type": "value",
> "value": 230
> },
> {
> "code": "mode",
> "custom\_name": "",
> "dp\_id": 4,
> "time": 1772521207672,
> "type": "enum",
> "value": "heat"
> },
> {
> "code": "windspeed",
> "custom\_name": "",
> "dp\_id": 5,
> "time": 1770803041733,
> "type": "enum",
> "value": "auto"
> },
> {
> "code": "mode\_ECO",
> "custom\_name": "",
> "dp\_id": 8,
> "time": 1770474510177,
> "type": "bool",
> "value": false
> },
> {
> "code": "mode\_dry",
> "custom\_name": "",
> "dp\_id": 9,
> "time": 1770474510177,
> "type": "bool",
> "value": false
> },
> {
> "code": "heat",
> "custom\_name": "",
> "dp\_id": 12,
> "time": 1772522965366,
> "type": "bool",
> "value": true
> },
> {
> "code": "light",
> "custom\_name": "",
> "dp\_id": 13,
> "time": 1770642835259,
> "type": "bool",
> "value": true
> },
> {
> "code": "windshake",
> "custom\_name": "",
> "dp\_id": 15,
> "time": 1770642484099,
> "type": "enum",
> "value": "off"
> },
> {
> "code": "Fault",
> "custom\_name": "",
> "dp\_id": 20,
> "time": 1770474510259,
> "type": "bitmap",
> "value": 0
> },
> {
> "code": "Countdown",
> "custom\_name": "",
> "dp\_id": 21,
> "time": 1770474506674,
> "type": "enum",
> "value": "0"
> },
> {
> "code": "countdown\_left",
> "custom\_name": "",
> "dp\_id": 22,
> "time": 1770474508806,
> "type": "value",
> "value": 0
> },
> {
> "code": "use\_number",
> "custom\_name": "",
> "dp\_id": 101,
> "time": 1770474510421,
> "type": "value",
> "value": 0
> },
> {
> "code": "total\_time",
> "custom\_name": "",
> "dp\_id": 102,
> "time": 1772553334896,
> "type": "value",
> "value": 151
> },
> {
> "code": "electricity",
> "custom\_name": "",
> "dp\_id": 103,
> "time": 1772552853000,
> "type": "value",
> "value": 1
> },
> {
> "code": "electricity\_number",
> "custom\_name": "",
> "dp\_id": 104,
> "time": 1770474506674,
> "type": "value",
> "value": 0
> },
> {
> "code": "unit",
> "custom\_name": "",
> "dp\_id": 105,
> "time": 1771803944077,
> "type": "enum",
> "value": "c"
> },
> {
> "code": "horizontal",
> "custom\_name": "",
> "dp\_id": 106,
> "time": 1770642446631,
> "type": "enum",
> "value": "off"
> },
> {
> "code": "vertical",
> "custom\_name": "",
> "dp\_id": 107,
> "time": 1770642484099,
> "type": "enum",
> "value": "off"
> },
> {
> "code": "swing3d",
> "custom\_name": "",
> "dp\_id": 108,
> "time": 1770474510177,
> "type": "bool",
> "value": false
> },
> {
> "code": "sleep",
> "custom\_name": "",
> "dp\_id": 109,
> "time": 1770641883241,
> "type": "bool",
> "value": false
> },
> {
> "code": "health",
> "custom\_name": "",
> "dp\_id": 110,
> "time": 1770642739109,
> "type": "bool",
> "value": true
> },
> {
> "code": "clean",
> "custom\_name": "",
> "dp\_id": 111,
> "time": 1770474510177,
> "type": "bool",
> "value": false
> },
> {
> "code": "type",
> "custom\_name": "",
> "dp\_id": 112,
> "time": 1770474510177,
> "type": "enum",
> "value": "cold"
> },
> {
> "code": "fault2",
> "custom\_name": "",
> "dp\_id": 113,
> "time": 1770474510259,
> "type": "bitmap",
> "value": 0
> },
> {
> "code": "current\_mode",
> "custom\_name": "",
> "dp\_id": 114,
> "time": 1770474506674,
> "type": "enum",
> "value": "cold"
> },
> {
> "code": "heat8",
> "custom\_name": "",
> "dp\_id": 115,
> "time": 1770642896790,
> "type": "bool",
> "value": false
> }
> \]
> },
> "thing\_model": {
> "modelId": "0000003fy5",
> "services": \[
> {
> "actions": \[\],
> "code": "",
> "description": "",
> "events": \[\],
> "name": "默认服务",
> "properties": \[
> {
> "abilityId": 1,
> "accessMode": "rw",
> "code": "Power",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_power",
> "attribute": "1"
> },
> "name": "开关",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 2,
> "accessMode": "rw",
> "code": "temp\_set",
> "description": "摄氏度：16-31\\n华氏度：61-88",
> "extensions": {
> "iconName": "icon-dp\_temp"
> },
> "name": "设置温度",
> "typeSpec": {
> "type": "value",
> "max": 880,
> "min": 160,
> "scale": 1,
> "step": 10,
> "unit": "℃"
> }
> },
> {
> "abilityId": 3,
> "accessMode": "ro",
> "code": "temp\_current",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_sun"
> },
> "name": "当前温度",
> "typeSpec": {
> "type": "value",
> "max": 600,
> "min": 0,
> "scale": 1,
> "step": 1,
> "unit": "℃"
> }
> },
> {
> "abilityId": 4,
> "accessMode": "rw",
> "code": "mode",
> "description": "自动/制冷/除湿/制热/送风",
> "extensions": {
> "iconName": "icon-dp\_mode"
> },
> "name": "工作模式",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "auto",
> "cold",
> "wet",
> "heat",
> "fan"
> \]
> }
> },
> {
> "abilityId": 5,
> "accessMode": "rw",
> "code": "windspeed",
> "description": "自动/低风/中低风/中风/中高风/高风/静音/超强",
> "extensions": {
> "iconName": "icon-dp\_wind"
> },
> "name": "风速",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "auto",
> "low",
> "low\_mid",
> "mid",
> "mid\_high",
> "high",
> "mute",
> "turbo"
> \]
> }
> },
> {
> "abilityId": 8,
> "accessMode": "rw",
> "code": "mode\_ECO",
> "description": "",
> "extensions": {
> "iconName": "icon-eco"
> },
> "name": "ECO模式",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 9,
> "accessMode": "rw",
> "code": "mode\_dry",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_flower"
> },
> "name": "干燥模式",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 12,
> "accessMode": "rw",
> "code": "heat",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_light2"
> },
> "name": "辅热",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 13,
> "accessMode": "rw",
> "code": "light",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_light"
> },
> "name": "灯光",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 15,
> "accessMode": "rw",
> "code": "windshake",
> "description": "上下/左右/全部/关闭",
> "extensions": {
> "iconName": "icon-dp\_shake"
> },
> "name": "风摆",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "un\_down",
> "left\_right",
> "all",
> "off"
> \]
> }
> },
> {
> "abilityId": 20,
> "accessMode": "ro",
> "code": "Fault",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_warming",
> "scope": "fault"
> },
> "name": "故障告警",
> "typeSpec": {
> "type": "bitmap",
> "label": \[
> "CL",
> "E4",
> "E5",
> "H6",
> "H9",
> "HE",
> "L0",
> "L1",
> "L2",
> "L3",
> "L6",
> "L7",
> "L8",
> "L9",
> "LA",
> "Ld",
> "P0",
> "P1",
> "P6",
> "P8",
> "PA",
> "PC",
> "Pd",
> "PE"
> \],
> "maxlen": 24
> }
> },
> {
> "abilityId": 21,
> "accessMode": "rw",
> "code": "Countdown",
> "description": "0:取消，1-6小时。可根据产品实际功能进行设定。",
> "extensions": {
> "iconName": "icon-dp\_time2"
> },
> "name": "倒计时",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "0",
> "1",
> "2",
> "3",
> "4",
> "5",
> "6",
> "7",
> "8",
> "9",
> "10",
> "11",
> "12",
> "13",
> "14",
> "15",
> "16",
> "17",
> "18",
> "19",
> "20",
> "21",
> "22",
> "23",
> "24"
> \]
> }
> },
> {
> "abilityId": 22,
> "accessMode": "ro",
> "code": "countdown\_left",
> "description": "",
> "extensions": {
> "iconName": "icon-dp\_time"
> },
> "name": "倒计时剩余时间",
> "typeSpec": {
> "type": "value",
> "max": 1440,
> "min": 0,
> "scale": 0,
> "step": 1,
> "unit": "分钟"
> }
> },
> {
> "abilityId": 101,
> "accessMode": "ro",
> "code": "use\_number",
> "description": "",
> "name": "使用时间上报次数",
> "typeSpec": {
> "type": "value",
> "max": 100000,
> "min": 0,
> "scale": 0,
> "step": 1,
> "unit": ""
> }
> },
> {
> "abilityId": 102,
> "accessMode": "ro",
> "code": "total\_time",
> "description": "",
> "name": "使用时间",
> "typeSpec": {
> "type": "value",
> "max": 70000,
> "min": 0,
> "scale": 0,
> "step": 1,
> "unit": ""
> }
> },
> {
> "abilityId": 103,
> "accessMode": "ro",
> "code": "electricity",
> "description": "",
> "extensions": {
> "trigger": "direct"
> },
> "name": "耗电量",
> "typeSpec": {
> "type": "value",
> "max": 70000,
> "min": 0,
> "scale": 1,
> "step": 1,
> "unit": ""
> }
> },
> {
> "abilityId": 104,
> "accessMode": "ro",
> "code": "electricity\_number",
> "description": "",
> "name": "耗电量上报次数",
> "typeSpec": {
> "type": "value",
> "max": 10000,
> "min": 0,
> "scale": 0,
> "step": 1,
> "unit": ""
> }
> },
> {
> "abilityId": 105,
> "accessMode": "rw",
> "code": "unit",
> "description": "",
> "name": "温标切换",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "c",
> "f"
> \]
> }
> },
> {
> "abilityId": 106,
> "accessMode": "rw",
> "code": "horizontal",
> "description": "关闭/同相扫风/相向扫风",
> "name": "左右扫风",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "off",
> "same",
> "opposite"
> \]
> }
> },
> {
> "abilityId": 107,
> "accessMode": "rw",
> "code": "vertical",
> "description": "关闭/15扫风/位置1/位置2/位置3/位置4/位置5",
> "name": "上下扫风",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "off",
> "15",
> "1",
> "2",
> "3",
> "4",
> "5"
> \]
> }
> },
> {
> "abilityId": 108,
> "accessMode": "rw",
> "code": "swing3d",
> "description": "",
> "name": "3d扫风",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 109,
> "accessMode": "rw",
> "code": "sleep",
> "description": "",
> "name": "睡眠",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 110,
> "accessMode": "rw",
> "code": "health",
> "description": "",
> "name": "健康",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 111,
> "accessMode": "rw",
> "code": "clean",
> "description": "",
> "name": "清洁",
> "typeSpec": {
> "type": "bool"
> }
> },
> {
> "abilityId": 112,
> "accessMode": "ro",
> "code": "type",
> "description": "单冷/冷暖",
> "name": "机型",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "cold",
> "cold\_heat"
> \]
> }
> },
> {
> "abilityId": 113,
> "accessMode": "ro",
> "code": "fault2",
> "description": "",
> "extensions": {
> "scope": "fault"
> },
> "name": "故障告警2",
> "typeSpec": {
> "type": "bitmap",
> "label": \[
> "PF",
> "SC",
> "U0",
> "U1",
> "U2",
> "U3",
> "U4",
> "U5",
> "U6",
> "U7",
> "U8",
> "U9",
> "UC",
> "Ud",
> "E1",
> "E2"
> \],
> "maxlen": 16
> }
> },
> {
> "abilityId": 114,
> "accessMode": "ro",
> "code": "current\_mode",
> "description": "",
> "name": "当前模式",
> "typeSpec": {
> "type": "enum",
> "range": \[
> "cold",
> "wet",
> "heat",
> "fan"
> \]
> }
> },
> {
> "abilityId": 115,
> "accessMode": "rw",
> "code": "heat8",
> "description": "",
> "name": "八度制热",
> "typeSpec": {
> "type": "bool"
> }
> }
> \]
> }
> \]
> }
> }
> \`\`\`
> 
> \## Suggested File: poll-device.json
> 
> Use this as a base Gladys device for cloud/local poll tests.
> 
> Important:
> \- this file reflects the support level available when the issue was created
> \- after implementing support in mappings, update \`device\_type\`, \`features\`, and \`tuya\_mapping\` to match the final Gladys support
> \- if the final support changes significantly, prefer rebuilding this file from the resulting converted device
> 
> \`\`\`json
> {
> "external\_id": "tuya:bf5638fc7cc3f25e32i45q",
> "params": \[
> {
> "name": "DEVICE\_ID",
> "value": "bf5638fc7cc3f25e32i45q"
> },
> {
> "name": "LOCAL\_KEY",
> "value": "\*\*\*"
> },
> {
> "name": "CLOUD\_IP",
> "value": "82.x.x.x"
> },
> {
> "name": "LOCAL\_OVERRIDE",
> "value": true
> },
> {
> "name": "PRODUCT\_ID",
> "value": "f3goccgfj6qino4c"
> },
> {
> "name": "CLOUD\_STRATEGY",
> "value": "legacy"
> },
> {
> "name": "IP\_ADDRESS",
> "value": "10.x.x.x"
> },
> {
> "name": "PROTOCOL\_VERSION",
> "value": "3.3"
> },
> {
> "name": "PRODUCT\_KEY",
> "value": "keyquxnsj75xc8se"
> }
> \],
> "features": \[
> {
> "name": "switch",
> "external\_id": "tuya:bf5638fc7cc3f25e32i45q:switch",
> "selector": "tuya:bf5638fc7cc3f25e32i45q:switch",
> "read\_only": false,
> "has\_feedback": true,
> "min": 0,
> "max": 1,
> "category": "switch",
> "type": "binary"
> },
> {
> "name": "Power",
> "external\_id": "tuya:bf5638fc7cc3f25e32i45q:Power",
> "selector": "tuya:bf5638fc7cc3f25e32i45q:Power",
> "read\_only": false,
> "has\_feedback": true,
> "min": 0,
> "max": 1,
> "category": "switch",
> "type": "binary"
> }
> \],
> "tuya\_mapping": {
> "ignored\_local\_dps": \[\],
> "ignored\_cloud\_codes": \[\]
> }
> }
> \`\`\`
> 
> \## Suggested File: cloud-status.json
> 
> Use this as the cloud poll response fixture.
> 
> Derived from \`cloud.assembled.properties\`.
> 
> \`\`\`json
> {
> "result": \[
> {
> "code": "Power",
> "value": true
> },
> {
> "code": "temp\_set",
> "value": 200
> },
> {
> "code": "temp\_current",
> "value": 230
> },
> {
> "code": "mode",
> "value": "heat"
> },
> {
> "code": "windspeed",
> "value": "auto"
> },
> {
> "code": "mode\_ECO",
> "value": false
> },
> {
> "code": "mode\_dry",
> "value": false
> },
> {
> "code": "heat",
> "value": true
> },
> {
> "code": "light",
> "value": true
> },
> {
> "code": "windshake",
> "value": "off"
> },
> {
> "code": "Fault",
> "value": 0
> },
> {
> "code": "Countdown",
> "value": "0"
> },
> {
> "code": "countdown\_left",
> "value": 0
> },
> {
> "code": "use\_number",
> "value": 0
> },
> {
> "code": "total\_time",
> "value": 151
> },
> {
> "code": "electricity",
> "value": 1
> },
> {
> "code": "electricity\_number",
> "value": 0
> },
> {
> "code": "unit",
> "value": "c"
> },
> {
> "code": "horizontal",
> "value": "off"
> },
> {
> "code": "vertical",
> "value": "off"
> },
> {
> "code": "swing3d",
> "value": false
> },
> {
> "code": "sleep",
> "value": false
> },
> {
> "code": "health",
> "value": true
> },
> {
> "code": "clean",
> "value": false
> },
> {
> "code": "type",
> "value": "cold"
> },
> {
> "code": "fault2",
> "value": 0
> },
> {
> "code": "current\_mode",
> "value": "cold"
> },
> {
> "code": "heat8",
> "value": false
> }
> \]
> }
> \`\`\`
> 
> \## Suggested File: local-dps.json
> 
> Use this as the local poll DPS fixture.
> 
> \`\`\`json
> {
> "1": true,
> "2": 200,
> "3": 230,
> "4": "heat",
> "5": "auto",
> "8": false,
> "9": false,
> "12": true,
> "13": true,
> "15": "off",
> "20": 0,
> "22": 0,
> "101": 0,
> "102": 151,
> "103": 1,
> "105": "c",
> "106": "off",
> "107": "off",
> "108": false,
> "109": false,
> "110": true,
> "111": false,
> "112": "cold",
> "113": 0,
> "115": false
> }
> \`\`\`
> 
> \## Suggested File: local-scan.json
> 
> Use this only if a local scan payload exists.
> 
> \`\`\`json
> {
> "ip": "10.x.x.x",
> "version": "3.3",
> "productKey": "keyquxnsj75xc8se"
> }
> \`\`\`
> 
> \## Manual Files Guide
> 
> Build the remaining files manually after the Tuya mappings are in place:
> 
> 1. Paste \`input-device.json\` from this issue, then add or update the Tuya mappings in \`server/services/tuya/lib/mappings/cloud/\`, \`server/services/tuya/lib/mappings/local/\`, and \`server/services/tuya/lib/mappings/index.js\`.
> 2. Create \`expected-device.json\` from the final Gladys device returned by \`convertDevice\`. This corresponds to the Tuya device as it should appear in the Discover page once support is implemented.
> 3. Build or complete \`poll-device.json\` from the final supported Gladys features. It should contain the final \`device\_type\`, \`features\`, params, and \`tuya\_mapping\` metadata.
> 4. Copy \`cloud-status.json\` from the cloud property values and \`local-dps.json\` from the local poll DPS payload when available.
> 5. Create \`expected-events.json\` if cloud and local polling should emit the same states. If they differ, keep separate \`expected-cloud-events.json\` and \`expected-local-events.json\` files instead.
> 6. Create \`expected-local-mapping.json\` from the final supported features present in \`poll-device.json\`, using the resolved DPS returned by the local mapping.
> 
> \## Device List Entry
> 
> Source: \`GET /v1.0/users/{sourceId}/devices\`.
> 
> \`\`\`json
> {
> "active\_time": 1770474506,
> "biz\_type": 18,
> "category": "kt",
> "create\_time": 1770474506,
> "icon": "smart/program\_category\_icon/kt.png",
> "id": "bf5638fc7cc3f25e32i45q",
> "ip": "82.x.x.x",
> "lat": "49.6",
> "local\_key": "\*\*\*",
> "lon": "0.33",
> "model": "",
> "name": "Clim Salle d'attente",
> "online": true,
> "owner\_id": "20747383",
> "product\_id": "f3goccgfj6qino4c",
> "product\_name": "Air Conditioner",
> "status": \[
> {
> "code": "switch",
> "value": true
> },
> {
> "code": "temp\_set",
> "value": 200
> },
> {
> "code": "temp\_current",
> "value": 230
> },
> {
> "code": "mode",
> "value": "hot"
> },
> {
> "code": "fan\_speed\_enum",
> "value": "auto"
> },
> {
> "code": "eco",
> "value": false
> },
> {
> "code": "drying",
> "value": false
> },
> {
> "code": "heat",
> "value": true
> },
> {
> "code": "light",
> "value": true
> },
> {
> "code": "countdown\_left",
> "value": 0
> },
> {
> "code": "temp\_unit\_convert",
> "value": "c"
> },
> {
> "code": "sleep",
> "value": false
> },
> {
> "code": "health",
> "value": true
> },
> {
> "code": "cleaning",
> "value": false
> }
> \],
> "sub": false,
> "time\_zone": "+01:00",
> "uid": "eu16072678921349PYdM",
> "update\_time": 1771984329,
> "uuid": "3a0a51d0530c85aa"
> }
> \`\`\`
> 
> \## Supplemental Diagnostics
> 
> Additional metadata that does not naturally belong to the suggested fixture files.
> 
> \`\`\`json
> {
> "selector": "tuya:bf5638fc7cc3f25e32i45q",
> "service\_id": "f631c437-9b06-4108-9151-4fb27f001e59",
> "device\_type": "unknown",
> "protocol\_version": "3.3",
> "poll\_frequency": 30000,
> "should\_poll": true,
> "local\_poll\_status": "Success",
> "unknown\_specification\_codes": \[
> "eco",
> "drying",
> "cleaning",
> "temp\_unit\_convert",
> "fan\_speed\_enum"
> \],
> "unknown\_local\_dps": \[
> "2",
> "3",
> "4",
> "5",
> "8",
> "9",
> "12",
> "13",
> "15",
> "20",
> "22",
> "101",
> "102",
> "103",
> "105",
> "106",
> "107",
> "108",
> "109",
> "110",
> "111",
> "112",
> "113",
> "115"
> \]
> }
> \`\`\`
> 
> Note:
> 
> \- The raw \`thing\_model.response.result.model\` string is intentionally omitted here because it is already represented in a readable object form in \`input-device.json \> thing\_model\`.
> 
> \## Remaining Files To Create Manually
> 
> \`\`\`text
> mapping file(s) in \`server/services/tuya/lib/mappings/cloud/\` and/or \`server/services/tuya/lib/mappings/local/\`
> \`server/services/tuya/lib/mappings/index.js\`
> \`server/utils/constants.js\` when a new Gladys category/type is required
> \`server/services/tuya/lib/device/tuya.deviceMapping.js\` when new read/write handlers are required
> poll-device.json (completed with final supported features)
> expected-device.json
> expected-events.json or expected-cloud-events.json / expected-local-events.json
> expected-local-mapping.json
> \`\`\`
> 
> \## Validation Checklist
> 
> \- Confirm the inferred \`device\_type\`
> \- Create or update the mapping files in \`server/services/tuya/lib/mappings/cloud/\` and/or \`server/services/tuya/lib/mappings/local/\`
> \- Register the mapping in \`server/services/tuya/lib/mappings/index.js\`
> \- Update \`server/utils/constants.js\` if the feature introduces a new Gladys \`category/type\`
> \- Update \`server/services/tuya/lib/device/tuya.deviceMapping.js\` if new \`readValues\` or \`writeValues\` handlers are needed
> \- Rebuild \`poll-device.json\` so it matches the final supported Gladys features
> \- Build \`expected-device.json\` from the final converted Gladys device shown in Discover
> \- Confirm the expected Gladys features
> \- Use a shared \`expected-events.json\` only when cloud and local polling should emit the same states
> \- Confirm cloud polling behavior
> \- Confirm local polling behavior
> \- Confirm local mapping
> \- Add or update mapping files if needed

> <https://github.com/GladysAssistant/Gladys/pull/2458>
>
> \### Pull Request check-list
> 
> To ensure your Pull Request can be accepted as fa…st as possible, make sure to review and check all of these items:
> 
> \- \[\] If your changes affect the code, did you write the tests?
> \- \[\] Are tests passing? (\`npm test\` on both front/server)
> \- \[\] Is the linter passing? (\`npm run eslint\` on both front/server)
> \- \[\] Did you run prettier? (\`npm run prettier\` on both front/server)
> \- \[\] If you are adding a new feature/service, did you run the integration comparator? (\`npm run compare-translations\` on front)
> \- \[\] Did you test this pull request in real life? With real devices? If this development is a big feature or a new service, we recommend that you provide a Docker image to the community (\[forum\](https://community.gladysassistant.com/)) for testing before merging.
> \- \[\] If your changes modify the API (REST or Node.js), did you modify the API documentation? (Documentation is based on comments in code)
> \- \[\] If you are adding a new features/services which needs explanation, did you modify the user documentation? See \[the GitHub repo\](https://github.com/GladysAssistant/v4-website) and the \[website\](https://gladysassistant.com).
> \- \[\] Did you add fake requests data for the demo mode (\`front/src/config/demo.js\`) so that the demo website is working without a backend? (if needed) See \[https://demo.gladysassistant.com\](https://demo.gladysassistant.com).
> 
> NOTE: these things are not required to open a PR and can be done afterwards / while the PR is open.
> 
> \### Description of change
> 
> \## Summary
> 
> \- Add support for Tuya air-conditioner devices reported in issue \`#2479\`.
> \- Support both local and cloud read/write flows for AC capabilities:
> - \`switch\`
> - \`temp\_set\`
> - \`temp\_current\`
> - \`mode\`
> - \`fan\_speed\_enum\`
> - \`horizontal\`
> - \`vertical\`
> \- Add dedicated AC fixture coverage and align cloud strategy/mapping tests.
> 
> \## Details
> 
> \- Front (prod):
> - add dedicated device feature components for AC fan speed and AC swing controls
> - integrate AC features into the room device feature rendering flow
> - update AC mode component behavior to align with the new mapping support
> \- Translations:
> - add/adjust AC labels in English, French, and German
> \- Server (prod):
> - add a dedicated \`air-conditioner\` Tuya device type
> - add explicit cloud mapping for AC capabilities
> - add explicit local mapping for AC DPS capabilities
> - register AC device type in Tuya mapping index
> - extend Tuya device read/write mappings for AC features
> - extend constants for AC-related supported feature values
> - simplify \`tuya.cloudStrategy\` by removing unreachable/dead branches while preserving behavior
> \- Server tests:
> - add a full fixture set for \`air-conditioner-f3goccgfj6qino4c\`
> - add/extend fixture-driven tests for convert/local mapping/poll/setValue
> - add missing AC write mapping regression (\`AIR\_CONDITIONING.BINARY\`)
> - add cloud strategy regression coverage for shadow-only supported codes
> 
> \## Why this matters
> 
> \- AC devices expose a broader and different capability model than previously supported Tuya devices.
> \- Explicit cloud/local mappings keep behavior predictable and easier to maintain across device families.
> \- Fixture-driven coverage ensures onboarding remains stable for future Tuya device additions.
> 
> \## Scope
> 
> Compared to \`tuya-pilot-thermostat-support\`:
> 
> \- Front (prod)
> 
> - \`+147 lines / -45 lines\`
> 
> \- Translations
> 
> - \`+93 lines / -6 lines\`
> 
> \- Server (prod)
> 
> - \`+311 lines / -11 lines\`
> 
> \- Server Tests
> 
> - \`+778 lines / -0 lines\`
> 
> \- No package changes.
> 
> \- Total
> 
> - \`27 files changed\`
> - \`+1329 lines / -62 lines\`
> 
> 
> 
> \## Summary by CodeRabbit
> 
> \* \*\*New Features\*\*
> \* More air‑conditioning controls: fan‑speed, eco, drying, cleaning, aux‑heat, light, sleep, health.
> \* Local network discovery and polling for Tuya devices.
> \* GitHub issue workflow to suggest unsupported/partially supported devices.
> 
> \* \*\*Improvements\*\*
> \* Richer Tuya device UI: cloud/local mode, IP/protocol controls, device ranking and partial‑support indicators, better connection states.
> \* Automatic temperature‑unit detection and conversion.
> \* Expanded translations (EN/DE/FR) and messaging.

- Gerät:

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/5/5/55f021ed765b8f39608fe49cfee1ef8fc41ff381.png)

- Dashboard

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/f/e/fe13c05ca56f8a7661d1b87dc1d9355c4c7c4542.png)

- Horizontaler Wisch:

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/e/1/e10b1571cf5a781189a638ca29c296fd2b26371e.png)

- Vertikaler Wisch:

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/b/f/bf4173675340dfac7b309dfe1131a60519ee9f82.png)

- Modus:

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/5/2/525506fecfdcfc73821462a44a373552ce0ac628.png)

- Lüftergeschwindigkeit:

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/b/3/b39d983817fd9346aeb428ad062188c1d90ac31f.png)

---

<div class="post-metadata">

**Author:** ![GBoulvin](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/gboulvin/32/10006_2.png) [@GBoulvin](https://community.gladysassistant.com/u/GBoulvin)\
**Post date:** [7. März 2026 um 20:49 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/46 "2026-03-07T20:49:30Z")

</div>

Hallo!

Danke für das Update!

Bei mir wird der „Smart meter“ immer noch als „nicht unterstützt“ angezeigt:

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/9/4/948dcfaf85576de63f5909f475308eccc296de97.png)

Bei den LSC-Steckdosen funktioniert eine der beiden (Protokoll 3.5) und wird als unterstützt angeboten (mit Kindersicherung!):

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/2/6/26c612ff8836e52208b8a94e4d66bd9c1fc66b33.png)

Die zweite (Protokoll 3.4) gibt mir jedoch eine Fehlermeldung (lokal).

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/5/e/5e046455999a20095c4be0193eda2698ac73d8a1.png)

Ich habe mit dem Button ein GitHub-Issue erstellt und hier ist das Ergebnis (sieht professionell aus!):

> <https://github.com/GladysAssistant/Gladys/issues/2484>
>
> \## Summary
> 
> Unsupported or partially supported Tuya device report.
> 
> \- Device nam…e: \`Smart Power Plug\`
> \- External ID: \`tuya:bf1d9d0b6ed2b5755fkt24\`
> \- Product ID: \`ewtmo9yydoyaam53\`
> \- Product key: \`keyjup78v54myhan\`
> \- Model: \`LSC Smart Power Plug\`
> \- Category: \`cz\`
> \- Online: \`true\`
> \- Local override: \`true\`
> \- Local poll status: \`Error\`
> \- Local poll protocol: \`unknown\`
> 
> \## Implementation Guide
> 
> Implement the Tuya support first, then finalize the tests:
> 
> 1. Add or update the Tuya cloud mapping in \`server/services/tuya/lib/mappings/cloud/\`.
> 2. Add or update the Tuya local mapping in \`server/services/tuya/lib/mappings/local/\`.
> 3. Register or update the device definition in \`server/services/tuya/lib/mappings/index.js\`.
> 4. If the new feature needs a new Gladys \`category/type\`, add it in \`server/utils/constants.js\`.
> 5. If the new feature uses a new \`category/type\` not yet handled by Tuya reading, update \`readValues\` in \`server/services/tuya/lib/device/tuya.deviceMapping.js\`.
> 6. If the feature should be writable from Gladys, also update \`writeValues\` in \`server/services/tuya/lib/device/tuya.deviceMapping.js\`.
> 
> \## Maintainer Notes
> 
> This issue contains:
> \- the complete structured Tuya report
> \- suggested fixture input files for onboarding tests
> \- raw cloud responses
> \- local poll DPS when available
> 
> This issue does not contain:
> \- \`expected-device.json\`
> \- \`expected-events.json\` or \`expected-cloud-events.json\` / \`expected-local-events.json\`
> \- \`expected-local-mapping.json\`
> 
> These expected files should still be reviewed and created manually.
> 
> \`poll-device.json\` is only a starting point based on the current support level in Gladys.
> After adding or updating mappings, it should be completed with the final supported features and mapping metadata.
> 
> \## Data Coverage
> 
> \- \`GET /v1.0/users/{sourceId}/devices\` -\> \`Device List Entry\` below
> \- \`GET /v1.2/iot-03/devices/{deviceId}/specification\` -\> \`input-device.json \> specifications\`
> \- \`GET /v1.0/iot-03/devices/{deviceId}\` -\> \`input-device.json\` top-level metadata
> \- \`GET /v2.0/cloud/thing/{deviceId}/shadow/properties\` -\> \`input-device.json \> properties\` and \`cloud-status.json\`
> \- \`GET /v2.0/cloud/thing/{deviceId}/model\` -\> \`input-device.json \> thing\_model\`
> \- local poll -\> \`local-dps.json\` when available
> 
> \## Suggested Fixture Folder
> 
> \`\`\`text
> lsc-smart-power-plug-ewtmo9yydoyaam53
> \`\`\`
> 
> Example:
> 
> \`\`\`text
> server/test/services/tuya/fixtures/devices/lsc-smart-power-plug-ewtmo9yydoyaam53
> \`\`\`
> 
> \## Suggested File: manifest.js
> 
> \`\`\`js
> module.exports = {
> name: 'Smart Power Plug',
> convertDevice: {
> input: './input-device.json',
> expected: './expected-device.json',
> },
> pollCloud: {
> device: './poll-device.json',
> response: './cloud-status.json',
> expectedEvents: './expected-cloud-events.json',
> },
> localMapping: {
> device: './poll-device.json',
> expected: './expected-local-mapping.json',
> },
> };
> \`\`\`
> 
> \## Suggested File: input-device.json
> 
> Use this as the base input for \`convertDevice\`.
> 
> \`\`\`json
> {
> "id": "47556a54-436b-41f8-8fc9-4fa9031f2415",
> "name": "Smart Power Plug",
> "product\_name": "LSC Smart Power Plug",
> "model": "LSC Smart Power Plug",
> "product\_id": "ewtmo9yydoyaam53",
> "product\_key": "keyjup78v54myhan",
> "local\_key": "\*\*\*",
> "ip": "192.x.x.x",
> "cloud\_ip": "91.x.x.x",
> "protocol\_version": "3.4",
> "local\_override": true,
> "online": true,
> "specifications": {
> "category": "cz"
> },
> "properties": {}
> }
> \`\`\`
> 
> \## Suggested File: poll-device.json
> 
> Use this as a base Gladys device for cloud/local poll tests.
> 
> Important:
> \- this file reflects the support level available when the issue was created
> \- after implementing support in mappings, update \`device\_type\`, \`features\`, and \`tuya\_mapping\` to match the final Gladys support
> \- if the final support changes significantly, prefer rebuilding this file from the resulting converted device
> 
> \`\`\`json
> {
> "external\_id": "tuya:bf1d9d0b6ed2b5755fkt24",
> "device\_type": "smart-socket",
> "params": \[
> {
> "name": "DEVICE\_ID",
> "value": "bf1d9d0b6ed2b5755fkt24"
> },
> {
> "name": "LOCAL\_KEY",
> "value": "\*\*\*"
> },
> {
> "name": "CLOUD\_IP",
> "value": "91.x.x.x"
> },
> {
> "name": "LOCAL\_OVERRIDE",
> "value": true
> },
> {
> "name": "PRODUCT\_ID",
> "value": "ewtmo9yydoyaam53"
> },
> {
> "name": "IP\_ADDRESS",
> "value": "192.x.x.x"
> },
> {
> "name": "PROTOCOL\_VERSION",
> "value": "3.4"
> },
> {
> "name": "PRODUCT\_KEY",
> "value": "keyjup78v54myhan"
> }
> \],
> "features": \[\],
> "tuya\_mapping": {
> "ignored\_local\_dps": \[
> "9",
> "11",
> "21",
> "22",
> "23",
> "24",
> "25",
> "38",
> "39",
> "40",
> "42",
> "43",
> "44"
> \],
> "ignored\_cloud\_codes": \[
> "countdown",
> "countdown\_1",
> "relay\_status",
> "overcharge\_switch",
> "light\_mode",
> "cycle\_time",
> "random\_time",
> "switch\_inching",
> "voltage\_coe",
> "electric\_coe",
> "power\_coe",
> "electricity\_coe",
> "test\_bit"
> \]
> }
> }
> \`\`\`
> 
> \## Suggested File: cloud-status.json
> 
> Use this as the cloud poll response fixture.
> 
> Derived from \`cloud.assembled.properties\`.
> 
> \`\`\`json
> {
> "result": \[\]
> }
> \`\`\`
> 
> \## Suggested File: local-scan.json
> 
> Use this only if a local scan payload exists.
> 
> \`\`\`json
> {
> "ip": "192.x.x.x",
> "version": "3.4",
> "productKey": "keyjup78v54myhan"
> }
> \`\`\`
> 
> \## Manual Files Guide
> 
> Build the remaining files manually after the Tuya mappings are in place:
> 
> 1. Paste \`input-device.json\` from this issue, then add or update the Tuya mappings in \`server/services/tuya/lib/mappings/cloud/\`, \`server/services/tuya/lib/mappings/local/\`, and \`server/services/tuya/lib/mappings/index.js\`.
> 2. Create \`expected-device.json\` from the final Gladys device returned by \`convertDevice\`. This corresponds to the Tuya device as it should appear in the Discover page once support is implemented.
> 3. Build or complete \`poll-device.json\` from the final supported Gladys features. It should contain the final \`device\_type\`, \`features\`, params, and \`tuya\_mapping\` metadata.
> 4. Copy \`cloud-status.json\` from the cloud property values and \`local-dps.json\` from the local poll DPS payload when available.
> 5. Create \`expected-events.json\` if cloud and local polling should emit the same states. If they differ, keep separate \`expected-cloud-events.json\` and \`expected-local-events.json\` files instead.
> 6. Create \`expected-local-mapping.json\` from the final supported features present in \`poll-device.json\`, using the resolved DPS returned by the local mapping.
> 
> \## Device List Entry
> 
> Source: \`GET /v1.0/users/{sourceId}/devices\`.
> 
> \`\`\`json
> {
> "active\_time": 1772006289,
> "biz\_type": 0,
> "category": "cz",
> "create\_time": 1772006289,
> "icon": "smart/icon/ay1541056239985fDGjj/74e5b5f39252e8a2ae7b44bb1fec1d64.png",
> "id": "bf1d9d0b6ed2b5755fkt24",
> "ip": "91.x.x.x",
> "lat": "50.3294",
> "local\_key": "\*\*\*",
> "lon": "4.4004",
> "model": "5225000300",
> "name": "Smart Power Plug",
> "online": true,
> "owner\_id": "161869416",
> "product\_id": "ewtmo9yydoyaam53",
> "product\_name": "LSC Smart Power Plug",
> "status": \[
> {
> "code": "switch\_1",
> "value": false
> },
> {
> "code": "countdown\_1",
> "value": 0
> },
> {
> "code": "add\_ele",
> "value": 1
> },
> {
> "code": "cur\_current",
> "value": 0
> },
> {
> "code": "cur\_power",
> "value": 0
> },
> {
> "code": "cur\_voltage",
> "value": 2317
> },
> {
> "code": "voltage\_coe",
> "value": 590
> },
> {
> "code": "electric\_coe",
> "value": 30088
> },
> {
> "code": "power\_coe",
> "value": 16241
> },
> {
> "code": "electricity\_coe",
> "value": 2560
> },
> {
> "code": "fault",
> "value": 0
> },
> {
> "code": "relay\_status",
> "value": "last"
> },
> {
> "code": "light\_mode",
> "value": "relay"
> }
> \],
> "sub": false,
> "time\_zone": "+01:00",
> "uid": "eu1690232009037AjM7i",
> "update\_time": 1772848844,
> "uuid": "55dcefbcafddf45f"
> }
> \`\`\`
> 
> \## Supplemental Diagnostics
> 
> Additional metadata that does not naturally belong to the suggested fixture files.
> 
> \`\`\`json
> {
> "selector": "tuya:bf1d9d0b6ed2b5755fkt24",
> "service\_id": "966ff9b2-7d5d-4c88-aa54-80c406d5743d",
> "device\_type": "smart-socket",
> "protocol\_version": "3.4",
> "poll\_frequency": 30000,
> "should\_poll": true,
> "local\_poll\_status": "Error",
> "local\_poll\_error": "Local poll timeout"
> }
> \`\`\`
> 
> Note:
> 
> \- The raw \`thing\_model.response.result.model\` string is intentionally omitted here because it is already represented in a readable object form in \`input-device.json \> thing\_model\`.
> 
> \## Remaining Files To Create Manually
> 
> \`\`\`text
> mapping file(s) in \`server/services/tuya/lib/mappings/cloud/\` and/or \`server/services/tuya/lib/mappings/local/\`
> \`server/services/tuya/lib/mappings/index.js\`
> \`server/utils/constants.js\` when a new Gladys category/type is required
> \`server/services/tuya/lib/device/tuya.deviceMapping.js\` when new read/write handlers are required
> poll-device.json (completed with final supported features)
> expected-device.json
> expected-events.json or expected-cloud-events.json / expected-local-events.json
> expected-local-mapping.json
> \`\`\`
> 
> \## Validation Checklist
> 
> \- Confirm the inferred \`device\_type\`
> \- Create or update the mapping files in \`server/services/tuya/lib/mappings/cloud/\` and/or \`server/services/tuya/lib/mappings/local/\`
> \- Register the mapping in \`server/services/tuya/lib/mappings/index.js\`
> \- Update \`server/utils/constants.js\` if the feature introduces a new Gladys \`category/type\`
> \- Update \`server/services/tuya/lib/device/tuya.deviceMapping.js\` if new \`readValues\` or \`writeValues\` handlers are needed
> \- Rebuild \`poll-device.json\` so it matches the final supported Gladys features
> \- Build \`expected-device.json\` from the final converted Gladys device shown in Discover
> \- Confirm the expected Gladys features
> \- Use a shared \`expected-events.json\` only when cloud and local polling should emit the same states
> \- Confirm cloud polling behavior
> \- Confirm local polling behavior
> \- Confirm local mapping
> \- Add or update mapping files if needed

Falls ich helfen kann, zögere nicht!

Edit: Bei der zweiten Steckdose funktioniert nach erneuter Testung die Cloud, aber nicht lokal.

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [11. März 2026 um 12:57 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/47 "2026-03-11T12:57:55Z")

</div>

Hallo @GBoulvin,

Danke für deine Tests

> [@GBoulvin](#):
>
> Der „Smart meter“ wird immer noch als „nicht unterstützt“ angezeigt

Was für eine Enttäuschung… Ich hatte gehofft, dass er gleich beim ersten Mal passt ^^

---

<div class="post-metadata">

**Author:** ![GBoulvin](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/gboulvin/32/10006_2.png) [@GBoulvin](https://community.gladysassistant.com/u/GBoulvin)\
**Post date:** [11. März 2026 um 15:29 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/48 "2026-03-11T15:29:41Z")

</div>

Neuer Test mit dem Bild des Tages!

Beim Smart Meter fehlen die Kommas:

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/3/4/344fb0b7c3c905196521509f19194bcfe45985b1.png)

Aber alle Funktionen werden korrekt angezeigt:

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/f/b/fbecb41fa4ff3c26e39b5b3209a4e39f1e3e7934.png)

Allerdings sind die Geräte nach dem lokalen Update aus dem Dashboard verschwunden (war das nicht schon behoben?)

Muss der lokale Scan unbedingt vom Cloud-Scan getrennt werden oder könnte das automatisch ablaufen?

Manchmal muss ich die IP-Adressen manuell eingeben und ich kann nicht herausfinden, warum oder warum nicht…

Und ich bestätige, dass die Protokolle 3.3, 3.4 und 3.5 lokal einwandfrei funktionieren!!!

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [13. März 2026 um 10:53 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/49 "2026-03-13T10:53:41Z")

</div>

Hallo @GBoulvin

> [@GBoulvin](#):
>
> Beim Smart Meter fehlen die Kommas:

Entschuldige für die Verzögerung, es war ein Test … leider ohne Erfolg!! Es war vor allem ein Vergessen. Das Bild wird aktualisiert und ist im Bau =\> 5 bis 20 Minuten.

> [@GBoulvin](#):
>
> Allerdings sind die Geräte nach dem lokalen Update vom Dashboard verschwunden (war das nicht behoben?)

Ja, in diesem Fall kann das normal sein, ich habe einige Änderungen an der Funktion vorgenommen, also hat das sicherlich das alte Gerät beschädigt (keine automatische Migration). Da wir in der Entwicklung sind, mache ich keine Migration, die das alte Gerät während der Bearbeitung beschädigen würde ^^

> [@GBoulvin](#):
>
> Muss der lokale Scan unbedingt vom Cloud-Scan getrennt werden oder könnte er automatisch erfolgen?

Ja, das ist momentan absichtlich so. Der lokale UDP-Scan dauert länger und hängt vom lokalen Netzwerk ab, daher habe ich ihn lieber als manuelle Aktion belassen, um die Cloud-Erkennung nicht zu verlangsamen.

> [@GBoulvin](#):
>
> Manchmal muss ich die IP-Adressen manuell eingeben und ich kann nicht herausfinden, warum oder warum nicht…

Das ist konsistent mit der Funktionsweise des lokalen UDP: je nach Netzwerk (AP-Isolation, VLAN, Broadcast/Multicast-Filterung, Gerät, das wenig broadcastet), kann die IP möglicherweise nicht automatisch zurückgemeldet werden.  
In diesen Fällen ist die manuelle Eingabe weiterhin notwendig. Handelt es sich deiner Meinung nach nicht um ein Gerät in einem anderen Netzwerk oder das länger braucht, um zu antworten?

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [6. April 2026 um 17:39 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/50 "2026-04-06T17:39:02Z")

</div>

Hallo @Papashultz und @GBoulvin,

Sagt mal, @pierre-gilles hat die Überprüfung des ersten PRs zu Tuya begonnen. Hättet ihr die Möglichkeit, das erste PR zu testen, sobald es code-seitig freigegeben ist, basierend auf einer Kopie eurer Produktionsdatenbank, um sicherzustellen, dass nichts auf funktionierender Hardware kaputt geht?

Ich habe es von meiner Seite mit 2 Steckdosen (die einzigen unterstützten Geräte in meiner aktuellen Version) getestet, aber das bringt uns nicht sehr weit.

Weitere Aufrufe an Mitwirkende, falls ihr die Möglichkeit habt, als Besitzer von Tuya-Geräten zu testen:

- @Kalvin
- @PhilippeMA
- @Francis66
- @Xenicle

Das Test-Image wird unter `docker pull terdious/gladys:tuya-PR1` verfügbar sein.

---

<div class="post-metadata">

**Author:** ![Psoy](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/psoy/32/9005_2.png) [@Psoy](https://community.gladysassistant.com/u/Psoy)\
**Post date:** [9. April 2026 um 20:58 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/51 "2026-04-09T20:58:19Z")

</div>

Guten Abend @Terdious  
Ich komme nach der Schlägerei, aber ich habe dein Bild getestet. Hier sind die Geräte, die ich getestet habe:

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/a/e/ae304d9f064fa47bd181dfdfdc6e13df6c7e05ac.png). Alle funktionieren, nur eine funktioniert nicht vollständig, das ist die Farbglühbirne. Man sieht schon am Dashboard, dass die Farben dunkel sind,  
 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/6/d/6d8c7ead5df28dffdc77011d09d3f8d5efb34d51.png). Das liegt daran, dass die Lampe nicht richtig erkannt wird, es fehlen Funktionen wie: Weißlichtmodus, Farbmodus, Szenariomodus, die in der Tuya-App vorhanden sind. Aber das Problem bestand schon, bevor du das Projekt übernommen hast. Ich hoffe, das hilft dir weiter, danke für deine Arbeit. Gute Nacht

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [10. April 2026 um 05:50 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/52 "2026-04-10T05:50:12Z")

</div>

Hallo @Psoy !!

Vielen Dank !! Du kommst überhaupt nicht nach dem Kampf, im Gegenteil !!  
Super beruhigende Rückkehr !!

Wenn du mehr testen möchtest, kannst du jetzt `docker pull terdious/gladys:tuya-test` testen, damit du ein GitHub-Issue erstellen kannst, damit ich die vollständige Erkennung der Geräte hinzufügen kann, bei denen etwas fehlt. Wenn sie in einem Issue vorhanden sind, kann ich daran von Zeit zu Zeit arbeiten, wenn ich etwas Zeit habe ^^

---

<div class="post-metadata">

**Author:** ![Psoy](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/psoy/32/9005_2.png) [@Psoy](https://community.gladysassistant.com/u/Psoy)\
**Post date:** [10. April 2026 um 05:56 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/53 "2026-04-10T05:56:45Z")

</div>

> [@Terdious](#):
>
> Das sollte dir ermöglichen, ein GitHub-Issue zu erstellen

Hallo @Terdious  
Ich habe das mit diesem Bild getestet `docker pull terdious/gladys:tuya-PR1`  
Ich werde `docker pull terdious/gladys:tuya-test` installieren, aber beim GitHub-Issue komme ich später auf dich zurück, denn das bekomme ich gerade nicht hin 😉

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [10. April 2026 um 06:08 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/54 "2026-04-10T06:08:55Z")

</div>

> [@Psoy](#):
>
> Ich werde `docker pull terdious/gladys:tuya-test` installieren, aber für das GitHub-Ticket komme ich später auf dich zurück, denn das bekomme ich gerade nicht hin 😉

Das geht ganz von alleine, du wirst schon sehen!! Und gerade bin ich daran interessiert, dein Feedback zur Verständlichkeit des kleinen Leitfadens zu hören ^^ 😉

Das Ziel dieser Entwicklung war es, das, was bei einigen anderen Integrationen gemacht wurde, weiterzuführen, aber noch stärker zu führen!! Und ohne doppelte Anfragen zu erstellen

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [10. April 2026 um 08:58 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/55 "2026-04-10T08:58:30Z")

</div>

Danke für dein Feedback @Psoy!

Falls noch jemand das Bild testen könnte, wäre das super! Danach kann ich diese erste PR für mich zum Deployment freigeben.

Danke @Terdious für die Entwicklung 🙌

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [22. April 2026 um 09:41 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/56 "2026-04-22T09:41:22Z")

</div>

Ich fürchte nein, es wird leider schwierig, voranzukommen.

Für meinen Teil hatte ich allerdings einen echten Bedarf. Ich habe mich also motiviert und obwohl es für die Klimaanlagen viel komplizierter war als hier erwartet, ist alles in HA installiert. Und es funktioniert sehr gut. Es hat mich zwar gekostet, alle meine Pro-Szenen in HA neu zu erstellen, aber es hat den Vorteil, dass es funktioniert (und mir seit zwei Wochen Einsparungen bringt).

Da ich seit zwei Wochen eine stressige Phase bei der Arbeit habe und jetzt in die Phase der Außenarbeiten (Arbeiten / Wartung) eintrete, wollte ich hiermit mitteilen, dass ich, wie jedes Jahr, bis Oktober nicht wirklich Zeit haben werde.

Für mich gibt es keinen dringenden Bedarf mehr an dieser Integration, aber ich werde trotzdem versuchen, den Fortschritt zu verfolgen, und wenn ich dann Zeit finde, werde ich mein Bestes tun, um denen zu helfen, die es brauchen.

Die automatische Aktivitätskontrolle auf der GitHub-PR wird den Job erledigen, um sie zu schließen, falls nicht.

Bis bald! Und einen schönen Frühling/Sommer an alle.

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [23. April 2026 um 12:02 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/57 "2026-04-23T12:02:31Z")

</div>

Danke für dein Feedback und dein Engagement @Terdious 🙂

Ich denke, die schönen Tage sind zurück und die Aktivität geht natürlich zurück, du bist nicht der Einzige, der im Moment mehr zu tun hat 😄

Ich sehe das auch in den sozialen Medien, ich habe weniger Aufrufe als zu Jahresbeginn!

Ich hoffe, wir bekommen noch mehr Tester 🤞

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [11. Mai 2026 um 06:12 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/58 "2026-05-11T06:12:35Z")

</div>

Hallo zusammen, @pierre-gilles,

Nur zur Info, der 2. PR für die Unterstützung des Protokolls 3.5 ist von meiner Seite aus bereit für die Überprüfung:

> <https://github.com/GladysAssistant/Gladys/pull/2438>
>
> \### Pull Request check-list
> 
> To ensure your Pull Request can be accepted as fa…st as possible, make sure to review and check all of these items:
> 
> \- \[x\] If your changes affect the code, did you write the tests?
> \- \[x\] Are tests passing? (\`npm test\` on both front/server)
> \- \[x\] Is the linter passing? (\`npm run eslint\` on both front/server)
> \- \[x\] Did you run prettier? (\`npm run prettier\` on both front/server)
> \- \[x\] If you are adding a new feature/service, did you run the integration comparator? (\`npm run compare-translations\` on front)
> \- \[x\] Did you test this pull request in real life? With real devices? If this development is a big feature or a new service, we recommend that you provide a Docker image to the community (\[forum\](https://community.gladysassistant.com/)) for testing before merging.
> \- \[\] If your changes modify the API (REST or Node.js), did you modify the API documentation? (Documentation is based on comments in code)
> \- \[\] If you are adding a new features/services which needs explanation, did you modify the user documentation? See \[the GitHub repo\](https://github.com/GladysAssistant/v4-website) and the \[website\](https://gladysassistant.com).
> \- \[\] Did you add fake requests data for the demo mode (\`front/src/config/demo.js\`) so that the demo website is working without a backend? (if needed) See \[https://demo.gladysassistant.com\](https://demo.gladysassistant.com).
> 
> NOTE: these things are not required to open a PR and can be done afterwards / while the PR is open.
> 
> \### Description of change
> 
> \## Summary
> 
> Adds support for \*\*Tuya local protocols 3.4 and 3.5\*\* to the Tuya integration. Stacks on top of \[PR #2434\](https://github.com/GladysAssistant/Gladys/pull/2434) which is now merged into \`master\`.
> 
> The official \`tuyapi@7.2.0\` only supports protocols 3.1 and 3.3 — it has \*\*no cipher or parser\*\* for 3.4 (the "3.4" dropdown option was pointing to a non-functional path) and obviously none for 3.5. A second client (\`@demirdeniz/tuyapi-newgen\`) is added and used \*\*only\*\* when \`protocolVersion === '3.4'\` or \`'3.5'\`. Protocols 3.1 and 3.3 keep using the original \`tuyapi\` client and are not impacted.
> 
> \## Details
> 
> \*\*Protocol routing\*\*
> \- \`tuya.localPoll.js\` and \`tuya.setValue.js\` pick the local API class based on an \`isNewGenProtocol\` flag (\`isProtocol34 || isProtocol35\`).
> \- For 3.5 only: \`keepAlive\` is disabled and \`socketTimeout\` is floored at 5 s because the 3.5 handshake takes longer than the others.
> \- For 3.5 only: a small fallback chain (\`{schema:true}\` → \`{schema:true, dps:\[1\]}\` → \`{}\`) because some firmwares reject a bare schema get on first contact. 3.4 uses a single schema attempt.
> \- Protocol 3.4 reuses the existing \`tuyapi-newgen\` \`\_decrypt34\` cipher and \`0x6699/0x9966\` UDP framing.
> 
> \*\*UDP local scan\*\*
> \- \`tuya.localScan.js\` now parses incoming packets with three \`MessageParser\` instances in order \`\[3.1, 3.4, 3.5\]\` and keeps the first one that succeeds.
> \- \`localScan(input)\` accepts either a number or an object so existing callers passing \`{ timeoutSeconds: N }\` still work.
> \- \`timeoutSeconds\` is sanitized into \`\[1, 30\] s\`.
> 
> \*\*Robustness improvements (touched along the way)\*\*
> \- \`localPoll.timeoutMs\` is sanitized into \`\[500, 30000\] ms\` to prevent immediate timeouts or pathologically long hangs.
> \- \`setValue\` now throws \`BadParameters\` when the external\_id has no command instead of silently falling back to the cloud.
> 
> \*\*Front (\`TuyaDeviceBox.jsx\`)\*\*
> \- Protocol 3.5 is enabled in the dropdown (3.4 was already listed but non-functional before this PR).
> \- \`pollLocal()\` adds 3.5 to the fallback list and captures \`currentDevice\` once at the start of the async loop to avoid stale \`this.state.device\` reads across protocol attempts.
> \- Obsolete i18n keys \`protocol35OptionUnsupported\` and \`protocolVersionRequired\` removed (en/fr/de).
> 
> \*\*Dependency\*\*
> \- \`@demirdeniz/tuyapi-newgen\` is \*\*pinned\*\* to exact version \`8.1.5\` (no caret), since it is a single-maintainer scoped fork. License MIT, integrity hash present in lockfile.
> 
> \## Scope
> 
> Computed against \`master\` (PR #2434 already merged).
> 
> \- \*\*server (prod)\*\* : ~150 lines (3 files: \`tuya.localPoll.js\`, \`tuya.localScan.js\`, \`tuya.setValue.js\`)
> \- \*\*server (tests)\*\* : ~325 lines (3 files: \`tuya.localPoll.test.js\`, \`tuya.localScan.test.js\`, \`tuya.setValue.test.js\`)
> \- \*\*front (prod)\*\* : ~29 lines (\`TuyaDeviceBox.jsx\`)
> \- \*\*translations\*\* : ~18 lines (\`en.json\`, \`fr.json\`, \`de.json\`)
> \- \*\*packages / lockfiles\*\* : ~75 lines (\`package.json\`, \`package-lock.json\`)
> 
> Total : ~597 lines across 12 files.
> 
> \## Validation
> 
> \- \`npm run test-service --service=tuya\` → \*\*159 passing, 0 failing\*\*
> \- \`eslint server/services/tuya server/test/services/tuya\` → clean
> \- \`eslint front/src/routes/integration/all/tuya\` → clean
> 
> 
> 
> 
> \## Summary by CodeRabbit
> 
> \* \*\*New Features\*\*
> \* Local device polling with multi-protocol fallback, UDP local discovery, connection status, manual disconnect, reconnect logic, and cloud/local mode controls.
> 
> \* \*\*UI\*\*
> \* Richer Tuya setup UI with new credential fields and connection states; device view shows masked IP, product/device identifiers, protocol/IP controls, local-poll actions, GitHub issue shortcut, and improved discovery ordering/status.
> 
> \* \*\*Localization\*\*
> \* Expanded DE/EN/FR translations for setup, discovery, devices, statuses, errors, and guidance.
> 
> \* \*\*Tests\*\*
> \* Extensive new and updated tests for local poll/scan, discovery, config, status, setValue, and lifecycle.

Ich habe gerade das Update des vorherigen Docker-Testimages gestartet `docker pull terdious/gladys:tuya-PR1` (Hätte ich es nicht so nennen sollen ^^)

Falls jemand Lust hat, es nochmal zu testen, wäre das super (Entschuldigung, ich werde die Leute, von denen ich weiß, dass sie Interesse haben, ein bisschen spammen. Zögert nicht, mir zu sagen, wenn ihr nicht mehr genannt werden wollt).  
@Psoy, @GBoulvin, @Papashultz, falls ihr die Gelegenheit habt, vielen Dank im Voraus.

**EDIT** :  
Keine Probleme meinerseits beim Starten des oben genannten PR2 über master nach dem Hinzufügen eines Tuya-Geräts im Protokoll 3.3. Aber ich habe kein Protokoll 3.5-Gerät zum Testen (ich habe einen Thermostat, aber dieser wird erst in PR6 oder 7 unterstützt). Falls @GBoulvin, könntest du dieses Bild testen? Ich glaube, du hast das, auch wenn nicht alle Funktionen unterstützt werden.

---

<div class="post-metadata">

**Author:** ![GBoulvin](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/gboulvin/32/10006_2.png) [@GBoulvin](https://community.gladysassistant.com/u/GBoulvin)\
**Post date:** [11. Mai 2026 um 14:35 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/59 "2026-05-11T14:35:18Z")

</div>

Hallo!

Das Protokoll 3.5 funktioniert problemlos! Allerdings bekomme ich die Version 3.4 nicht zum Laufen. Es hat aber doch früher funktioniert… Die Fehlermeldung lautet: „Lokaler Poll-Timeout“.

Ich habe es von einem sauberen Image aus getestet.

Edit: Nach dem Lesen der vorherigen Nachrichten scheint es nicht funktioniert zu haben…

---

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [11. Mai 2026 um 14:40 UTC](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983/60 "2026-05-11T14:40:47Z")

</div>

Danke @GBoulvin für dein Test.

Tatsächlich, soweit ich sehe (und dank der neuen Analyse von Claude Opus 4.7), ist das Protokoll 3.4 nicht implementiert.  
Ich werde nicht genug Zeit haben, um schnell daran zu arbeiten, aber ich werde die Arbeit natürlich in diese Richtung fortsetzen.

[Vorherige Seite](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983.md?page=2)

[Nächste Seite](https://community.gladysassistant.com/t/tuya-integration-chauffage-et-climatiseur/9983.md?page=4)
