Skip to main content

Tuya / Smart Life (Cloud)

Cloud bridge for any device paired in the Tuya, Smart Life, Brilliant, Geeni, Treatlife, or other Tuya-white-label apps. One device row represents a Tuya IoT Platform project; each Tuya device exposed to that project becomes a GEM zone keyed by the Tuya device id. The same project can front a single home's couple of smart plugs or hundreds of devices across a property — the Tuya Cloud OpenAPI is one of the largest device platforms in the world by install base and is a common request for retrofit installs that already have Tuya hardware in place.

Prerequisites

  • A Tuya IoT Platform account at https://iot.tuya.com.
  • A Cloud Development project (Cloud → Development → Create Cloud Project) with the IoT Core service enabled (the free tier is enough for control + status).
  • The Smart Life / Tuya end-user account that owns the physical devices linked into the project under Devices → Link Tuya App Account.
  • The project Data Center matched to the linked account's region (Tuya supports US, EU, China, India). Mismatched regions silently return empty device lists.

Setup

  1. In the Tuya IoT Platform, open Cloud → Development → <your project> → Authorization Key. Copy the Access ID and Access Secret.
  2. In GEM, go to System → Devices → Add Device (Open Devices) and pick the Tuya / Smart Life (Cloud) driver. Paste the Access ID into client_id and the Access Secret into password (stored encrypted).
  3. Set region to the project Data Center: us, eu, cn, or in. Use api_base only when Tuya has migrated your account to a per-customer endpoint.
  4. (Optional) Set uid to the linked Smart Life user id (Devices → Link Tuya App Account → UID column). If uid is blank, the driver falls back to the project-wide device list endpoint, which returns only the first 50 devices — set uid for any site with more than ~50 Tuya devices.
  5. Run get_devices to enumerate Tuya devices visible to the project. Each entry returns id, name, category, product_id, plus the dp code map.
  6. Create a zone per device. zone.address = the 20-character Tuya device id (e.g. bf6c...e3a1).
Subsystem placement

GEM does not auto-create zones for Tuya devices — add one zone per device by hand. Put each zone in the subsystem that matches what the device physically is: Lights for bulbs, Power for plugs and wall switches, Shades for curtains/blinds, Climate for thermostats, Fans for fans. Use on/off/set_level/set_color/set_ct for lights and plugs and open/close/stop for shade/curtain devices.

Device attributes

AttributeRequiredDescription
client_idyesTuya project Access ID.
passwordyesTuya project Access Secret. Stored encrypted.
regionno (default us)Tuya regional data center: us, eu, cn, in.
api_basenoOverride the regional endpoint URL.
uidnoLinked Smart Life / Tuya user id. Without it the driver uses the project-wide device list endpoint.
status_intervalno (default 30000 ms)Polling cadence for /devices/<id>/status. Free-tier projects rate-limit at roughly 60 requests/min — keep this at 30 s or above for accounts with more than a handful of devices.
request_timeoutno (default 10000 ms)Per-request HTTP timeout.

Zone attributes

AttributeDescription
addressTuya device id from get_devices.
power_codeOverride the on/off data point code. Common values: switch_led (bulbs), switch_1 (multi-gang switches), switch (single-relay plugs). Auto-detected on first command if blank.
level_codeOverride the brightness dp. Common: bright_value_v2 (newer), bright_value (older).
level_rangePer-zone [min, max] integer range for brightness. Defaults to [10, 1000]. Get the right range from get_specifications.
ct_codeOverride CT dp. Common: temp_value_v2.
ct_range[min, max] for CT. Defaults to [0, 1000].
color_codeOverride HSV color dp. Common: colour_data_v2.
control_codeFor shades / curtains: override the dp used for open/close/stop. Defaults to control.

State the driver reports back

On every status poll (and after each command that succeeds) the driver writes live state onto the zone, so you can drive triggers, tiles, and history off it:

AttributeDescription
stateon / off resolved from the device's power dp. For zones in a subsystem with relay-state semantics (e.g. gates, doors, garages), the value is mapped to that subsystem's state words.
levelBrightness scaled back to 0-100 from the device's level_range. Written only when the device exposes a brightness dp.
battery_level0-100 from the device's battery_percentage / battery dp, for battery-powered Tuya devices (sensors, locks). Written only when the device reports a battery dp.

