External integration - Tuya

I thought so… :innocent:

You told me this distributor should expose what I needed.
Your F14-W should then expose:
• Distribute — a button that gives a portion (usable in a scene,
for example every day at 8:00 a.m.)
• Last distributed quantity
• Slow distribution
• Indicator light
• Battery
I think you didn’t see my feedback.
The distributor doesn’t expose everything it should, only the distribution button.

For what you asked me, I found this.

[2026-08-05T18:08:07.095Z] [INFO] [tuya] [Tuya][poll][local] device=bf15bc151aba2c

Hello!

I have an issue with the ‹ doorbell rings › action.

The action appears correctly, well detected but the scene does not trigger…

Yet, it worked!

Nothing special in the logs. I have the impression that it’s rather on the core side…

[2026-09-03T16:26:54.376Z] [INFO] [tuya] [Tuya][push] device=bf8a5bf8acc4540a41rere local push published 1 change(s)
[2026-09-03T16:26:54.414Z] [INFO] [tuya] [Tuya][push] device=bf8a5bf8acc4540a41rere local push published 1 change(s)
[2026-09-03T16:26:54.520Z] [INFO] [tuya] [Tuya][push] device=bf8a5bf8acc4540a41rere local push published 1 change(s)
[2026-09-03T16:26:54.718Z] [INFO] [tuya] [Tuya][push] device=bf8a5bf8acc4540a41rere local push published 1 change(s)
[2026-09-03T16:26:55.913Z] [INFO] [tuya] [Tuya][media] doorbell_pic event fired (device=ext:ext-terdious-gladys-tuya:device:bf0e59548489fcb4ea62of)
[2026-09-03T16:26:57.110Z] [INFO] [tuya] [Tuya][media] doorbell_pic snapshot published (device=ext:ext-terdious-gladys-tuya:device:bf0e59548489fcb4ea62of)

Edit:

2026-09-03T18:26:54+0200 <error> device.poll.js:30 (DeviceManager.poll) There was an error while polling device production-solaire-bf8a5bf8acc4540a41rere
2026-09-03T18:26:54+0200 <error> device.poll.js:31 (DeviceManager.poll) ExternalIntegrationUnavailableError: EXTERNAL_INTEGRATION_COMMAND_TIMEOUT
    at Timeout._onTimeout (/src/server/lib/external-integration/externalIntegration.sendCommand.js:32:14)
    at listOnTimeout (node:internal/timers:685:17)
    at processTimers (node:internal/timers:618:7)
2026-09-03T18:26:55+0200 <warn> scene.executeActions.js:47 (executeAction) ExternalIntegrationUnavailableError: No Tuya snapshot available yet (it updates on a ring or a motion event)
    at ExternalIntegration.handleCommandResult (/src/server/lib/external-integration/externalIntegration.handleCommandResult.js:29:7)
    at WebSocket.<anonymous> (/src/server/api/websockets/index.js:161:45)
    at WebSocket.emit (node:events:514:28)
    at Receiver.receiverOnMessage (/src/server/node_modules/ws/lib/websocket.js:807:20)
    at Receiver.emit (node:events:514:28)
    at Receiver.dataMessage (/src/server/node_modules/ws/lib/receiver.js:448:14)
    at Receiver.getData (/src/server/node_modules/ws/lib/receiver.js:377:17)
    at Receiver.startLoop (/src/server/node_modules/ws/lib/receiver.js:158:22)
    at Receiver._write (/src/server/node_modules/ws/lib/receiver.js:94:10)
    at writeOrBuffer (node:internal/streams/writable:574:12)
    at _write (node:internal/streams/writable:503:10)
    at Receiver.Writable.write (node:internal/streams/writable:512:10)
    at Socket.socketOnData (/src/server/node_modules/ws/lib/websocket.js:882:35)
    at Socket.emit (node:events:514:28)
    at addChunk (node:internal/streams/readable:567:12)
    at readableAddChunkPushByteMode (node:internal/streams/readable:518:3)
    at Socket.Readable.push (node:internal/streams/readable:398:5)
    at TCP.onStreamRead (node:internal/stream_base_commons:189:23)
