Integración externa - Tuya

Parecía que… :innocent:

Me habías anunciado que este distribuidor debía exponer.
Tu F14-W debería entonces exponer:
• Distribuir — un botón que da una porción (utilizable en una escena,
por ejemplo todos los días a las 8h)
• Última cantidad distribuida
• Distribución lenta
• Indicador
• Batería
Creo que no has visto mi respuesta.
El distribuidor no expone todo lo que debería, solo el botón de distribución.

Por lo que me pediste, encontré esto.

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

¡Hola!

Tengo un problema con la acción ‹ sonnette sonne ›.

La acción aparece bien, bien detectada pero la escena no se activa…

Sin embargo, ¡funcionó!

Nada especial en los registros. Tengo la impresión de que es más del lado del núcleo…

[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)

Edición:

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)

Por lo tanto, sí, en los registros hay el hecho de que envío tres veces el instantánea y que no existe… Bueno, ¿todavía no?

Edición 2: Soy tonto… Configuré la integración externa de Telegram y no se modificó en la escena que enviaba el mensaje a través de una voz/vía inexistente…

Hola @elfedagger, disculpa por la demora.
De hecho no vi tu respuesta anterior.

Tu distribuidor probablemente no expone los mismos códigos Tuya que el modelo en el que me basé. Esperaba que fuera mejor que esto, lo siento.

La versión 1.13.1 se lanzó esta mañana (actualiza desde la tienda en una hora), pero no creará características adicionales por sí misma. Para que yo corrija el mapeo para tu modelo, necesito dos líneas de registro de la integración, después de una actualización y luego un escaneo en Descubrimiento:
la línea que comienza con [Tuya][discovery] « F14-W » (indica features=1 y la lista UNMANAGED=[…] de los códigos que aún no manejo);
la línea completa [Tuya][poll][local] device=… DPS snapshot: … (la que enviaste está cortada después del identificador).

Envíalas sin la clave local ni tu IP si aparecen al lado. Con eso intentaré sacar una versión corregida de inmediato.

Hola @GBoulvin,

¡Vaya! Lo siento, entonces me sorprende el desvarío, Claude intenta algo, pero no estoy seguro de que lo arregle… te transmito su mensaje :sweat_smile:

Gracias por los registros, lo dicen todo, y no, no es del lado del núcleo.
La escena se activa correctamente (tu captura « Sonido: hace unos segundos » lo confirma). Lo que falla son tus tres acciones « enviar la imagen »: la integración tiraba del sonido antes de terminar de descargar la foto (1,2 segundos de diferencia en tus registros). La escena, por lo tanto, pedía la imagen demasiado pronto. Antes, en realidad recuperabas la foto del timbre anterior sin darte cuenta; la actualización de esta mañana reinició el contenedor, borró la caché y el error se hizo visible.
Corregido en la 1.13.2 (disponible en la tienda en una hora): la foto se publica primero, el sonido después, y una solicitud de imagen durante la descarga espera en lugar de fallar. Después de la actualización, pulsa el timbre una primera vez para iniciar, luego la escena debe enviar la foto correcta del visitante.

Lo he recuperado.