These names are cataloged, so they autocomplete in the Attribute editor and can be referenced directly in attribute triggers.

Zone address format

A 20-character Tuya device id, lower-case hexadecimal. Obtain via the get_devices command — each entry returns id, name, category, product_id, plus the dp code map.

Supported commands

CommandMapping
on / offAuto-resolves the power dp from zone.power_code or the status response, then `POST /commands { commands: [{code, value: true
toggleReads /status, flips the power dp.
set_levelbright_value_v2 scaled from GEM 0-100 to the device's level_range (default [10, 1000]).
set_cttemp_value_v2 scaled from GEM 0-100 to the device's ct_range (default [0, 1000]).
set_colorConverts RRGGBB hex to Tuya HSV {h: 0-360, s: 0-1000, v: 0-1000} and sends via colour_data_v2.
open / close / stopcontrol dp with the verb name (Tuya convention for shades / curtains).
get_devicesLists devices visible to the project. With uid set it returns the full linked-account list via /v1.0/users/<uid>/devices; without uid it returns the project-wide list via /v1.3/iot-03/devices, capped at the first 50 devices (no paging).
get_statusReads /v1.0/iot-03/devices/<id>/status — the dp value array.
get_specificationsReads /v1.0/iot-03/devices/<id>/specifications — the dp catalog with codes, types, and value ranges. Use this to populate level_range / ct_range for a specific product.
refresh_tokenForce a token refresh.
raw_commandSend any dp value: {code, value}. value accepts primitives or JSON for HSV / scene blobs.
raw_requestPass-through to any /v1.x Tuya endpoint with full signing. Useful for scenes, automations, schedule queries.

What we don't yet support

  • Tuya Cloud pulsar message stream (real-time push). The driver polls /status per zone; for sub-second updates you'd need a WebSocket subscription to Tuya's message service, which requires a paid tier and a separate transport.
  • Scene execution beyond raw_request. Scenes are project-scoped under /v2.0/cloud/scene/rule — easily reachable via raw_request but no first-class command surface.
  • Automatic dp range discovery. set_level defaults to [10, 1000]; for devices that use a different range, set zone.level_range from the get_specifications output until per-zone auto-detection is wired.
  • IR-blaster sub-devices (Tuya treats them as a parent IR hub + virtual children). The driver currently surfaces only the parent.

Troubleshooting

  • sign invalid. Clock skew between the GEM host and Tuya's servers exceeds 60 seconds. Run timedatectl status and confirm NTP is healthy.
  • get_devices returns empty. Most often the project Data Center doesn't match the Smart Life account's region — us projects can't see eu accounts. Double-check Devices → Link Tuya App Account shows the account as linked.
  • HTTP 401 / token invalid. The Access Secret was rotated in the Tuya IoT Platform, or the project's IoT Core service has expired (free tier auto-renews but lapsed projects do happen). The driver auto-retries once with a fresh token on a 401 or on Tuya result code 1010 (token expired/invalid); if it persists, run refresh_token manually.
  • get_devices shows fewer devices than the account has. Without uid, the project-wide list is capped at the first 50 devices. Set uid to the linked Smart Life account id (Devices → Link Tuya App Account → UID) to enumerate the full account.
  • Command returns success: true but the device doesn't change. The dp code is wrong for this product. Run get_status — the live dp codes will be in the response. Set zone.power_code / zone.level_code to the right code and try again.
  • Rate limit errors (code: 28841105 or similar). You're polling too aggressively for a free-tier project. Bump status_interval to 60000 and shrink the zone count under a single Tuya project, or upgrade the project tier.
  • Devices — add and configure the Tuya project device.
  • Zones — create one zone per Tuya device, placed in the matching subsystem.
  • Subsystems — the Lights / Power / Shades / Climate / Fans subsystems these zones belong to.
  • Commands — the command grid and Test runner for on/off, set_level, set_color, get_devices, get_specifications, raw_command, and raw_request.