2026-09-03T18:26:55+0200 <warn> scene.executeActions.js:47 (executeAction) ExternalIntegrationUnavailableError: No Tuya snapshot available yet (it updates on a ring or a motion event)
    at ExternalIntegration.handleCommandResult (/src/server/lib/external-integration/externalIntegration.handleCommandResult.js:29:7)
    at WebSocket.<anonymous> (/src/server/api/websockets/index.js:161:45)
    at WebSocket.emit (node:events:514:28)
    at Receiver.receiverOnMessage (/src/server/node_modules/ws/lib/websocket.js:807:20)
    at Receiver.emit (node:events:514:28)
    at Receiver.dataMessage (/src/server/node_modules/ws/lib/receiver.js:448:14)
    at Receiver.getData (/src/server/node_modules/ws/lib/receiver.js:377:17)
    at Receiver.startLoop (/src/server/node_modules/ws/lib/receiver.js:158:22)
    at Receiver._write (/src/server/node_modules/ws/lib/receiver.js:94:10)
    at writeOrBuffer (node:internal/streams/writable:574:12)
    at _write (node:internal/streams/writable:503:10)
    at Receiver.Writable.write (node:internal/streams/writable:512:10)
    at Socket.socketOnData (/src/server/node_modules/ws/lib/websocket.js:882:35)
    at Socket.emit (node:events:514:28)
    at addChunk (node:internal/streams/readable:567:12)
    at readableAddChunkPushByteMode (node:internal/streams/readable:518:3)
    at Socket.Readable.push (node:internal/streams/readable:398:5)
    at TCP.onStreamRead (node:internal/stream_base_commons:189:23)
2026-09-03T18:26:55+0200 <warn> scene.executeActions.js:47 (executeAction) ExternalIntegrationUnavailableError: No Tuya snapshot available yet (it updates on a ring or a motion event)
    at ExternalIntegration.handleCommandResult (/src/server/lib/external-integration/externalIntegration.handleCommandResult.js:29:7)
    at WebSocket.<anonymous> (/src/server/api/websockets/index.js:161:45)
    at WebSocket.emit (node:events:514:28)
    at Receiver.receiverOnMessage (/src/server/node_modules/ws/lib/websocket.js:807:20)
    at Receiver.emit (node:events:514:28)
    at Receiver.dataMessage (/src/server/node_modules/ws/lib/receiver.js:448:14)
    at Receiver.getData (/src/server/node_modules/ws/lib/receiver.js:377:17)
    at Receiver.startLoop (/src/server/node_modules/ws/lib/receiver.js:158:22)
    at Receiver._write (/src/server/node_modules/ws/lib/receiver.js:94:10)
    at writeOrBuffer (node:internal/streams/writable:574:12)
    at _write (node:internal/streams/writable:503:10)
    at Receiver.Writable.write (node:internal/streams/writable:512:10)
    at Socket.socketOnData (/src/server/node_modules/ws/lib/websocket.js:882:35)
    at Socket.emit (node:events:514:28)
    at addChunk (node:internal/streams/readable:567:12)
    at readableAddChunkPushByteMode (node:internal/streams/readable:518:3)
    at Socket.Readable.push (node:internal/streams/readable:398:5)
    at TCP.onStreamRead (node:internal/stream_base_commons:189:23)

Hi @elfedagger, sorry for the delay.
I didn’t see your previous feedback.

Your distributor probably doesn’t expose the same Tuya codes as the model I based it on. I hoped it would be better than that, sorry.

Version 1.13.1 was released this morning (update from the store in about an hour), but it won’t add any features by itself. For me to fix the mapping for your model, I need two lines of integration logs, after an update and then a scan in Discovery:
the line starting with [Tuya][discovery] « F14-W » (it indicates features=1 and the UNMANAGED=[…] list of codes I don’t handle yet);
the full [Tuya][poll][local] device=… DPS snapshot: … line (the one you sent is cut off after the identifier).

Send them without the local key or your IP if they appear next to it. With that, I’ll try to release a corrected version right away.

Hi @GBoulvin,

Oh damn! Sorry, so I’m surprised by the mess. Claude is trying something, but I’m not sure it will help… I’ll forward his message to you :sweat_smile:

Thanks for the logs, they say it all, and no, it’s not on the core side.
The scene is indeed triggered (your capture « Ring: a few seconds ago » confirms it). What fails are your three actions « send the image »: the integration was pulling the ring before finishing downloading the photo (1.2s difference in your logs). The scene therefore requested the image too early. Before, you actually retrieved the photo from the previous ring without noticing; this morning’s update restarted the container, cleared the cache, and the error became visible.
Fixed in 1.13.2 (available in the store in about an hour): the photo is published first, the ring second, and an image request during download waits instead of failing. After the update, press the doorbell once to prime it, then the scene should send the correct photo of the visitor.

I retrieved this.

[2026-09-03T22:31:25.479Z] [INFO] [tuya] [Tuya][discovery] "F14-W" id=************** type=pet-feeder product_id=*************** category=cwwsq features=1 UNMANAGED=[meal_plan_num, battery_val, meal_plan2, feed_record, vip_alarm, battery_alarm]
[2026-09-03T22:31:25.480Z] [WARN] [tuya] Tuya function with "basic_indicator" code is not managed
[2026-09-03T22:31:25.481Z] [WARN] [tuya] Tuya function with "motion_record" code is not managed
[2026-09-03T22:31:25.481Z] [WARN] [tuya] Tuya function with "motion_interval" code is not managed
[2026-09-03T22:31:25.481Z] [WARN] [tuya] Tuya function with "record_switch1" code is not managed
[2026-09-03T22:31:25.482Z] [WARN] [tuya] Tuya function with "decibel_upload" code is not managed
[2026-09-03T22:31:25.482Z] [WARN] [tuya] Tuya function with "ipc_mute_record" code is not managed
[2026-09-03T22:31:25.482Z] [WARN] [tuya] Tuya function with "ipc_detection_area" code is not managed
[2026-09-03T22:31:25.482Z] [WARN] [tuya] Tuya function with "multi_motion_area" code is not managed

Thanks, that’s exactly what was needed. Your dispenser is a variant: it doesn’t expose the standard codes I built the support for (feed_report, slow_feed, battery_percentage…) but others (feed_record, battery_val, battery_alarm…). Only the dispensing button is common, hence a single functionality.

I prefer not to blindly map (displaying a battery at « 2957 % » wouldn’t help you). I just released 1.13.3 which adds the last missing info: update from the store within an hour, wait a minute, then send me in a PM the line containing [Tuya][poll][cloud] and status snapshot for your dispenser (it only appears once, on the first reading after the restart). With that, I’ll release the support for your model right away: last meal, battery, alarms.

The basic_indicator / motion_record lines you copied come from a camera, not the dispenser, you can ignore them.

:bell: Tuya (external integration) — v1.20.0: 6 new device types + integration in 4 languages

Hello everyone :waving_hand:

Since v1.11.0, the Tuya external integration has evolved a lot: here’s the recap up to v1.20.0, which has just been released.

:sparkles: New supported devices

  • Robot vacuum cleaners (Honiture Q6 Pro): start/stop, pause, return to base, status, battery, suction power, water level, modes, brush wear.
  • Pet feeders (category cwwsq, including the F14-W): on-demand distribution, last served quantity, battery, scheduled meals.
  • Fans / Double-flow VMC (category fs, e.g. AV-TTW5-W): on/off, speed, light, child lock, airflow direction, oscillation.
  • Dehumidifiers (category cs, e.g. Qlima D825A): humidity, temperature, speed, timer, mode, target humidity, child lock.
  • Temperature / Humidity sensors (category wsdcg, e.g. Konyks Termo): temperature, humidity, low battery.
  • Water osmosis / purifiers (category js, e.g. The Box): TDS input/output, remaining life of each filter (PP, CTO, RO) in % and days, operating status.

:globe_showing_europe_africa: Integration in French, English, German, and Spanish

  • New option « Feature Names »: the names and option labels of newly discovered devices in French, English, German, or Spanish. A big thank you to @spenceur for the PR! :folded_hands:
  • The entire integration is now translated into Gladys’ 4 languages: configuration, actions, connection messages, Cloud badge tooltips, and documentation.

:hammer_and_wrench: Tools and fixes

  • « Device Diagnostic » action: having trouble with a device that’s not recognized or not working properly? Run the action, copy the result into a GitHub issue, and I can add it. The report does not contain local keys, IP addresses, or Tuya identifiers.
  • Air conditioners: the Heating and Ventilation modes are now selectable again.
  • Doorbells: the visitor’s photo arrives before the ring (useful for sending it in a scene).