[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
[2026-09-03T22:31:21.250Z] [INFO] [tuya] [Tuya][poll][local] device=************** DPS snapshot: 4="standby" (UNMAPPED) | 106=2957 (UNMAPPED) | 108="7f0800317f143021" (UNMAPPED) | 112="{"value":2,"type":2}" (UNMAPPED) | 113=0 (UNMAPPED) | 114=0 (UNMAPPED)

Gracias, es exactamente lo que necesitaba. Tu distribuidor es una variante: no expone los códigos estándar sobre los que construí el soporte (feed_report, slow_feed, battery_percentage…) sino otros (feed_record, battery_val, battery_alarm…). Solo el botón de distribución es común, por lo que solo hay una funcionalidad.

Prefiero no mapear a ciegas (mostrar una batería al « 2957 % » no te ayudaría). Acabo de lanzar la 1.13.3 que añade la última información faltante: actualiza desde la tienda en una hora, espera un minuto y luego envíame por mensaje privado la línea que contiene [Tuya][poll][cloud] y status snapshot para tu distribuidor (solo aparece una vez, en la primera lectura después del reinicio). Con eso, sacaré el soporte de tu modelo de inmediato: última comida, batería, alarmas.

Las líneas basic_indicator / motion_record que copiaste provienen de una cámara, no del distribuidor, puedes ignorarlas.

:bell: Tuya (integración externa) — v1.20.0: 6 nuevos tipos de dispositivos + integración en 4 idiomas

¡Hola a todos! :waving_hand:

Desde la v1.11.0, la integración externa de Tuya ha avanzado mucho: aquí tienes un resumen hasta la v1.20.0, que acaba de salir.

:sparkles: Nuevos dispositivos soportados

  • Robots aspiradores (Honiture Q6 Pro): inicio/parada, pausa, regreso a la base, estado, batería, potencia de succión, nivel de agua, modos, desgaste de las escobillas.
  • Distribuidores de croquetas (categoría cwwsq, incluyendo el F14-W): distribución a demanda, última cantidad servida, batería, comidas programadas.
  • Ventiladores / VMC de doble flujo (categoría fs, ej. AV-TTW5-W): encendido/apagado, velocidad, luz, seguridad infantil, dirección del flujo de aire, oscilación.
  • Deshumidificadores (categoría cs, ej. Qlima D825A): humedad, temperatura, velocidad, temporizador, modo, humedad objetivo, seguridad infantil.
  • Sensores de temperatura / humedad (categoría wsdcg, ej. Konyks Termo): temperatura, humedad, batería baja.
  • Ósmosis / purificadores de agua (categoría js, ej. The Box): TDS entrada/salida, vida restante de cada filtro (PP, CTO, RO) en % y en días, estado de funcionamiento.

:globe_showing_europe_africa: La integración en francés, inglés, alemán y español

  • Nueva opción « Nombres de las funciones »: los nombres y los textos de las opciones de los dispositivos recién descubiertos en francés, inglés, alemán o español. ¡Muchas gracias a @spenceur por la PR! :folded_hands:
  • Toda la integración ahora está traducida a los 4 idiomas de Gladys: configuración, acciones, mensajes de conexión, globos de información del badge Cloud y documentación.

:hammer_and_wrench: Herramientas y correcciones

  • Acción « Diagnóstico de un dispositivo »: ¿Un dispositivo no reconocido o mal reconocido? Ejecuta la acción, copia el resultado en una issue de GitHub, y puedo agregarlo. El informe no contiene ni clave local, ni IP, ni identificador de Tuya.
  • Aire acondicionado: los modos Calentamiento y Ventilación son nuevamente seleccionables.
  • Timbres: la foto del visitante llega antes del timbre (útil para enviarla en una escena).

:warning: Requisitos previos

  • Gladys ≥ 4.86.1 para una nueva instalación desde la tienda (y para la potencia de succión / nivel de agua del aspirador).
  • Una integración ya instalada continúa actualizándose en cualquier versión de Gladys.

:counterclockwise_arrows_button: Dispositivos ya creados

  • Los nuevos tipos de dispositivos: simplemente reinicia un descubrimiento.
  • La opción « Nombres de las funciones » no renombra las funciones ya creadas: solo los textos de las listas (ej. potencia de succión) siguen el nuevo idioma en el siguiente descubrimiento. Para los nombres: renombra manualmente, o elimina y vuelve a crear el dispositivo.

:test_tube: Comentarios bienvenidos

Estos puntos me interesan especialmente:

  • Deshumidificador, ósmosis, sensor Konyks Termo y distribuidor F14-W: ¿todo se reporta bien y las órdenes funcionan?
  • Los nombres de las funciones en alemán / español, para quienes usan Gladys en estos idiomas.

El detalle de cada versión está en el changelog: gladys-tuya/CHANGELOG.md at master · Terdious/gladys-tuya · GitHub

¡Gracias de antemano por sus comentarios! :folded_hands:

:wrench: v1.21.0 — corrección de aire acondicionado configurado en °F

Pequeña actualización correctiva justo después de la 1.20.0:

  • Aire acondicionado con pantalla configurada en °F: la temperatura ambiente ya no se divide por 10 en los modelos que envían grados enteros (se mostraba « 2,4 » en lugar de 24 °C), y la temperatura de consigna y la temperatura ambiente ya no se etiquetan como °F cuando el dispositivo envía °C. Gladys ahora convierte correctamente a la unidad que has elegido.
  • No hay cambios para los aires acondicionados configurados en °C ni para otros dispositivos.

:backhand_index_pointing_right: Si tu aire acondicionado está afectado: elimínalo y recréalo desde la pestaña Descubrimiento, para que vuelva a tomar la unidad correcta.

:memo: Novedad en el proyecto: cada versión ahora tiene sus notas de versión en GitHub, y todos los detalles están en el registro de cambios.

Gracias a @Lucid_Wray por su informe de error muy preciso :folded_hands:

:snowflake: v1.22.0 — climatizadores « exóticos » (ej. MEDION P502)

Nueva versión para los climatizadores Tuya que no hablan el vocabulario estándar:

  • Modos: reconocidos independientemente de cómo estén escritos (COOL, cool, cold…), y enviados exactamente como el dispositivo los espera. Se acabó el bloqueo del aire acondicionado en un modo.
  • Velocidad del ventilador: los aires acondicionados que declaran sus velocidades en niveles simples (« 1 », « 2 »…) ahora muestran Baja / Alta (hasta 5 niveles), en lugar de una lista de 8 opciones sin efecto.
  • Oscilación: el modo de balanceo encendido/apagado (Shake) aparece como un interruptor « Oscilación », tanto en la nube como en local.

Nada cambia para los aires acondicionados que ya funcionaban. Si el suyo está afectado, reinicie un descubrimiento (o elimine y vuelva a crear el aire acondicionado) para que tenga en cuenta su propio vocabulario.

Gracias a VV69004, cuyo trabajo bien documentado sobre la MEDION P502 permitió integrar todo esto de manera adecuada para todos :folded_hands:

:droplet: v1.23.0 y v1.24.0 — válvulas de riego, listas de dispositivos y fiabilidad

Novedades

  • Válvulas de riego / programadores Tuya (categoría sfkzq, ej. R2601): apertura/cierre, estado de la válvula (si el agua fluye o no), caudal instantáneo, batería, bloqueo infantil, modo de riego (automático/manual), duración de riego manual. Utilizan la categoría «válvula de agua» de Gladys. Los programas de riego siguen en la aplicación Tuya por ahora.
  • Listas desplegables en las acciones: «Detectar el protocolo local» y «Diagnóstico de un dispositivo» ahora muestran la lista de tus dispositivos. Un segundo campo sigue aceptando un nombre o un identificador Tuya para un dispositivo que aún no se ha creado en Gladys.
  • Diagnóstico más completo: también indica el rango, la unidad y la escala de cada valor numérico. Es gracias a esto que la válvula pudo ser añadida en una versión.

Fiabilidad

  • Una desconexión breve entre Gladys y la integración ya no reinicia toda la conexión en la nube ni un escaneo completo de la red.
  • La detección manual del protocolo local ya no puede ser cancelada por un descubrimiento lanzado al mismo tiempo.
  • Cierre más limpio: las conexiones locales a los dispositivos se cierran antes de detener el contenedor.

:backhand_index_pointing_right: Válvula ya añadida: botón «Actualizar» en la pestaña Descubrimiento (o elimínala y recréala) para obtener sus nuevas funcionalidades.

:camera: Llamada a los poseedores de cámaras PTZ Tuya (@GBoulvin :wink:)

Gladys ahora puede controlar las cámaras motorizadas (movimientos, zoom, posiciones guardadas), y me gustaría añadirlo a las cámaras Tuya (LSC PTZ…). Solo necesito el resultado de la acción «Diagnóstico de un dispositivo» (pestaña Configuración de la integración, elige la cámara en la lista): pégalo aquí o en la issue #26. El informe no contiene ni clave local, ni dirección IP, ni identificador Tuya.

El detalle está en el changelog. ¡Gracias por vuestros comentarios :folded_hands:!

Aquí está la primera, de doble banda:

Tuya device diagnostic — "Cámara salón"
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

Y la segunda (LSC también, más antigua)

Tuya device diagnostic — "Cámara entrada"
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.