:warning: Prerequisites

  • Gladys ≥ 4.86.1 for a new installation from the store (and for the vacuum cleaner’s suction power / water level).
  • An already installed integration continues to update on any version of Gladys.

:counterclockwise_arrows_button: Already created devices

  • New device types: simply run a discovery again.
  • The « Feature Names » option does not rename already created features: only the labels in the lists (e.g. suction power) follow the new language in the next discovery. For names: rename manually, or delete and recreate the device.

:test_tube: Feedback welcome

These points are of particular interest to me:

  • Dehumidifier, water osmosis, Konyks Termo sensor, and F14-W feeder: does everything come back correctly, and do the commands work?
  • Feature names in German / Spanish for those who use Gladys in these languages.

The details of each version are in the changelog: gladys-tuya/CHANGELOG.md at master · Terdious/gladys-tuya · GitHub

Thanks in advance for your feedback :folded_hands:

:wrench: v1.21.0 — Fix for air conditioners set to °F

A small bugfix update right after 1.20.0:

  • Air conditioners with the screen set to °F: The ambient temperature is no longer divided by 10 on models that send whole degrees (24 °C was displayed as “2.4”), and the setpoint as well as the ambient temperature are no longer labeled °F when the device sends °C. Gladys now correctly converts to the unit you have chosen.
  • Nothing changes for air conditioners set to °C or for other devices.

:backhand_index_pointing_right: If your air conditioner is affected: delete it and recreate it from the Discovery tab, so that it takes the correct unit.

:memo: Project news: each version now has its release notes on GitHub, and all the details are in the changelog.

Thanks to @Lucid_Wray for their very precise bug report :folded_hands:

:snowflake: v1.22.0 — exotic air conditioners (ex. MEDION P502)

New version for Tuya air conditioners that don’t speak standard vocabulary:

  • Modes: Recognized regardless of how they are written (COOL, cool, cold…), and sent exactly as the device expects them. No more air conditioners stuck in a mode.
  • Fan speed: Air conditioners that declare their speeds as simple levels (“1”, “2”…) now display Low / High (up to 5 levels), instead of a list of 8 choices with no effect.
  • Swing: The on/off sweep (Shake) appears as an “Oscillation” switch, both in the cloud and locally.

Nothing changes for air conditioners that were already working. If yours is affected, restart a discovery (or delete and recreate the air conditioner) so that it takes into account its own vocabulary.

Thanks to VV69004, whose well-documented work on the MEDION P502 made it possible to integrate all this properly for everyone :folded_hands:

:droplet: v1.23.0 and v1.24.0 — Sprinkler valves, device lists, and reliability

New Features

  • Sprinkler valves / Tuya timers (category sfkzq, e.g. R2601): open/close, valve status (water flowing or not), instant flow rate, battery, child lock, watering mode (auto/manual), manual watering duration. They use Gladys’ « water valve » category. Watering programs remain in the Tuya app for now.
  • Dropdown lists in actions: “Detect local protocol” and “Device diagnostics” now offer a list of your devices. A second field still accepts a name or Tuya ID for a device not yet created in Gladys.
  • More comprehensive diagnostics: it also indicates the range, unit, and scale of each numerical value. This is how the valve could be added in one version.

Reliability

  • A brief disconnection between Gladys and the integration no longer restarts the entire cloud connection or a full network scan.
  • Manual detection of the local protocol can no longer be canceled by a discovery launched at the same time.
  • Cleaner shutdown: local connections to devices are closed before the container is stopped.

:backhand_index_pointing_right: Valve already added: “Update” button in the Discovery tab (or delete it and recreate it) to get its new features.

:camera: Call to Tuya PTZ camera owners (@GBoulvin :wink:)

Gladys can now control motorized cameras (movements, zoom, saved positions), and I would like to add them to Tuya cameras (LSC PTZ…). I just need the result of the “Device diagnostics” action (Integration Configuration tab, choose the camera from the list): paste it here or in issue #26. The report contains no local key, IP address, or Tuya ID.

Details are in the changelog. Thanks for your feedback :folded_hands:

Here is the first one, dual band:

Tuya device diagnostic — "Living Room Camera"
model=LSC PTZ Camera Dualband product_id=rogprwflblumx2co category=sp
detected type=camera mapped features=8

Cloud status (24 codes):
  alarm_message = undefined  [ignored on purpose]
  basic_flip = false  [switch/binary]
  basic_nightvision = "0"  [ignored on purpose]
  basic_osd = true  [ignored on purpose]
  basic_private = false  [switch/binary]
  decibel_sensitivity = "0"  [ignored on purpose]
  decibel_switch = false  [ignored on purpose]
  humanoid_filter = false  [switch/binary]
  motion_area = "{"num":1,"region0":{"x":0, "y":0, "xlen":100, "ylen":100 }}"  [ignored on purpose]
  motion_area_switch = false  [ignored on purpose]
  motion_sensitivity = "1"  [ignored on purpose]
  motion_switch = false  [switch/binary]
  motion_tracking = false  [switch/binary]
  movement_detect_pic = <snapshot payload>  [motion-sensor/binary]
  ptz_calibration = false  [ignored on purpose]
  ptz_control = "7"  [ignored on purpose]
  ptz_stop = true  [ignored on purpose]
  record_mode = "1"  [ignored on purpose]
  record_switch = true  [switch/binary]
  sd_format = true  [ignored on purpose]
  sd_format_state = 0  [ignored on purpose]
  sd_status = 5  [ignored on purpose]
  sd_storge = "0|0|0"  [ignored on purpose]
  siren_switch = false  [siren/binary]

Declared enum ranges:
  basic_nightvision: 0, 1, 2 (functions+status+model)
  decibel_sensitivity: 0, 1 (functions+status+model)
  motion_sensitivity: 0, 1, 2 (functions+status+model)
  ptz_control: 1, 2, 3, 4, 5, 6, 7, 0 (functions+status+model)
  record_mode: 1, 2 (functions+status+model)

LAN DPS snapshot: unavailable (Local poll timeout).

This report contains no local key, IP address nor Tuya device id: it can be pasted as-is in a GitHub issue

And the second one (LSC as well, older)

Tuya device diagnostic — "Entrance Camera"
model=LSC PTZ Camera product_id=n7h0m2x7i2yzol0p category=sp
detected type=camera mapped features=8

Cloud status (23 codes):
  alarm_message = undefined  [ignored on purpose]
  basic_anti_flicker = "1"  [UNMANAGED]
  basic_flip = false  [switch/binary]
  basic_nightvision = "0"  [ignored on purpose]
  basic_osd = true  [ignored on purpose]
  basic_private = false  [switch/binary]
  decibel_sensitivity = "0"  [ignored on purpose]
  decibel_switch = false  [ignored on purpose]
  humanoid_filter = false  [switch/binary]
  motion_sensitivity = "0"  [ignored on purpose]
  motion_switch = false  [switch/binary]
  motion_tracking = false  [switch/binary]
  movement_detect_pic = <snapshot payload>  [motion-sensor/binary]
  ptz_calibration = false  [ignored on purpose]
  ptz_control = "5"  [ignored on purpose]
  ptz_stop = true  [ignored on purpose]
  record_mode = "2"  [ignored on purpose]
  record_switch = true  [switch/binary]
  sd_format = true  [ignored on purpose]
  sd_format_state = 0  [ignored on purpose]
  sd_status = 1  [ignored on purpose]
  sd_storge = "30272512|15700992|14571520"  [ignored on purpose]
  siren_switch = false  [siren/binary]

Declared but not reported: initiative_message

Declared enum ranges:
  basic_anti_flicker: 0, 1, 2 (functions+status+model)
  basic_nightvision: 0, 1, 2 (functions+status+model)
  decibel_sensitivity: 0, 1 (functions+status+model)
  motion_sensitivity: 0, 1, 2 (functions+status+model)
  ptz_control: 1, 2, 3, 4, 5, 6, 7, 0 (functions+status+model)
  record_mode: 1, 2 (functions+status+model)

LAN DPS snapshot:
  109="30272512|15700992|14571520" (UNMAPPED)

This report contains no local key, IP address nor Tuya device id: it can be pasted as-is in a GitHub issue.