Version 1.0.230 · Local WiFi/LAN control of Tuya smart devices — no cloud, no Zigbee hub required.
All communication happens over your local network via the Tuya LAN protocol. Twenty-two built-in drivers cover the most common device types; a fully generic driver handles anything else.
| Driver | Typical devices | Device class |
|---|---|---|
| Dehumidifier | Dehumidifiers, air dryers | Dehumidifier |
| Smart Plug | Smart plugs with energy monitoring | Socket |
| Air Conditioner | Any Tuya local LAN air conditioner | Air Conditioner |
| Fan | Ceiling fans, table fans, tower fans | Fan |
| Ceiling Fan Light | Ceiling fans with a built-in light (fan + light on one device) | Light |
| Humidifier | Humidifiers, aroma diffusers | Humidifier |
| Heater | Panel heaters, convectors, oil radiators | Heater |
| Light | Bulbs, LED strips, ceiling lights | Light |
| Pet Feeder | Automatic pet feeders (e.g. WOFEA, Mypin, PETKIT) | Pet Feeder |
| Garage Door | Garage door openers (WOFEA, AOSD, ZC34T, BoboYun gatePro) | Garage Door |
| Heat Pump | Pool / air-water heat pumps (Phalén, Fairland, Brustec, BWT, Waterco, …) | Heat Pump |
| Curtain Motor | Curtain / blind / roller motors (Zemismart v1 & v2 and compatible) | Blinds |
| Thermostat | Floor heating, room thermostats, TRVs, zone valves | Thermostat |
| Smart Kettle | Smart kettles with temperature control | Kettle |
| Wall Switch | 1/2/3/4-gang WiFi wall switches | Socket |
| Doorbell | Tuya video doorbells (Marmitek Buzz LO, Bcom Majic IPBox, Cleverio CD-200 and compatible) | Doorbell |
| Presence Sensor | mmWave radar presence sensors (ZY-M100-WIFI and compatible) | Sensor |
| Smoke Detector | Tuya WiFi smoke detectors, category ywbj |
Smoke Detector |
| Energy Meter | DIN-rail meters, clamp meters and metering breakers (zndb, dlq) |
Sensor |
| Weather Station | WiFi weather stations with outdoor sensors (temperature, humidity, pressure, wind, rain) | Sensor |
| Ultrasonic Level Sensor | Tank and cistern level sensors with configurable alarm thresholds | Sensor |
| EV Charger | Tuya EV chargers, category qccdz (Vevor, Nine, Tera, Emini, Aimiler, Ecopoint, Dowell, Feyree, AfyeEV, Junsun, Zencar, iPengen, Suntree, Immax, Voldt, Wadapower and other rebrands) |
EV Charger |
| Generic Tuya Device | Any Tuya device not covered above | Other |
A Face Access Panel driver also exists but is deprecated: these panels keep their user database, unlocking and event reporting behind the Tuya cloud, and the local protocol exposes too little to control one usefully. Existing devices keep working; the driver no longer appears when adding a device.
- Cloud-free — all traffic stays on your local network
- Real-time push — instant state updates without polling (polling is optional and configurable)
- Automatic reconnect — exponential back-off with jitter; watchdog detects stale connections and reconnects
- Protocol detection — three things happen before anything is guessed. Every Tuya frame but 3.2 carries its version as plain text at the start of its payload, so a frame that cannot be decoded is still read for that and the connection switches straight to it — the device's own statement about itself, not an inference. A version under which packets have actually been decoded then sticks: those prove the framing and the key, and no run of failures gives that up short of a firmware change. Only where neither applies does the connection cycle through the fallbacks (3.3 → 3.4 → 3.1 → 3.5 → 3.2) after 5 consecutive failures. An open socket alone never counts as proof: 3.1, 3.2 and 3.3 have no session handshake, so a device speaking a different version accepts the socket and then resets it. Whatever version settles is written into the device settings, so the next reconnect starts there
- Stale-connection watchdog — a second watchdog beside the heartbeat, watching for something the heartbeat cannot see: firmware that keeps answering keep-alive pings while it has stopped answering everything else. That state used to look perfectly healthy — and on protocol 3.4/3.5, where a SET is fire-and-forget, commands into it reported success while the device did not move. A device that has sent no data for three polling cycles (at least 90 s) is now reconnected
- Command pacing — a configurable minimum gap between two commands to the same device (Command Gap, default 100 ms). Some firmware accepts the first command of a pair and silently drops the second when they arrive microseconds apart, which nothing on 3.4/3.5 reports as an error
- Outbound heartbeat — sends a keep-alive ping every 15 s; keeps connections alive on strict firmware that requires host-initiated keep-alives
- Push-only device support — devices that don't respond to GET requests (e.g. BCM700D-TY01 curtain motors) stay connected and accept SET commands without entering a reconnect loop; set Polling Interval to 0 for these devices
- Cloud Lookup — fetch Device ID and Local Key from the Tuya IoT Platform inside the app settings or directly during device pairing — no CLI tools needed. Device names show your custom name (as set in the Tuya app) as the primary label. Click a device name to see all DPs with types, current values, and allowed ranges. Access credentials are saved on Homey and auto-filled next time
- Protocol auto-detect — pairing and repair default to Auto-detect, which tries 3.3 → 3.4 → 3.1 → 3.5 → 3.2 in order and saves the working version automatically
- Network scanner — finds Tuya devices via UDP broadcast (ports 6666 / 6667) and a full TCP subnet scan (port 6668)
- Auto DP detection — on pairing, the app connects to the device, collects live data points and maps them to capabilities automatically
- Cloud-assisted DP detection — once Cloud Lookup credentials are saved, pairing additionally reads the device's Tuya specification and matches DPs by the manufacturer's own code names (
envhumid,windspeed,work_state,bright_value, …) instead of guessing from value shape. It also picks up the full list of allowed values for mode and fan-speed pickers rather than only the value the device happens to report at that moment — which is what makes devices with plain numeric enums (0/1) work out of the box. Entirely optional - Energy dashboard integration — drivers that measure power feed Homey's energy dashboard; the EV Charger additionally exposes
target_powerso Homey's energy management can steer the charge rate (e.g. solar-surplus charging) - Inline DP editor — every DP number can be adjusted in the pairing screen before adding the device
- Optional capabilities — tiles are added or removed dynamically based on your DP settings; set a DP to
0to hide the tile - Live credential updates — change IP address, Local Key or Protocol Version directly in device settings at any time without re-pairing
- Computed energy metering — kWh accumulated from live power readings using trapezoidal integration; persisted across restarts
- Push notifications — Homey notifications for water tank events, fault alarms and other device alerts
- Efficient polling — alternates between full GET and lightweight dp_refresh to reduce traffic
- Fix It tab — five checks that compare your devices against what Tuya declares and offer to correct them: stale local keys, wrong protocol version, wrong measurement scaling, picker options that never got updated, and data points a device does not actually have. Every check previews exactly what it would change, per device, and saves nothing until you confirm
- Connect-failure diagnosis — when a device fails to connect during pairing, the app probes port 6668 and says which of the three it was: nothing at that address, the port closed, or the connection refused because something else already holds the device's single connection slot
- Support bundle — one button, at the top of the Fix It tab, collecting everything a report needs: per device the driver, the protocol version configured and in use, the full DP mapping, the live values, the connection history (how many connections, how long they held, how many packets arrived, whether any data ever did) and the manufacturer's specification where Cloud Lookup is set up. Local keys never appear in it and device IDs are shortened. Repeated log lines are folded into one with a count, so a single chatty fault cannot crowd out everything else
- Diagnostic tools — in-app log buffer, live DP debug panel, and a Help tab covering every driver and the common faults
- Bilingual — full English and German UI
- Homey Pro with firmware ≥ 12.13.0 — required by the EV Charger driver's
target_powercapability - Device reachable on your local network
- Device ID, Local Key and IP address — see How to get Device ID and Local Key
No CLI tools or terminal needed. Everything happens inside the Homey app. Credentials are saved on Homey and auto-filled next time.
One-time setup:
- Create a free account at iot.tuya.com.
- Cloud → Project Management → Create Cloud Project — industry: Smart Home, region: same as your mobile app.
- Open your project → Devices → Link Tuya App Account → scan the QR code with Tuya Smart / Smart Life.
- Open your project → Overview → copy Access ID / Client ID and Access Secret / Client Secret.
Option A — During pairing (easiest):
- When adding a device, click ☁️ Fetch Device ID & Local Key from Cloud in the credentials screen.
- Paste your Access ID and Secret, select your data center, click Fetch Devices.
- Click a device in the list — Device ID and Local Key are filled in automatically.
- Check Save credentials on Homey so they're pre-filled next time.
Option B — In app settings:
- In Homey: More → Apps → Tuya Local → Settings → ☁️ Cloud Lookup tab.
- Paste your Access ID and Secret, select your data center, click Fetch Devices.
- Use the Copy button next to each device to copy all fields (custom name, name, Device ID, Local Key, product, category, UUID).
If you recently reset or re-paired a device the Local Key changes. Click Fetch Devices again to get the new key.
Requires Node.js ≥ 16 on your computer.
npx @tuyapi/cli wizardThe wizard logs you into the Tuya IoT Platform, links your Smart Life / Tuya mobile app, and lists every device with its Device ID and Local Key.
- Open your project at iot.tuya.com.
- Devices → All Devices → click the pencil icon next to your device.
- Copy Device ID and Device Secret (= Local Key).
- Check your router's DHCP client list.
- Use the Scan Network button in the pairing wizard (UDP + TCP scan, ~10 s).
- Assign a static IP / DHCP reservation so the address never changes.
Search for Tuya Local in the Homey app → install.
git clone https://github.com/andiwirz/com.tuyalocal
cd com.tuyalocal
npm install
homey app install- Homey app → Devices → + → Tuya Local → choose your driver.
- Scan Network to auto-discover devices, or enter IP / Device ID / Local Key manually.
- To fill in Device ID and Local Key automatically, click ☁️ Fetch Device ID & Local Key from Cloud — enter your Tuya API credentials once (or re-use previously saved ones), pick your device from the list, and the fields are filled in automatically.
- Check Save credentials on Homey to have them pre-filled next time.
- Leave Protocol Version on Auto-detect (default) — the app tries 3.3 → 3.4 → 3.1 → 3.5 → 3.2 and saves the working version automatically. Select a specific version only if auto-detect fails.
- Click Test & Connect — the app connects, collects live data, then shows a summary screen.
- Review the detected DP mapping. Adjust DP numbers directly in the table if needed.
Generic: the full DP mapper opens — assign each data point to a capability and configure scale, unit, options. - Expand Show all detected DPs to inspect the raw snapshot from the device.
- Optionally rename the device, then click Add Device.
| Setting | Description | Default |
|---|---|---|
| IP Address | Local IP of the device | — |
| Device ID | Tuya device identifier | — |
| Local Key | LAN encryption key (16 or 32 chars) | — |
| Protocol Version | Auto-detect / 3.1 / 3.3 / 3.4 / 3.5 | Auto-detect |
| Polling Interval (s) | Active poll cadence — 0 disables polling |
30 |
| Offline Grace Period (s) | Seconds to wait before triggering "device disconnected" flows — 0 = immediate |
60 |
Two settings cover the common deviations from the standard timer format.
| Setting | Description | Default |
|---|---|---|
dp_countdown_timer_numeric |
Enable if the timer DP sends 0…24 instead of cancel / 1h … 24h |
off |
dp_countdown_left_minutes |
Enable if the remaining-time DP counts minutes (0–1440) instead of hours | off |
| Setting | Default (full superset) |
|---|---|
mode_values |
manual,laundry,auto,continuous,smart,sleep,drying |
fan_speed_values |
low,medium,middle,high,auto,turbo |
The exact strings vary by manufacturer. Check the Raw Data panel in app settings to find what your device sends. After saving, restart the Tuya Local app for the picker to reflect the updated options.
Some dehumidifiers report modes and fan speeds as plain numbers rather than names — set mode_values = 0,1 and fan_speed_values = 0,1 to match, otherwise the picker rejects the values and the tiles stay empty.
Water tank alarm: on many models this DP is really a fault bitmap covering several error conditions, not a dedicated tank sensor. The driver treats any non-zero value as "tank full", so an unrelated fault can surface as a tank alarm. Watch the raw value in DP Debug while filling the tank to confirm what your device actually sends.
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
Most Tuya plugs send the energy counter (DP 17, add_ele) as a resetting delta — the Tuya cloud accumulates the deltas into a lifetime total, but locally the value appears frozen.
When dp_energy = 0 (default), the app computes kWh itself by integrating live power readings using trapezoidal averaging — the mean of the previous and current power reading multiplied by elapsed time. The result is monotonically increasing and persisted across app restarts.
Set dp_energy = 17 only if your device provides a reliable cumulative local energy counter.
The energy accumulator can be reset via the Reset energy meter flow action.
Besides the conventional block 17/18/19/20 there is a second arrangement, common on breakers and on plugs outside the usual family:
| DP | Code | DP | Code | |
|---|---|---|---|---|
| 20 | add_ele — energy, scale 3 |
22 | cur_voltage — voltage, scale 1 |
|
| 21 | cur_current — current, scale 3 |
23 | cur_power — power, scale 1 |
Pairing recognises it. The two overlap at DP 20 and mean opposite things there — voltage in one, energy in the other — so the tell is DP 22: a mains voltage is the one quantity a value alone identifies, since 100–280 V covers every grid and nothing else idles there.
With Cloud Lookup configured none of this is needed: the app matches switch_1,
cur_power, cur_current, cur_voltage, add_ele, relay_status and countdown_1 by
name and fills the settings in from the manufacturer's own list.
Controls what the device does when mains power is restored after an outage.
| Value | Meaning |
|---|---|
off |
Always Off — device stays off when power is restored |
on |
Always On — device turns on when power is restored |
memory |
Last State — device resumes its previous state |
Default: off,on,memory (all three options shown).
| Setting | Behavior |
|---|---|
| ×0.1 (default) | Multiply raw value by 0.1 — standard for Tuya plugs |
| ×1 | Use raw value directly |
| Auto-detect | Raw > 2000 → ×0.1; first non-zero value ≤ 2000 → ×1 (legacy, not recommended) |
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
Some AC units send temperatures multiplied by 10 (e.g. 220 = 22.0 °C). The driver auto-detects this during pairing. If the displayed temperature is still 10× too high, set temp_divisor = 10 in device settings.
| Setting | Default |
|---|---|
mode_values |
cool,heat,auto,dry,fan |
fan_speed_values |
auto,low,medium,high,turbo |
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
The speed slider (dim) maps the numeric DP range speed_min … speed_max to 0–100 %. Both a numeric speed DP and a string enum DP (fan_speed) can be active at the same time.
Fill in the three light DPs and the fan gains separate light controls plus the flow cards Set light, Set light brightness and the condition Light is on. Leave them at 0 for fans without a light — nothing extra appears.
| Setting | Description | Default |
|---|---|---|
dp_light_dim_min / dp_light_dim_max |
Device brightness range, scaled to 0–100 % | 0 / 100 |
dp_light_color_temp_invert |
Enable if warm and cold are swapped | off |
Because the speed slider already occupies dim, the light's brightness uses its own dim.light sub-capability.
| Setting | Default |
|---|---|
fan_speed_values |
low,medium,high,auto,turbo |
fan_mode_values |
normal,sleep,nature,breeze,smart |
The fan_direction capability uses fixed values forward and reverse (Tuya standard). The DP is auto-detected at pairing time if the device reports either of those strings.
Homey multiplies the consumption you store for a device by its dim value, which on a
fan is the speed — and for most fans that is simply wrong, since they draw very nearly
the same at every step. With a
houseful of them the energy total is wrong all day.
| Setting | Meaning | Default |
|---|---|---|
power_on_watts |
Report this wattage while the device is on | 0 (off) |
power_off_watts |
Standby draw reported while it is off | 0 |
Enter what a plug-in meter reads and the app reports that figure instead, whatever the
slider says. A measured value takes precedence over Homey's estimate. At 0 nothing
changes.
A ceiling fan with a light built into it — one Tuya device carrying two independent things. Separate from the Fan driver because Homey has to be told which of the two the device is: this one is a Light, so the main tile, the on/off button and Homey's light groups all act on the light. The fan gets its own sub-capabilities and its own flow cards.
| What | Capability | Driven by |
|---|---|---|
| Light on/off (main switch) | onoff |
dp_light_onoff |
| Light brightness | dim |
dp_light_dim |
| Fan on/off | onoff.fan |
dp_onoff |
| Fan speed (slider) | dim.fan |
dp_speed |
If the main switch operates the fan instead of the light,
dp_light_onoffwas not detected at pairing. Set it in device settings — the fan keeps its owndp_onoff.
Same settings as Dehumidifier, plus Fire and Forget (on by default — most of these fans are 3.4/3.5).
speed_min / speed_max (default 1 … 100) map the device's raw speed range onto the 0–100 % slider.
A fan with six steps takes speed_min = 1, speed_max = 6.
| Setting | Icon | Capability | Type | Default DP | Optional |
|---|---|---|---|---|---|
dp_light_onoff |
onoff |
boolean | 0 | — | |
dp_light_dim |
dim |
number | 0 | ✓ 0 = disabled |
|
dp_light_color_temp |
light_temperature |
number | 0 | ✓ 0 = disabled |
|
dp_light_colour |
light_hue, light_saturation |
string | 0 | ✓ 0 = disabled |
|
dp_light_mode |
light_mode |
enum | 0 | ✓ 0 = disabled |
dp_light_dim_min / dp_light_dim_max and dp_light_color_temp_min / _max map the device's raw
ranges onto Homey's 0–100 %. dp_light_color_temp_invert (on by default) flips the colour-temperature
direction for devices that count from warm to cold rather than the other way round.
Tuya has two colour encodings, and the app speaks whichever the fitting itself reports — nothing to configure.
| Length | Layout | |
|---|---|---|
| 12 characters | HHHHSSSSVVVV |
hue 0–360, saturation and value 0–1000 |
| 14 characters | RRGGBBHHHHSSVV |
RGB first, then hue 0–360 and 0–255 pairs |
A fitting expecting the longer form reads the first six characters of the short one as
RGB, and those come out as 00 xx 03 for every hue — which shows as green at every
colour in the picker, brighter or dimmer. The format is taken from what the device
reports, since that is by definition what it understands.
The light half carries the same power_on_watts / power_off_watts settings as the
Light driver — see there.
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
Note:
alarm_waterfor a humidifier indicates that the water tank is empty (refill needed), as opposed to the dehumidifier where it means the tank is full.
| Setting | Default |
|---|---|
mode_values |
auto,manual,normal,sleep,eco,boost |
fan_speed_values |
low,medium,middle,high,auto |
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
| Setting | Description | Default |
|---|---|---|
temp_divisor |
Divide raw DP value to get °C — use 10 if device sends e.g. 215 for 21.5 °C |
1 |
temp_min |
Minimum target temperature (°C) | 5 |
temp_max |
Maximum target temperature (°C) | 35 |
temp_step |
Step size for the temperature slider (°C) | 1 |
| Setting | Default |
|---|---|
mode_values |
eco,comfort,boost,away,auto |
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
| Setting | Icon | Capability | Type | Default DP | Optional |
|---|---|---|---|---|---|
dp_onoff |
onoff |
boolean | 20 | — | |
dp_brightness |
dim |
number | 22 | — | |
dp_color_temp |
light_temperature |
number | 23 | ✓ 0 = disabled |
|
dp_color_mode |
light_mode |
string | 21 | ✓ 0 = disabled |
|
dp_color |
light_hue + light_saturation |
HSV hex | 24 | ✓ 0 = disabled |
Standard Tuya light DP layout (newer protocol):
| DP | Function |
|---|---|
| 20 | On/Off |
| 21 | Color mode (white / colour) |
| 22 | Brightness (0–1000) |
| 23 | Color temperature (0–1000) |
| 24 | HSV color (12-char hex HHHHSSSSBBBB) |
Older protocol uses DPs 1–5 instead of 20–24.
| Setting | Description | Default |
|---|---|---|
brightness_max |
Maximum raw brightness value | 1000 |
color_temp_max |
Maximum raw color temperature value | 1000 |
color_temp_invert |
Enable if 0 = warm white and max = cool white |
false |
color_mode_white_val |
String the device uses for white/CCT mode | white |
color_mode_color_val |
String the device uses for color (HSV) mode | colour |
In white mode, the brightness (dim) slider writes directly to dp_brightness. In color mode, the brightness slider updates the V (value) component of the HSV hex string. Hue and saturation are mapped from the Homey light_hue / light_saturation capabilities.
Homey multiplies the consumption you store for a device by its dim value, and for most LED lamps that is simply wrong — they draw very nearly the same at every step. With a houseful of them the energy total is wrong all day.
| Setting | Meaning | Default |
|---|---|---|
power_on_watts |
Report this wattage while the device is on | 0 (off) |
power_off_watts |
Standby draw reported while it is off | 0 |
Enter what a plug-in meter reads and the app reports that figure instead, whatever the
slider says. A measured value takes precedence over Homey's estimate. At 0 nothing
changes.
Universal driver for pool / air-water heat pumps. Auto-detects all major DP layouts at pairing time.
| Device family | On/Off | Target temp | Current temp | Mode |
|---|---|---|---|---|
| Brustec / BWT / CBC / Madimack / Mountfield / Varpoolfaye | DP 1 | DP 2 | DP 3 | DP 4/5 |
| Phalén Calidi XP / Fairland InverterPlus | DP 1 | DP 106 | DP 102 | DP 105 |
| Waterco Electroheat ECO-VS | DP 101 | DP 104 | — | — |
| Apricus / Powerworld water HP | DP 1 | DP 2 | DP 3 | DP 4 |
| Arcelik / Axen combo (DHW + space heating) | DP 1 | DP 103–106 | — | DP 109 |
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
The quiet or night mode most pumps carry as SilentMode — DP 117 on the Fairland /
Phalén family. Set dp_silent to it and the device gains a Silent mode switch, plus a
flow action, condition and trigger.
Which raw value means quiet is a setting rather than a rule, because the two disagree.
The data point is named SilentMode, which reads as true = quiet; on a measured
Fairland InverterPlus it is the other way round — true is Smart, false is Silence.
| Setting | Meaning | Default |
|---|---|---|
silent_true_means |
Whether true on that data point is the Smart mode or the quiet one |
smart |
silent_values |
The two names, if the data point carries a named value instead of a switch | smart,silence |
If the switch reads off while the pump is audibly running quietly, set silent_true_means
to silent.
Some pumps name the two modes rather than switching them — a reported Fairland PSL puts
smart / silence on DP 102 where another Fairland puts a boolean on DP 117. The app
tells the two apart by what the device reports, so nothing needs choosing; only the two
names have to be in silent_values, normal mode first. On a boolean device that setting
is ignored.
| Setting | Description | Default |
|---|---|---|
temp_divisor |
Divide raw DP value to get °C for both target and measured temperature — use 10 if device sends e.g. 350 for 35 °C |
1 (auto-detected) |
current_temp_divisor |
Override divisor for the measured temperature only — use 10 if the current temp DP is ×10 but the target temp DP is raw °C (e.g. Weau). Set to 0 to fall back to temp_divisor. |
0 (uses temp_divisor) |
temp_min |
Minimum target temperature (°C) | 12 |
temp_max |
Maximum target temperature (°C) | 45 |
temp_step |
Step size for the temperature slider (°C) | 1 |
| Setting | Description | Default |
|---|---|---|
mode_values |
Comma-separated mode strings matching your device | heat,cool,auto |
preset_values |
Comma-separated preset names — for bool DPs the first value = false, second = true | sleep,comfort,boost |
Check DP Debug in app settings to find the exact strings your device sends. A bool
preset DP is handled automatically — set preset_values to two names and false takes
the first, true the second.
If your device reports a mode that mode_values does not list, the app now says so in
the log. A Tuya device discards an enum value it does not recognise without a word, so
this is what "the mode picker does nothing" looks like from outside.
DP 117 has its own setting above and does not belong in preset_values — it is a switch
between two named modes, not one of three presets.
Universal driver for curtain, blind and roller motors (Tuya category cl). Auto-detects all DP layouts at pairing time.
| Device | Control DP | Position DP | Work state DP | Fault DP |
|---|---|---|---|---|
| Zemismart v1 | DP 1 open/stop/close |
DP 2 (0–100 %) | DP 7 | DP 10 |
| Zemismart v2 | DP 1 | DP 2 | DP 7 | DP 12 |
| Most category-cl motors | DP 1 | DP 2 | DP 7 | DP 10 or 12 |
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
| Setting | Icon | Capability | Type | Default DP | Optional |
|---|---|---|---|---|---|
dp_control |
windowcoverings_state |
enum open/stop/close |
1 | — | |
dp_percent_control |
windowcoverings_set |
integer 0–100 % | 2 | — | |
dp_work_state |
windowcoverings_state |
enum opening/closing (read-only) |
7 | ✓ 0 = disabled |
|
dp_fault |
alarm_generic |
bitmap | 0 | ✓ 0 = disabled |
| Setting | Description | Default |
|---|---|---|
invert_position |
Enable if 0 % = open and 100 % = closed on your device |
false |
Position convention: The driver maps
percent_controlwhere0= fully closed and100= fully open to Homey'swindowcoverings_set(0.0–1.0). Enableinvert_positionif your device uses the opposite convention.
Zemismart v2 extra DPs: DP 16 (
border/ limit calibration) and DP 19 (position_best/ favourite position) are motor-setup commands — run the limit calibration from the Tuya/Smart Life app first, then use Homey for daily control.
Universal driver for floor heating thermostats, room thermostats, TRVs (radiator valves), and zone valves.
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
| Setting | Description | Default |
|---|---|---|
temp_divisor |
Divide raw DP value to get °C — use 10 if device sends e.g. 220 for 22.0 °C (common on BHT-002 / Moes) |
1 (auto-detected) |
temp_min |
Minimum target temperature (°C) | 5 |
temp_max |
Maximum target temperature (°C) | 35 |
temp_step |
Step size for the temperature slider (°C) | 0.5 |
| Setting | Default |
|---|---|
mode_values |
manual,auto,program |
Common alternatives: heat,cool,off (HVAC), auto,manual,holiday (TRV), comfort,eco,away (floor heating).
Supports Tuya smart kettles with temperature control, keep-warm, and mode selection (Anko, Aeno, Kogan and others).
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
| Setting | Description | Default |
|---|---|---|
temp_min |
Minimum target temperature (°C) | 40 |
temp_max |
Maximum target temperature (°C) | 100 |
temp_step |
Step size (°C) | 5 |
| Setting | Default |
|---|---|
mode_values |
boil,heat,keep_warm |
status_values |
standby,heating,cooling,warm,done |
Some kettles use tea-specific modes (e.g. Aeno EK1S): mzj_black,mzj_green,mzj_water,mzj_oolong,mzj_warm.
Dedicated driver for 1/2/3/4-gang WiFi wall switches. Each gang gets its own tile and flow cards.
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
| Setting | Icon | Capability | Type | Default DP | Optional |
|---|---|---|---|---|---|
dp_switch_1 |
onoff |
boolean | 1 | — | |
dp_switch_2 |
onoff.2 |
boolean | 0 | ✓ 0 = disabled |
|
dp_switch_3 |
onoff.3 |
boolean | 0 | ✓ 0 = disabled |
|
dp_switch_4 |
onoff.4 |
boolean | 0 | ✓ 0 = disabled |
|
dp_countdown_1–4 |
(settings only) | number | 0 | ✓ 0 = disabled |
|
dp_relay_status |
(settings only) | enum | 0 | ✓ 0 = disabled |
On a multi-gang switch the main on/off is channel 1 — the capability the tile carries, a dashboard shows and a voice assistant reaches. "Kitchen off" then switches one channel of two.
| Setting | Meaning | Default |
|---|---|---|
aggregate_main |
Main on/off controls every configured channel | off |
Switched on, the main on/off turns them all on or all off — off always reaching every channel whatever it was doing — and reads as on while any one of them is on, including after someone used the switch on the wall. Channel 1 moves to its own control beside the others. No flows are involved and nothing loops.
Off by default, because turning it on changes what an existing flow on the main on/off does.
Each switch tile can be renamed in Settings → Switch Names. Leave empty for the default name ("Power" / "Switch 2/3/4"). The app needs to be restarted for name changes to take effect.
Event-driven driver for Tuya video doorbells. The device pushes events over the LAN connection — no polling is used (default polling_interval = 0).
Compatible devices include: Marmitek Buzz LO, Bcom Majic IPBox, Cleverio CD-200, and any Tuya doorbell that sends DP 136 (ring) or DP 115 (motion).
| Setting | Description | Default |
|---|---|---|
ip |
Device IP address | — |
device_id |
Tuya Device ID | — |
local_key |
Tuya Local Key (16 or 32 chars) | — |
version |
Protocol version | Auto-detect |
polling_interval |
Seconds between GET polls (0 = push-only, recommended) |
0 |
offline_grace_seconds |
Seconds without data before marking device offline | 60 |
These DPs fire a trigger when the device pushes a new value.
| Setting | Trigger | Type | Default DP | Notes |
|---|---|---|---|---|
dp_doorbell |
Doorbell rang | boolean | 136 | true = ring event |
dp_motion_event |
Motion detected | boolean | 115 | true = motion event |
dp_alarm_message |
Ring or motion via alarm message | string (base64) | 0 | DP 185 on some devices; decodes ipc_doorbell / ipc_motion JSON |
Seed protection: the ring and motion triggers are suppressed for the very first packet after each (re)connect to prevent false events. Subsequent packets fire normally.
| Setting | Description | Type | Default DP | Optional |
|---|---|---|---|---|
dp_motion_switch |
Enable/disable motion detection | boolean | 134 | ✓ 0 = disabled |
dp_nightvision |
Night vision mode | number (0=auto, 1=off, 2=color) |
108 | ✓ 0 = disabled |
dp_chime_volume |
Chime volume (0–100) | number | 157 | ✓ 0 = disabled |
dp_device_volume |
Device speaker volume (0–100) | number | 160 | ✓ 0 = disabled |
dp_indicator |
Status LED on/off | boolean | 101 | ✓ 0 = disabled |
dp_recording |
Cloud/SD recording on/off | boolean | 150 | ✓ 0 = disabled |
| Setting | Description | Default |
|---|---|---|
dp_motion_sensitivity |
DP for motion sensitivity (0=low, 1=medium, 2=high) |
106 |
motion_reset_seconds |
Seconds after which the motion alarm auto-clears | 30 |
Driver for Tuya mmWave radar presence sensors. Push-driven — no polling is used (default polling_interval = 0).
The defaults match the ZY-M100-WIFI DP layout exactly. Sensors using a different layout are corrected automatically at pairing when Cloud Lookup credentials are saved.
| Setting | Description | Default |
|---|---|---|
ip |
Device IP address | — |
device_id |
Tuya Device ID | — |
local_key |
Tuya Local Key (16 or 32 chars) | — |
version |
Protocol version | Auto-detect |
polling_interval |
Seconds between GET polls (0 = push-only, recommended) |
0 |
offline_grace_seconds |
Seconds without data before marking device offline | 60 |
These are device settings rather than tiles — they configure the radar itself.
| Setting | Description | Default DP |
|---|---|---|
dp_sensitivity |
Radar sensitivity, 0–9 | 2 |
dp_near_detection |
Near detection limit, 0–1000 cm (step 10) | 3 |
dp_far_detection |
Far detection limit, 0–1000 cm (step 10) | 4 |
dp_detection_delay |
Seconds before presence is reported | 101 |
dp_fading_time |
Seconds before presence clears after the room empties | 102 |
Driver for Tuya WiFi smoke detectors (category ywbj). Read-only apart from two commands: silencing a sounding alarm and starting the detector's own self-test.
Polling defaults to 300 seconds rather than the 30 the mains-powered drivers use. A detector pushes its alarm the moment it sounds, so the poll only refreshes the battery reading — and on a cell-powered detector every request answered is battery spent. Set it to 0 to switch polling off entirely.
The concentration on dp_smoke_value rises before the alarm trips, which makes it the one reading you can build an early warning on — see the Smoke level rose above trigger. Reported in plain ppm; if a detector scales it differently the raw value shows in DP Debug.
The battery data points are not settled. Tuya's specification calls DP 14 the level and DP 15 the percentage; a reported implementation had them the other way round. So neither is trusted: the driver reads the value and decides. A number is a percentage, a word is a level. A swapped pair therefore still lands correctly, and the defaults only have to be plausible.
| Setting | Description | Default |
|---|---|---|
ip |
Device IP address | — |
device_id |
Tuya Device ID | — |
local_key |
Tuya Local Key (16 or 32 chars) | — |
version |
Protocol version | Auto-detect |
polling_interval |
Seconds between GET polls (0 = push-only) |
300 |
offline_grace_seconds |
Seconds without data before marking device offline | 60 |
Written to, never read. Both are reachable from flow cards.
| Setting | Description | Default DP |
|---|---|---|
dp_self_test_start |
Starts the detector's self-test | 8 |
dp_muffling |
Silences a sounding alarm | 16 |
| Setting | Description | Default |
|---|---|---|
smoke_alarm_values |
Comma-separated words that mean smoke, for detectors with a different vocabulary. A word that is neither in this list nor a known word for "no smoke" is reported once and treated as no smoke — on a detector, a false alarm gets switched off, which is the worse way to be wrong | alarm |
battery_low_percent |
Raises the battery alarm at or below this percentage. Only used where the detector reports a percentage | 15 |
Driver for Tuya EV chargers (category qccdz). Single-phase and three-phase units are both supported, verified against every EV-charger configuration published in the tuya-local project.
Uses Homey's native EV charger capabilities, so the built-in Start charging / Stop charging actions, the Is charging condition and the charging-state trigger are all available without custom flow cards.
| Setting | Description | Default |
|---|---|---|
ip |
Device IP address | — |
device_id |
Tuya Device ID | — |
local_key |
Tuya Local Key (16 or 32 chars) | — |
version |
Protocol version | Auto-detect |
polling_interval |
Seconds between GET polls | 30 |
reconnect_interval |
Minutes between reconnect attempts while offline (0 = disabled) |
0 |
offline_grace_seconds |
Seconds without data before marking device offline | 60 |
Homey controls the charge rate in watts (target_power), the charger accepts amps. The conversion is W = A × voltage × phases.
| Setting | Description | Default |
|---|---|---|
current_min / current_max |
Physical amp range of your charger (e.g. 6–16 for 3.7 kW, 6–32 for 7.4 kW). Tuya often reports a far wider range than the hardware allows | 6 / 16 |
phase_count |
1 or 3 — detected at pairing from the number of phase DPs reported | 1 |
nominal_voltage |
Grid voltage used for the conversion | 230 |
A 16 A single-phase charger becomes a 0–3680 W slider in 230 W steps (1 A each). Anything below the charger's minimum current is treated as idle and stops the charge, rather than requesting an impossible current.
Chargers are not consistent here, and a single pairing snapshot cannot tell the variants apart — so each scale has its own setting. Defaults match the large majority; change one only if a reading is off by a factor of ten or a hundred.
| Setting | Description | Default |
|---|---|---|
current_scale |
1 = raw value is amps · 0.1 = raw value is amps × 10 |
1 |
voltage_scale |
Scale for the separate voltage DPs. 2359 for 235.9 V means 0.1 |
1 |
amp_scale |
Scale for the separate current DPs — the current that flows, not the limit above | 1 |
power_scale |
Multiplier turning the total power DP into watts. 110 for 11 kW means 100 |
1 |
temp_scale |
435 for 43.5 °C means 0.1 |
1 |
session_energy_scale |
0.01 = raw value is kWh × 100 · 1 = raw value is kWh |
0.01 |
total_energy_scale |
Same options, for the lifetime counter — some chargers scale it differently from the session counter | 0.01 |
Tuya reports eight states, Homey has five:
Tuya work_state |
Homey evcharger_charging_state |
|---|---|
charger_free, charger_free_fault |
Not plugged in |
charger_insert, charger_wait, charger_end, charger_fault |
Plugged in |
charger_charging |
Charging |
charger_pause |
Paused |
The exact Tuya state stays available through the Detailed charger state changed trigger and its matching condition, which can tell waiting from finished.
Total energy: many chargers expose a lifetime counter (DP 1) that reports a plausible value but never updates over the local connection. Because one reading cannot distinguish a working counter from a frozen one,
dp_energy_totaldefaults to0and the total is accumulated from the session counter instead — which works on every model tested. Set it to1if your charger's own counter does update.
Live measurements: some chargers only stream voltage / current / power while their
online_stateDP is set toonline. Setdp_live_updates = 27and the app re-asserts it on every reconnect.
Charging modes: chargers usually advertise five modes (immediate, to %, fixed kWh, scheduled, delayed) but implement far fewer — on many units only Charge Now does anything. DP 33 (
mode_set) is a bitmask declaring what the hardware actually supports and is more trustworthy than the advertised enum.dp_work_modeis therefore disabled by default.
DIN-rail meters, clamp meters and metering circuit breakers — Tuya categories zndb and dlq.
Separate from the Smart Plug because here the measurement is the point and the switch is optional.
A clamp meter in a distribution board has no switch at all, and the plug driver — declared as a
socket with onoff in its manifest — gives one anyway: a dead toggle on a device that cannot switch
anything. dp_switch is therefore 0 by default; set it only on a breaker that really switches
what it measures.
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Command Gap, Offline Grace Period).
Defaults are the classic Tuya metering block (17 / 18 / 19 / 20), which is what most single-phase meters use. DPs 21–25 are the factory calibration coefficients — read-only, never useful, and deliberately not logged as unmapped.
| Setting | Default | Example |
|---|---|---|
power_scale |
0.1 |
raw 4538 → 453.8 W |
voltage_scale |
0.1 |
raw 2376 → 237.6 V |
current_scale |
0.001 |
raw 2491 → 2.491 A |
kwh_scale |
0.01 |
raw 364 → 3.64 kWh |
Pairing also recognises the shifted layout — energy on DP 20, current 21, voltage 22,
power 23 — and sets kwh_scale to 0.001 with it, since add_ele carries scale 3 there.
See the Smart Plug section for what distinguishes the two.
Values are rounded to the number of decimals the divisor can express, so a raw 2376 becomes 237.6 V rather than 237.60000000000002 in Insights for ever. Check measurement scaling on the Fix It tab reads the divisor Tuya declares and offers to correct these.
A meter reports numbers and almost nothing else, and one number looks much like another — a voltage
of 2376 and an energy total of 2376 are the same integer. Local detection therefore resolves the
conventional block and mains voltage, and leaves the rest to Cloud Lookup, which knows the
manufacturer's code names (cur_power, add_ele, cur_voltage, …). Across the 42 single-DP meter
definitions in the tuya-local catalogue the local heuristic identifies six; a wider number table
would reach twelve and get much of the rest wrong, because DP 103 is the power on seven models, the
voltage on three and the current on two. A confident wrong reading on a meter is worse than none.
If nothing could be identified, pairing says so rather than handing over a silent device.
Not supported: meters that pack voltage, current and power for a phase into one binary value (28 of the 70 definitions, 27 of them on DP 6). The format is undocumented and no reading from a real device has been available to check an implementation against, so such a meter pairs and then shows nothing.
WiFi weather stations with outdoor sensors — indoor and outdoor temperature and humidity, barometric pressure, wind speed, gust and direction, and rainfall.
Same settings as Dehumidifier. Polling Interval defaults to 300 s: these stations report on their own schedule and nothing is gained by asking more often.
| Setting | Icon | Capability | Default DP |
|---|---|---|---|
dp_temp_in |
measure_temperature (indoor) |
101 | |
dp_hum_in |
measure_humidity (indoor) |
102 | |
dp_temp_out |
measure_temperature.outdoor |
103 | |
dp_hum_out |
measure_humidity.outdoor |
104 | |
dp_temp_extra |
measure_temperature.extra |
0 |
temp_divisor and humidity_divisor default to 10 — these stations send tenths.
wind_divisor defaults to 1: these stations send whole units, and a divisor of 10 produced gust
readings with a decimal place the hardware does not have.
wd_values maps the raw direction index onto compass points, in order from north clockwise —
N,NNE,NE,ENE,E,ESE,SE,SSE,S,SSW,SW,WSW,W,WNW,NW,NNW. That one data point feeds two capabilities
on purpose: wind_direction carries the compass point that the tile shows, and Homey's own
measure_wind_angle keeps the degrees, so a flow can use whichever it needs.
| Setting | Icon | Capability | Default DP |
|---|---|---|---|
dp_comfort |
comfort_level |
126 |
comfort_values maps the raw strings the station sends onto that picker, default
moist,dry,comfortable,na.
Tank and cistern level sensors: an ultrasonic head measures the distance down to the liquid and reports both a depth and a percentage, plus configurable high and low alarm thresholds.
Same settings as Dehumidifier.
| Setting | Icon | Capability | Type | Default DP |
|---|---|---|---|---|
dp_level_percent |
liquid_level |
number | 22 | |
dp_depth |
measure_distance |
number | 2 | |
dp_state |
liquid_state, alarm_tank_empty, alarm_tank_full |
enum | 1 |
depth_divisor defaults to 1000 — the depth arrives in millimetres.
state_values maps the raw strings, default normal,lower_alarm,upper_alarm. The state drives
three capabilities from the one data point: the liquid_state picker showing which of the three it
is, plus an empty and a full alarm that a flow can react to directly.
These are written by flow actions rather than read as capabilities, which is why they sit in their own group. Their DP numbers only need changing if your sensor arranges them differently.
| Setting | Meaning | Default DP |
|---|---|---|
dp_max_set |
High threshold | 7 |
dp_mini_set |
Low threshold | 8 |
dp_upper_switch |
High alarm enabled | 14 |
dp_lower_switch |
Low alarm enabled | 15 |
dp_install_height |
Mounting height above the tank floor | 19 |
dp_depth_full |
Depth that counts as full | 21 |
Each of these is followed by a read-only field showing the value the device currently holds, with the raw number beside it. The app asks for them explicitly after connecting: they are settings inside the device and never change, so a device that only reports what moves would never send them at all.
The thresholds above are the device's own. Reaching one sets off its alarm, and on some models a loud buzzer — so they cannot simply be moved to get an earlier warning in Homey.
| Setting | Meaning | Default |
|---|---|---|
own_low_percent |
Raise the empty alarm in Homey at this percentage | 0 (off) |
own_high_percent |
Raise the full alarm in Homey at this percentage | 0 (off) |
Set either and that alarm is computed from the level instead of from the device's own
state, and takes precedence over it — the device reporting normal no longer withdraws
a warning you asked for. At 0 nothing changes.
liquid_state keeps reporting what the device says either way. It is the device's own
statement; the alarms are where Homey's judgement belongs.
Maps any Tuya DP to any Homey capability. The mapping is built visually during pairing — no manual JSON editing required.
Each entry in the dp_config JSON array supports the following fields:
| Field | Type | Required | Description |
|---|---|---|---|
dp |
number | ✓ | Tuya data point number |
cap |
string | ✓ | Homey capability ID (e.g. onoff, generic_sensor_1) |
label |
string | Custom display name shown in the UI | |
settable |
boolean | true = Homey can send commands; false = read-only |
|
scale |
number | Multiply raw number by this factor (e.g. 0.1 → raw 220 = 22.0) |
|
integer |
boolean | false = send as float; omit or true = round to integer (default) |
|
unit |
string | Unit label shown in the UI (e.g. °C, %, W) |
|
min / max / step |
number | Range and step for slider capabilities | |
options |
string | Comma-separated enum values for picker capabilities | |
readMap |
string | JSON map: raw DP value → capability value (e.g. {"1":"on","2":"off"}) |
|
writeMap |
string | JSON map: capability value → raw DP value (e.g. {"on":"1","off":"2"}) |
Debounce: Slider capabilities are debounced by 300 ms to prevent flooding the device during drag.
| Pool | Capability IDs | Type | Settable |
|---|---|---|---|
| Sensors | generic_sensor_1 … generic_sensor_4 |
number | No |
| Sliders | generic_number_1, generic_number_2 |
number | Yes |
| Toggles | generic_switch_1 … generic_switch_4 |
boolean | Yes |
| Pickers | generic_picker_1 … generic_picker_4 |
enum | Yes |
| Standard | onoff, measure_temperature, measure_humidity, measure_power, measure_voltage, measure_current, meter_power, and others |
various | varies |
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
All DP numbers are auto-detected at pairing time. Set any optional DP to 0 to hide the tile.
| Value | Meaning |
|---|---|
full / high / half |
Adequate food in the hopper |
low / less / lack |
Level is low — triggers push notification |
empty |
Hopper is empty — also triggers notification |
less and lack are used by Mypin 6L and some video feeder variants.
| Setting | Description | Default |
|---|---|---|
portions_min |
Lowest value shown in the portions picker | 1 |
portions_max |
Highest value shown in the portions picker | 12 |
The picker range is rebuilt on every startup and whenever these settings change.
| Setting | Description | Default |
|---|---|---|
food_empty_values |
Comma-separated food status values that trigger a push notification | low,less,empty,lack |
voice_times |
Number of times the mealtime recording plays (written to device) | 1 |
manual_button_portions |
Portions dispensed per physical button press (written to device) | 1 |
Supports four device families with automatic DP pattern detection at pairing time.
| Device family | State DP | Control DP | Examples |
|---|---|---|---|
| WOFEA / ckmkzq | DP 3 bool | DP 6 enum open/close |
WOFEA WF-CS01 |
| ZC34T swing arm | DP 1 string "open"/"closed" |
DP 101 string open/close/stop |
ZC34T-03-3A |
| AOSD + light | DP 107 string opened/closing/… |
DP 101 string | AOSD garage door with light |
| BoboYun gatePro | DP 10 string opened/closing/… |
DP 106 bool (open) + DP 107 bool (close) | BoboYun gatePro |
Same settings as Dehumidifier (IP, Device ID, Local Key, Protocol Version, Polling Interval, Offline Grace Period).
| Setting | Icon | Capability | Default DP | Description |
|---|---|---|---|---|
dp_door_contact |
garagedoor_closed |
3 | Bool or string "open"/"closed" contact sensor. WOFEA DP 3, ZC34T DP 1, eWeLink DP 2. |
|
dp_door_action |
garagedoor_closed |
0 | String action state (opened/closed/opening/closing). AOSD DP 107, BoboYun DP 10. |
|
dp_door_control |
— | 6 | Combined open/close command DP. WOFEA DP 6 (enum), AOSD/ZC34T DP 101 (string). | |
dp_door_open |
— | 0 | Separate bool open DP (BoboYun DP 106: send true → open). |
|
dp_door_close |
— | 0 | Separate bool close DP (BoboYun DP 107: send true → close). |
|
dp_switch |
— | 1 | Relay toggle DP (WOFEA DP 1 = relay pulse; BoboYun DP 103 = stop). Used by Toggle and Stop actions. | |
dp_door_state |
alarm_generic |
12 | Alarm state. WOFEA: none/unclosed_time/close_time_alarm. BoboYun: No/event strings (set to 141). |
|
dp_light |
onoff.light |
0 | Integrated light switch. AOSD DP 105, BoboYun DP 102. 0 = disabled. |
All DPs are auto-detected at pairing time. For AOSD and BoboYun, dp_door_action and dp_light are detected automatically; BoboYun's dp_door_state (DP 141) must be set manually.
| Setting | Description | Default |
|---|---|---|
door_contact_invert |
Swap open/closed reading from the contact sensor — enable if the door shows open when closed | false |
use_relay_toggle |
Enable for single-relay openers (e.g. WOFEA): tile button and Open/Close flow actions send a relay pulse on dp_switch instead of an open/close command. The door status continues to be read from the contact sensor. |
false |
| Configuration | Open door | Close door | Stop door |
|---|---|---|---|
dp_door_open > 0 (BoboYun) |
set(dp_door_open, true) |
set(dp_door_close, true) |
set(dp_switch, true) |
dp_door_control > 0 (WOFEA / AOSD / ZC34T) |
set(dp_door_control, 'open') |
set(dp_door_control, 'close') |
set(dp_door_control, 'stop') |
Stop note: WOFEA DP 6 only accepts open/close; sending stop is silently ignored by the device. Use the Toggle action to interrupt movement on WOFEA devices.
- Contact sensor (
dp_door_contact): reports binary open/closed — opens/closed flow triggers fire on every change. - Action state (
dp_door_action): reportsopened/opening/closing/closed— opened/closed flow triggers fire only on terminal states (opened/closed), not during movement.
| Trigger | Filter tokens | Flow tokens |
|---|---|---|
| Humidity went above threshold | threshold (%) | humidity, prevHumidity, trend |
| Humidity dropped below threshold | threshold (%) | humidity, prevHumidity, trend |
| Water tank became full | — | — |
| Water tank was emptied | — | — |
| Dehumidifier connected | — | — |
| Dehumidifier disconnected | — | — |
| A data point changed | — | dp (string), value (string) |
| Dehumidifier child lock switched | enabled as a filter — pick turned on or turned off |
— |
| Dehumidifier oscillation switched | enabled as a filter — pick turned on or turned off |
— |
| Condition |
|---|
| Humidity is / is not above [value] % |
| Humidity is / is not below [value] % |
| Water tank is / is not full |
| Dehumidifier is / is not connected |
| Mode is / is not [mode] |
| Dehumidifier child lock is / is not on |
| Dehumidifier oscillation is / is not on |
| Action | Notes |
|---|---|
| Set target humidity | 25–80 % |
| Set operating mode | Uses values from mode_values setting |
| Set fan speed | Uses values from fan_speed_values setting |
| Set countdown timer | cancel / 1h … 24h |
| Enable / disable child lock | Only works when dp_child_lock > 0 |
| Enable / disable ioniser | Only works when dp_anion > 0 |
| Set self-clean | on / off — requires dp_self_clean > 0 |
| Set water pump | on / off — requires dp_pump > 0 |
| Set dehumidifier oscillation | on / off — requires dp_oscillate > 0 |
| Refresh dehumidifier values | Triggers an immediate GET request |
| Force dehumidifier reconnect | Drops and re-establishes the TCP connection |
| Trigger | Filter tokens | Flow tokens |
|---|---|---|
| Power went above threshold | threshold (W) | power (W), prevPower (W) |
| Power dropped below threshold | threshold (W) | power (W), prevPower (W) |
| Smart plug fault alarm triggered | — | fault_code (string) |
| Smart plug connected | — | — |
| Smart plug disconnected | — | — |
| A data point changed | — | dp (string), value (string) |
| Condition |
|---|
| Power is / is not above [value] W |
| Fault alarm is / is not active |
| Device is / is not connected |
| Action | Notes |
|---|---|
| Refresh smart plug values | Triggers an immediate GET request |
| Force smart plug reconnect | Drops and re-establishes the TCP connection |
| Set countdown timer | 0–86400 s; 0 cancels. Requires dp_countdown > 0 |
| Reset energy meter | Resets the computed kWh accumulator to zero |
| Trigger | Flow tokens |
|---|---|
| AC connected | — |
| AC disconnected | — |
| AC fault alarm triggered | fault_code (number) |
| AC mode changed | mode (string), prev_mode (string) |
| AC data point changed | dp (string), value (string) |
| AC child lock switched | enabled as a filter — pick turned on or turned off |
| Condition |
|---|
| AC is / is not connected |
| AC mode is / is not [mode] |
| AC fan speed is / is not [speed] |
| AC sleep mode is on / is off |
| AC fault alarm is / is not active |
| AC child lock is / is not on |
| Action | Notes |
|---|---|
| Set AC mode | cool / heat / auto / dry / fan |
| Set AC fan speed | auto / low / medium / high / turbo |
| Set AC target temperature | Configurable min/max/step |
| Set AC swing | on / off — requires dp_swing > 0 |
| Set AC sleep mode | on / off — requires dp_sleep > 0 |
| Set AC ECO mode | on / off — requires dp_eco > 0 |
| Set AC ioniser | on / off — requires dp_anion > 0 |
| Set AC horizontal swing | on / off — requires dp_swing_h > 0 |
| Set AC child lock | on / off — requires dp_child_lock > 0 |
| Set AC timer | Countdown, cancel or 1–24 h — requires dp_countdown_timer > 0 |
| Force AC reconnect | Drops and re-establishes the TCP connection |
| Refresh AC device | Triggers an immediate GET request |
| Trigger | Flow tokens |
|---|---|
| Fan connected | — |
| Fan disconnected | — |
| Fan mode changed | mode (string), prev_mode (string) |
| Fan direction changed | direction (string), prev_direction (string) |
| Fan data point changed | dp (string), value (string) |
| Fan child lock switched | enabled as a filter — pick turned on or turned off |
| Fan oscillation switched | enabled as a filter — pick turned on or turned off |
| Condition |
|---|
| Fan is / is not connected |
| Fan mode is / is not [mode] |
| Fan direction is / is not [forward|reverse] |
| Fan child lock is / is not on |
| Fan oscillation is / is not on |
| Light is / is not on |
| Action | Notes |
|---|---|
| Set fan mode | normal / sleep / nature / breeze / smart |
| Set fan speed | low / medium / high / auto / turbo |
| Set fan oscillation | on / off — requires dp_oscillate > 0 |
| Set fan direction | forward / reverse — requires dp_direction > 0 |
| Set fan child lock | on / off — requires dp_child_lock > 0 |
| Set timer | Countdown before the fan switches itself off — requires dp_countdown_timer > 0 |
| Set light | on / off — the lamp built into the fan, requires dp_light_onoff > 0 |
| Set light brightness | 0–100 % — requires dp_light_dim > 0 |
| Set light mode (advanced) | Raw mode string for lamps with white / colour modes |
| Force fan reconnect | Drops and re-establishes the TCP connection |
| Refresh fan values | Triggers an immediate GET request |
Homey generates the light's own cards — Turn on, Turn off, Dim, Is on — automatically
from the onoff and dim capabilities, because the driver is a Light. It generates nothing for the
fan: sub-capabilities (onoff.fan, dim.fan) and app-defined capabilities (fan_speed, oscillate,
child_lock) get no cards of their own. Everything below is the driver making up that difference.
| Trigger | Flow tokens |
|---|---|
| Fan connected | — |
| Fan disconnected | — |
| The fan was switched on or off | on (boolean) |
| Fan mode changed | mode (string), prev_mode (string) |
| Fan direction changed | direction (string), prev_direction (string) |
| Fan data point changed | dp (string), value (string) |
| Ceiling fan child lock switched | enabled as a filter — pick turned on or turned off |
| Ceiling fan oscillation switched | enabled as a filter — pick turned on or turned off |
| Condition |
|---|
| Device is / is not connected |
| Fan is / is not running |
| Fan speed is / is not [speed] |
| Fan mode is / is not [mode] |
| Fan direction is / is not [forward|reverse] |
| The fan is / is not oscillating |
| The child lock is / is not on |
| Action | Notes |
|---|---|
| Turn the fan on or off | The fan only — the light keeps Homey's own on/off card |
| Set fan speed | low / medium / high / auto / turbo — requires dp_fan_speed > 0 |
| Set fan speed by percentage | 0–100 %, mapped onto speed_min … speed_max — requires dp_speed > 0 |
| Set fan mode | normal / sleep / nature / breeze / smart — requires dp_mode > 0 |
| Set fan direction | forward / reverse — requires dp_direction > 0 |
| Set fan oscillation | on / off — requires dp_oscillate > 0 |
| Set the child lock | on / off — requires dp_child_lock > 0 |
| Set timer | Countdown — requires dp_countdown_timer > 0 |
| Set light mode (advanced) | white / colour / scene / music — requires dp_light_mode > 0 |
| Force ceiling fan light reconnect | Drops and re-establishes the TCP connection |
| Refresh ceiling fan light values | Triggers an immediate GET request |
| Trigger | Filter tokens | Flow tokens |
|---|---|---|
| Humidity went above threshold | threshold (%) | humidity, prevHumidity |
| Humidity dropped below threshold | threshold (%) | humidity, prevHumidity |
| Water tank became empty | — | — |
| Water tank was refilled | — | — |
| Humidifier connected | — | — |
| Humidifier disconnected | — | — |
| Humidifier data point changed | — | dp (string), value (string) |
| Humidifier child lock switched | enabled as a filter — pick turned on or turned off |
— |
| Condition |
|---|
| Humidifier is / is not connected |
| Humidity is / is not above [value] % |
| Humidity is / is not below [value] % |
| Water tank is / is not empty |
| Humidifier child lock is / is not on |
| Action | Notes |
|---|---|
| Set target humidity | 25–95 % |
| Set humidifier mode | auto / manual / normal / sleep / eco / boost |
| Set humidifier fan speed | low / medium / high / auto |
| Set humidifier ioniser | on / off — requires dp_anion > 0 |
| Set humidifier child lock | on / off — requires dp_child_lock > 0 |
| Set humidifier timer | Countdown, cancel or 1–24 h — requires dp_countdown_timer > 0 |
| Force humidifier reconnect | Drops and re-establishes the TCP connection |
| Refresh humidifier values | Triggers an immediate GET request |
| Trigger | Flow tokens |
|---|---|
| Heater connected | — |
| Heater disconnected | — |
| Heater fault alarm triggered | — |
| Heater started heating | — |
| Heater stopped heating | — |
| Heater data point changed | dp (string), value (string) |
| Heater child lock switched | enabled as a filter — pick turned on or turned off |
| Heater oscillation switched | enabled as a filter — pick turned on or turned off |
| Condition |
|---|
| Heater is / is not connected |
| Heater fault alarm is / is not active |
| Heater is / is not actively heating |
| Heater mode is / is not [mode] |
| Heating level is / is not [level] |
| Heater child lock is / is not on |
| Heater oscillation is / is not on |
| Action | Notes |
|---|---|
| Set heater mode | eco / comfort / boost / away / auto |
| Set heater target temperature | Configurable min/max/step |
| Set heater child lock | on / off — requires dp_child_lock > 0 |
| Set heater timer | Countdown, cancel or 1–24 h — requires dp_countdown_timer > 0 |
| Set heating level | The element's power step — requires dp_heat_level > 0 |
| Force heater reconnect | Drops and re-establishes the TCP connection |
| Refresh heater values | Triggers an immediate GET request |
| Trigger | Flow tokens |
|---|---|
| Light connected | — |
| Light disconnected | — |
| Light data point changed | dp (string), value (string) |
| Condition |
|---|
| Light is / is not connected |
| Light colour mode is / is not [colour|white] |
| Action | Notes |
|---|---|
| Set light colour mode | Colour / White — switches work_mode on the lamp; requires dp_color_mode > 0 |
| Force light reconnect | Drops and re-establishes the TCP connection |
| Refresh light values | Triggers an immediate GET request |
Standard Homey light capabilities (
onoff,dim,light_hue,light_saturation,light_temperature,light_mode) are fully accessible via the built-in Homey flow cards.
| Trigger | Flow tokens |
|---|---|
| Device connected | — |
| Device disconnected | — |
| A data point changed | dp (string), value (string) |
| A specific data point changed | value, previous_value — pick the DP number in the card |
| Condition |
|---|
| Device is / is not connected |
| Action | Notes |
|---|---|
| Send DP command | Write any value to any data point — the escape hatch for anything the drivers do not cover |
| Refresh device values | Triggers an immediate GET request |
| Force reconnect | Drops and re-establishes the TCP connection |
| Trigger | Flow tokens |
|---|---|
| Pet feeder connected | — |
| Pet feeder disconnected | — |
| Food level changed | food_status (string), prev_status (string) |
| Feeding completed | — |
| Pet feeder data point changed | dp (string), value (string) |
| Feeder child lock switched | enabled as a filter — pick turned on or turned off |
Offline grace period: The "disconnected" trigger is delayed by the Offline Grace Period setting (default 60 s). Tuya pet feeder firmware briefly drops the TCP connection at certain intervals — without the grace period this causes spurious nightly offline notifications.
| Condition |
|---|
| Food level is / is not low |
| Pet feeder is / is not connected |
| Feeder child lock is / is not on |
| Action | Notes |
|---|---|
| Feed [[portions]] portion(s) now | Dispenses 1–50 portions immediately |
| Refresh pet feeder values | Triggers an immediate GET request |
| Set feeder child lock | on / off — requires dp_child_lock > 0 |
| Set feeder indicator light | on / off — requires dp_indicator_light > 0 |
| Set feeder voice playback | on / off — the announcement the feeder plays when it dispenses — requires dp_voice_playback > 0 |
| Force pet feeder reconnect | Drops and re-establishes the TCP connection |
| Trigger | Flow tokens |
|---|---|
| Heat pump connected | — |
| Heat pump disconnected | — |
| Heat pump mode changed | mode (string), prev_mode (string) |
| Silent mode changed | silent (boolean) |
| Fault alarm triggered | fault_code (string) |
| Heat pump data point changed | dp (string), value (string) |
| Condition |
|---|
| Heat pump is / is not on |
| Silent mode is / is not on |
| Fault alarm is / is not active |
| Heat pump is / is not connected |
| Action | Notes |
|---|---|
| Set operating mode | Values from mode_values setting — autocomplete in flow editor |
| Set preset | Values from preset_values setting — autocomplete in flow editor |
| Turn silent mode on or off | Needs dp_silent set — see the driver's Silent Mode section |
| Force heat pump reconnect | Drops and re-establishes the TCP connection |
| Refresh heat pump values | Triggers an immediate GET request |
| Trigger | Flow tokens |
|---|---|
| Garage door opened | — |
| Garage door closed | — |
| Garage door alarm triggered | alarm_state (string) — e.g. unclosed_time, close_time_alarm, openLongTime |
| Garage door opener connected | — |
| Garage door opener disconnected | — |
| Garage door data point changed | dp (string), value (string) |
Opened/closed triggers with action state DP: When using
dp_door_action(AOSD / BoboYun), the opened and closed triggers fire only on terminal states (opened/closed), not on intermediateopening/closingstates.
| Condition |
|---|
| Garage door is open / is closed |
| Garage door opener is / is not connected |
| Action | Notes |
|---|---|
| Open garage door | Sends open command via dp_door_control or dp_door_open |
| Close garage door | Sends close command via dp_door_control or dp_door_close |
| Stop garage door | Sends stop via dp_door_control (AOSD/ZC34T) or dp_switch (BoboYun). WOFEA: use Toggle instead |
| Toggle garage door | Sends a relay pulse on dp_switch — equivalent to pressing the wall button |
| Force garage door opener reconnect | Drops and re-establishes the TCP connection |
| Refresh garage door values | Triggers an immediate GET request |
| Trigger | Flow tokens |
|---|---|
| Curtain fully opened | — |
| Curtain fully closed | — |
| Curtain position changed | position (number, %) |
| Motor fault triggered | fault_code (string) |
| Curtain motor connected | — |
| Curtain motor disconnected | — |
| Curtain motor data point changed | dp (string), value (string) |
Opened / closed triggers fire when the position reaches 100 % (opened) or 0 % (closed). They do not fire during intermediate movement.
| Condition |
|---|
| Curtain is / is not open (> 50 %) |
| Curtain is / is not fully closed (= 0 %) |
| Curtain is / is not moving |
| Curtain motor is / is not connected |
| Action | Notes |
|---|---|
| Open curtain | Sends open on dp_control |
| Close curtain | Sends close on dp_control |
| Stop curtain | Sends stop on dp_control |
| Set curtain position to [%] | 0 = fully closed, 100 = fully open |
| Move curtain to favourite position | The position stored in the motor itself; requires dp_favourite > 0 |
| Force curtain motor reconnect | Drops and re-establishes the TCP connection |
| Refresh curtain motor values | Triggers an immediate GET request |
| Trigger | Flow tokens |
|---|---|
| Thermostat mode changed | mode (string), prev_mode (string) |
| Thermostat connected | — |
| Thermostat disconnected | — |
| Thermostat data point changed | dp (string), value (string) |
| Thermostat child lock switched | enabled as a filter — pick turned on or turned off |
| Condition |
|---|
| Thermostat mode is / is not [mode] |
| Thermostat is / is not connected |
| Thermostat child lock is / is not on |
| Action | Notes |
|---|---|
| Set thermostat mode | Uses values from mode_values setting |
| Set target temperature | Configurable min/max/step |
| Set thermostat child lock | on / off — requires dp_child_lock > 0 |
| Force thermostat reconnect | Drops and re-establishes the TCP connection |
| Refresh thermostat values | Triggers an immediate GET request |
| Trigger | Flow tokens |
|---|---|
| Kettle finished boiling | — |
| Kettle status changed | status (string), prev_status (string) |
| Kettle connected | — |
| Kettle disconnected | — |
| Kettle data point changed | dp (string), value (string) |
| Condition |
|---|
| Kettle is / is not heating |
| Kettle is / is not connected |
| Action | Notes |
|---|---|
| Set target temperature | 40–100 °C |
| Set kettle mode | Uses values from mode_values setting |
| Set keep warm | on / off |
| Force kettle reconnect | Drops and re-establishes the TCP connection |
| Refresh kettle values | Triggers an immediate GET request |
| Trigger | Flow tokens |
|---|---|
| A switch gang changed | gang (string: 1/2/3/4), state (boolean) |
| Wall switch connected | — |
| Wall switch disconnected | — |
| Wall switch data point changed | dp (string), value (string) |
| Condition |
|---|
| Switch gang is / is not on |
| Wall switch is / is not connected |
| Action | Notes |
|---|---|
| Set switch gang on or off | Select gang (1–4) and state (on/off) |
| Toggle switch gang | Inverts current state of selected gang |
| Force wall switch reconnect | Drops and re-establishes the TCP connection |
| Refresh wall switch values | Triggers an immediate GET request |
| Trigger | Flow tokens | Notes |
|---|---|---|
| Doorbell rang | — | Fires on every ring event (DP 136 or decoded ipc_doorbell in DP 185) |
| Motion detected | — | Fires when motion starts; auto-clears after motion_reset_seconds |
| Doorbell connected | — | Device established a LAN connection |
| Doorbell disconnected | — | Connection lost after offline grace period |
| Doorbell data point changed | dp (string), value (string) |
Any raw DP change |
| Condition |
|---|
| Motion is / is not active |
| Night light is / is not on |
| Doorbell is / is not connected |
| Action | Notes |
|---|---|
| Enable motion detection | Sets dp_motion_switch DP to true; throws error if DP is set to 0 |
| Disable motion detection | Sets dp_motion_switch DP to false; throws error if DP is set to 0 |
| Set night vision | Select mode: Auto / Off / Color (always on); requires dp_nightvision ≠ 0 |
| Set chime volume | Enter volume 0–100 (step 10); requires dp_chime_volume ≠ 0 |
| Set motion sensitivity | Select Low / Medium / High; requires dp_motion_sensitivity ≠ 0 |
| Set night light | on / off; requires dp_night_light > 0 |
| Set alarm reporting | Whether the doorbell reports its alarm events; requires dp_alarm_report > 0 |
| Set ring tone | Select one of the chimes the device carries; requires dp_ring_tone > 0 |
| Force doorbell reconnect | Drops and re-establishes the TCP connection |
| Refresh doorbell values | Triggers an immediate GET request |
| Trigger | Flow tokens |
|---|---|
| Doorbell pressed | — |
| Lock state changed | locked (boolean) |
| A specific data point changed | value, previous_value, code — pick the DP number in the card |
| Access panel connected | — |
| Access panel disconnected | — |
| Access panel data point changed | dp (string), value (string) |
| Condition |
|---|
| Door is / is not locked |
| Door is / is not open |
| Access panel is / is not connected |
| Action | Notes |
|---|---|
| Set hold open | Keeps the door released until switched back — requires dp_hold_open > 0 |
| Set automatic locking | Whether the door re-locks by itself — requires dp_auto_lock > 0 |
| Set automatic locking delay | Seconds before it does — requires dp_auto_lock_delay > 0 |
| Set alarm duration | How long the panel sounds its alarm — requires dp_alarm_duration > 0 |
| Set doorbell volume | Requires dp_doorbell_volume > 0 |
| Force access panel reconnect | Drops and re-establishes the TCP connection |
| Refresh access panel values | Triggers an immediate GET request |
| Trigger | Flow tokens | Notes |
|---|---|---|
| Presence detected | — | Radar reports presence |
| Presence cleared | — | Radar reports none (after dp_fading_time) |
| Presence sensor connected | — | Device established a LAN connection |
| Presence sensor disconnected | — | Connection lost after offline grace period |
| Presence sensor data point changed | dp (string), value (string) |
Any raw DP change |
| Condition |
|---|
| Presence is / is not active |
| Presence sensor is / is not connected |
| Action | Notes |
|---|---|
| Force presence sensor reconnect | Drops and re-establishes the TCP connection |
| Refresh presence sensor values | Triggers an immediate GET request |
Homey generates the smoke, battery, tamper and self-test alarm cards itself from the standard capabilities. The cards below are the driver's own additions.
| Trigger | Flow tokens | Notes |
|---|---|---|
| Smoke level rose above | level (number) |
Fires the moment the reading crosses the threshold in the card, not on every reading above it. The early warning — the concentration rises before the detector sounds |
| Self-test finished | result (string), passed (boolean) |
Fires however the test was started — from a flow, or by pressing the button on the detector |
| Detector connected | — | Device established a LAN connection |
| Detector disconnected | — | Connection lost after offline grace period |
| Detector data point changed | dp (string), value (string) |
Any raw DP change |
| Condition |
|---|
| Smoke level is / is not above [ppm] |
| Detector is / is not connected |
| Action | Notes |
|---|---|
| Silence the alarm | Writes dp_muffling. Does not clear the smoke reading — the alarm returns while smoke is still present |
| Run self-test | Writes dp_self_test_start; the outcome arrives on the trigger above |
| Force detector reconnect | Drops and re-establishes the TCP connection |
| Refresh detector values | Triggers an immediate GET request |
Homey generates Start charging, Stop charging, Is charging and a charging-state trigger automatically from the native EV charger capabilities, plus Set target power from target_power. The cards below are the driver's own additions.
| Trigger | Flow tokens | Notes |
|---|---|---|
| Charging session finished | energy (number) |
Fires when the charger leaves the charging state, with the kWh delivered in that session |
| Detailed charger state changed | state, prev_state (string) |
Raw Tuya state — distinguishes waiting / finished / plugged in, which Homey's standard state groups together |
| Charging mode changed | mode, prev_mode (string) |
Fires however the mode was changed — from Homey, at the charger, or in the manufacturer's app. Requires dp_work_mode > 0 |
| Charger fault occurred | fault_code (number) |
Raw 16-bit fault bitmap value, debounced against reconnect artifacts |
| Charger connected | — | Device established a LAN connection |
| Charger disconnected | — | Connection lost after offline grace period |
| Charger data point changed | dp (string), value (string) |
Any raw DP change |
| Condition | Notes |
|---|---|
| Detailed charger state is / is not | Compares the raw Tuya work_state — finer-grained than Homey's standard state |
| Charging mode is / is not | Compares the raw Tuya work_mode: Charge Now, Charge to %, Charge kWh, Scheduled, Delayed Start |
| Charger is / is not connected | — |
| Action | Notes |
|---|---|
| Set charge current | Enter amps; clamped to current_min … current_max and converted to watts internally. Homey's built-in Set target power covers the same DP in watts |
| Set charging mode | Switches between Charge Now, Charge to %, Charge kWh, Scheduled and Delayed Start. Several chargers ignore the charge switch while they are in scheduled mode, so this belongs before Start charging in such a flow |
| Reset energy meter | Clears the accumulated total; also sends the device's own clear-energy command when dp_clear_energy is set |
| Force charger reconnect | Drops and re-establishes the TCP connection |
| Refresh charger values | Triggers an immediate GET request |
| Trigger | Flow tokens |
|---|---|
| Device connected | — |
| Device disconnected | — |
| A data point changed | dp (string), value (string) |
| Condition | Notes |
|---|---|
| Device is / is not connected | |
| Power is / is not above [watts] | |
| Current is / is not above [amps] | Useful as an overload warning on a circuit whose breaker rating you know |
| Fault is / is not active | dp_fault above zero |
| Action | Notes |
|---|---|
| Force reconnect | Drops and re-establishes the TCP connection |
| Refresh device values | Triggers an immediate GET request |
Homey generates cards for the measurement capabilities itself. The cards below are the driver's own additions.
| Trigger | Flow tokens |
|---|---|
| Weather station connected | — |
| Weather station disconnected | — |
| Comfort level changed | comfort (string), prev_comfort (string) |
| Weather station data point changed | dp (string), value (string) |
| Condition | Notes |
|---|---|
| Weather station is / is not connected | |
| Comfort level is / is not [level] | moist / dry / comfortable / na |
| Wind speed is / is not above [value] | |
| Wind is / is not from [direction] | Compass point, taken from wd_values |
| Action | Notes |
|---|---|
| Force weather station reconnect | Drops and re-establishes the TCP connection |
| Refresh weather station values | Triggers an immediate GET request |
| Trigger | Flow tokens |
|---|---|
| Level sensor connected | — |
| Level sensor disconnected | — |
| Level state changed | state (string), prev_state (string) |
| Liquid level rose above [percent] | level (number) |
| Liquid level dropped below [percent] | level (number) |
| Level sensor data point changed | dp (string), value (string) |
| Condition | Notes |
|---|---|
| Level sensor is / is not connected | |
| Level state is / is not [state] | normal / lower_alarm / upper_alarm |
| Liquid level is / is not above [percent] |
| Action | Notes |
|---|---|
| Set high threshold | Writes dp_max_set on the device |
| Set low threshold | Writes dp_mini_set on the device |
| Enable or disable a level alarm | Writes dp_upper_switch / dp_lower_switch |
| Force level sensor reconnect | Drops and re-establishes the TCP connection |
| Refresh level sensor values | Triggers an immediate GET request |
| Event | Driver | Condition |
|---|---|---|
| Water tank is full | Dehumidifier | Alarm active — debounced to suppress reconnect artifacts |
| Water tank is empty | Humidifier | alarm_water transitions false → true |
| Fault detected | Smart Plug | alarm_generic transitions false → true |
| Fault detected | Air Conditioner | alarm_generic transitions false → true (debounced, 30 s grace on reconnect) |
| Fault detected | Heater | alarm_generic transitions false → true (debounced, 30 s grace on reconnect) |
| Fault detected | Heat Pump | alarm_generic transitions false → true (debounced, 30 s grace on reconnect) |
| Food level low / empty | Pet Feeder | food_status transitions to any value in food_empty_values (default: low,less,empty,lack) |
| Motor reports no food | Pet Feeder | motor_state = no_food — hopper empty during feeding attempt |
| Garage door left open | Garage Door | Alarm state unclosed_time (WOFEA) or openLongTime (BoboYun) — uses "left open" message |
| Garage door alarm | Garage Door | Any other alarm state (e.g. close_time_alarm, closeLongTime) — uses generic fault message |
| Motor fault detected | Curtain Motor | alarm_generic transitions false → true (debounced, 30 s grace on reconnect) |
| Fault detected | EV Charger | Fault bitmap becomes non-zero (debounced against reconnect artifacts) |
Open Homey app → More → Apps → Tuya Local → Settings.
Timestamped in-memory buffer (max 500 entries, cleared on app restart):
| Level | Meaning |
|---|---|
[INF] |
Normal events: connect, disconnect, capability updates |
[WRN] |
Warnings: reconnect attempts, stale connection, rejected capability option values |
[ERR] |
Errors — includes ECONNRESET hint when a protocol version mismatch is likely |
Repeated identical messages are automatically suppressed: the first 3 occurrences are shown in full, then one summary every 10th repeat, and a final "suppressed N more times" note when the message changes.
Every data point the app has received from a device, which is how you find out which DP carries what: operate the device with its own buttons while watching the table, and the DP that moves is the one the setting needs to point at.
- Select a device from the dropdown
- Shows DP number, current value, and type
- Colour-coded: green =
true, red =false, purple = number, orange = string - Auto-refresh re-reads every 5 seconds — switch it on before operating the device, otherwise a DP can change and change back between two looks
- Copy Local DP Table, Report on GitHub and Copy for forum package the table for a bug report
What this panel cannot show is what the numbers mean: the local protocol never transmits a name, a type or an allowed range. Cloud Lookup does, which is why the two are used together.
Five checks that compare your devices against what Tuya declares for them. Each one previews exactly what it would change, device by device, says why a device was left alone, and saves nothing until you confirm. All except protocol versions need Cloud Lookup credentials.
| Check | What it finds |
|---|---|
| Check local keys | A local key changes every time the device is reset or re-paired in the Tuya app, and the symptom is a device that never connects again. Compares the stored key against your account. Keys are shown shortened, never in full |
| Check protocol versions | The device is connected and answering on a different version than the settings say. Waits for the device to answer first, so it cannot save a version a device was merely stuck on |
| Check measurement scaling | Readings that are 10× or 100× off, using the divisor Tuya declares rather than leaving you to work it out from the number |
| Update pickers on existing devices | Mode and fan-speed lists that were seeded from whatever the device happened to report at pairing time. Never touches DP numbers |
| Find data points your device does not have | Driver defaults written for one device family pointing at nothing on another. A DP is only reported when the specification does not list it and your device has never once reported it |
A per-driver reference inside the app: what each driver covers, what its data points mean, and the faults that come up most often. Linked from the other tabs where a topic needs more room than a tooltip.
Fetch device credentials and DP specifications from the Tuya IoT Platform (available in app settings and during pairing):
- Enter your Access ID and Access Secret from iot.tuya.com → Cloud → Project Management → your project → Overview
- Select your Data Center and click Fetch Devices
- Device list shows the custom name (as set in the Tuya app) as the primary name, with the product model name as a subtitle
- Click a device name to see the full DP specification: DP numbers, code names, types, current values, allowed ranges, and read/write status
- Copy button per device copies all available fields: custom name, name, Device ID, Local Key, product, category, UUID
- Check Save credentials on Homey to persist your Access ID, Secret, and region — they are auto-filled next time you open Cloud Lookup in settings or pairing
- Useful for finding exact enum strings (
mode,fan_speed, etc.)
| Symptom | Likely cause | Fix |
|---|---|---|
| Device stays unavailable | Wrong IP, Device ID or Local Key | Open the device in Homey → Settings → update the credentials; check the Logs tab for the exact error |
| ECONNRESET on every connect | Protocol version mismatch | Open device Settings → set Protocol Version to Auto-detect, or manually try 3.3, 3.4, 3.1, 3.5 in turn |
| Device connects but values are wrong | Incorrect DP numbers | Adjust DPs in device settings |
| Smart Plug power reading is 10× off | Wrong power scale | Change Power Scale setting to ×0.1 |
Energy (kWh) shows — or never updates |
dp_energy set to 17 but device sends delta locally |
Set dp_energy = 0 — app will compute kWh from power readings |
| AC / Heater temperature is 10× too high | Device sends ×10 scaled values | Set temp_divisor = 10 in device settings |
| Heat pump target temp correct but measured temp is 10× too high | Asymmetric DP scaling (e.g. Weau): target DP is raw °C but measured DP is ×10 | Set Measured Temperature Divisor (override) (current_temp_divisor) to 10, leave the main temp_divisor at 1 |
| Mode / fan picker shows wrong options | mode_values / fan_speed_values mismatch |
Update values in device settings, then restart the Tuya Local app |
| Picker still shows old options after saving | Homey caches capability options | Restart the Tuya Local app |
| Light color mode not working | Wrong color_mode_white_val / color_mode_color_val |
Check the DP Debug tab for the actual strings sent by the device (e.g. white, colour, color) |
| Humidifier water alarm fires on connect | Device sends transient alarm on reconnect | Built-in debounce suppresses these; if they persist increase the alarm guard window |
| Spurious fault alarm after reconnect | Reconnect artifact | Built-in 30 s grace period on reconnect suppresses these (AC, Heater, Heat Pump) |
| Heat pump mode/preset picker does nothing | DP was enabled after initial pairing — listener not registered | Restart the Tuya Local app; the listener is re-registered on next onInit |
| Pet feeder sends 3–4 "disconnected" notifications per night | Tuya firmware briefly drops TCP connection at timed intervals | Increase Offline Grace Period in device settings (default 60 s already handles most cases; try 120 s if it still fires) |
| Generic device shows raw key as label | Missing locale key | Set labels via the label field in the dp_config mapping |
| Curtain position slider is inverted | Device uses 0 = open, 100 = closed | Enable invert_position in device settings |
| Curtain tile shows "moving" but motor has stopped | work_state DP not resetting on this device |
Set dp_work_state = 0 to disable it |
| Curtain motor limit positions are wrong | Motor limits not calibrated | Run limit calibration from the Tuya / Smart Life app (DP 16 border) before using Homey |
| Thermostat temperature is 10× too high | Device sends ×10 values (e.g. BHT-002, Moes) | Set temp_divisor = 10 in device settings |
| Thermostat mode picker shows wrong options | mode_values mismatch |
Check the DP Debug tab for the actual strings, update mode_values in settings |
Thermostat heating indicator (alarm_heat) never activates |
dp_hvac_action not set |
Set DP HVAC Action in device settings to the DP that reports heating/1/true when the boiler fires |
| A multi-gang switch shows only one channel | It was paired on the Smart Plug driver, which has a single dp_switch. Its cloud specification gives it away: switch_1 … switch_4 and no power, voltage or current at all |
Remove it and pair it on the Wall Switch driver, which has dp_switch_1 … dp_switch_4. A device cannot change driver. Countdowns are not auto-detected — enter dp_countdown_1 … _4 by hand if you want per-channel timers |
| Wall switch trigger doesn't fire for switch 2+ | Using Homey's built-in "Turned on/off" trigger | Use the Wall Switch-specific "A switch gang changed" trigger card instead |
| Wall switch tile names don't update | Homey caches capability titles | Restart the Tuya Local app after changing switch names |
| Kettle mode picker empty | mode_values doesn't match device strings |
Check DP Debug for the exact mode strings (some use mzj_black, boiling_quick, etc.) |
| Device missing DPs or SET commands rejected | Standard Instruction Set hides some DPs | Switch to DP Instruction Set on iot.tuya.com → Devices → your device → Instruction Mode |
| Cloud Lookup shows fewer DPs than expected | Same cause — Standard mode limits visible DPs | Switch to DP Instruction mode, then re-fetch in Cloud Lookup |
| SET command causes disconnect | Device rejects encrypted command | 1) Refresh Local Key via Cloud Lookup. 2) Enable Fire and Forget in device settings. 3) Switch instruction mode to DP on iot.tuya.com |
Device unavailable immediately — log shows Invalid local key length |
Local Key is not exactly 16 characters — likely a copy/paste truncation | Open device Settings → re-enter the Local Key (must be exactly 16 characters) |
| Curtain motor / push-only device enters connect → timeout → disconnect loop | Firmware does not respond to GET requests (e.g. BCM700D-TY01) | Set Polling Interval to 0 in device settings — the device will stay connected and push DPs and accept commands normally |
| Protocol version mismatch after firmware OTA update | OTA changed the required protocol; configured version no longer works | The app auto-rotates through 3.3 / 3.4 / 3.1 / 3.5 / 3.2 after 5 failed reconnects and logs which version connected — update Protocol Version in device settings to that version to skip the retry delay |
| Device goes offline after a while and never recovers | Auto-Reconnect Interval set very low, tearing down healthy connections | Fixed in 1.0.128 — auto-reconnect now only fires while the device is genuinely offline. Set the interval back to 0 or a few minutes |
| Mode or fan-speed tile stays empty | Device reports values that are not in the picker's list (often plain numbers) | Check the raw value in DP Debug, then set mode_values / fan_speed_values to match exactly (e.g. 0,1) and restart the app |
| Newly enabled tile does not respond to taps | Capability listener registered only at startup | Fixed in 1.0.129 for Fan and Dehumidifier. On other drivers, restart the Tuya Local app once |
| Generic picker shows raw numbers instead of labels | readMap was previously ignored on numeric DPs |
Fixed in 1.0.140. Add a readMap with the raw values as text keys: {"0":"Auto","1":"Continuous"} |
| EV charger total energy never increases | Charger's lifetime counter (DP 1) does not update over LAN | Leave dp_energy_total at 0 — the total is then accumulated from the session counter |
| EV charger session energy is 100× too low / current 10× too high | Charger uses a different DP scale than the majority | Adjust session_energy_scale, total_energy_scale or current_scale in device settings |
| EV charger power slider range looks wrong | current_min / current_max / phase_count don't match the hardware |
Set them to your charger's real amp range and phase count — the watt range is derived (W = A × V × phases) |
| EV charger shows no voltage / current / power | Charger only streams live values while online_state is online |
Set dp_live_updates = 27 — the app re-asserts it on every reconnect |
| EV charging mode picker has no effect | Charger advertises modes it does not implement | Set dp_work_mode = 0 to hide the picker; DP 33 (mode_set) declares what the hardware really supports |
Endless connect → ECONNRESET loop, log always says attempt 1 |
Protocol 3.1/3.2/3.3 has no session handshake, so the open TCP socket was read as success and cleared the failure counter — the version rotation never reached its five failures | Fixed in 1.0.208. A connection now only counts once the device answers. Afterwards, set Protocol Version to the version the log says actually worked |
| Device shows as connected but commands do nothing | Firmware still answers keep-alive pings while it has stopped answering everything else; on 3.4/3.5 a SET is fire-and-forget, so the app sees no error | Fixed in 1.0.190 — a device silent for three polling cycles is reconnected. If it recurs, reduce Polling Interval so the watchdog window closes sooner |
| Two commands in one flow, only the first arrives | Firmware cannot keep up with commands sent microseconds apart, and nothing on 3.4/3.5 reports a dropped SET | Raise Command Gap in device settings (default 100 ms; a reported heater needed 2000 ms) |
| Energy meter shows no readings at all | The DP numbers alone cannot say which number is the power and which the voltage — on this device family the same number means different things on different models | Set up Cloud Lookup and pair again: it matches by the manufacturer's own code names. Or read the numbers off DP Debug and enter them by hand |
| Ceiling fan light: the main on/off switches the fan, not the light | dp_light_onoff not detected at pairing |
Set DP Light On/Off in device settings — that DP drives the main onoff; the fan sits on its own dp_onoff |
Device connects and stays connected, but data ever received: NO |
The address may belong to a different Tuya device. One that is not yours still accepts the connection and answers keep-alives — those need no key — and discards everything encrypted, which looks exactly like a wrong key | Start Add device → Tuya Local → (any driver) and press Scan Network, then cancel. Tuya devices announce their Device ID in the clear, so the list shows which ID is at which address. Check this before chasing the Local Key, and give the device a DHCP reservation afterwards |
Log repeats HMAC mismatch and no values ever arrive |
On 3.4/3.5 the signature on every frame is computed from the Local Key and nothing else, so a mismatch means the stored key does not belong to this device. It changes every time the device is re-added in the Smart Life app | Fix It → Check local keys compares every device against your Tuya account and corrects the ones that no longer match. Without cloud credentials, re-copy the key from the Tuya IoT Platform |
| Check local keys reports an error and compares nothing | Your Tuya project refuses to list its devices. Listing and per-device access are permissioned separately, so the specification of a device can be readable while the account listing is not | The check now falls back to asking for each device by its id. If it still finds nothing, open the Tuya IoT Platform → your project → Link Tuya App Account and re-link your Smart Life account. The support report names the exact refusal |
| EV charger reports voltage and current per phase, but the fields stay empty | Some chargers name those data points themselves (A_Voltage, A_Current, DeviceKw) instead of using the standard code names |
Cloud Lookup now recognises those names — pair the device again, or read the numbers off DP Debug and enter dp_voltage_a … dp_current_c by hand |
| EV charger: Session Energy stays empty and the total never moves | On chargers with vendor code names, DP 25 (charge_energy_once) is never sent — their session counter is DP 112 (DeviceKwh), which rises during a charge and returns to 0 afterwards |
Set dp_session_energy = 112, dp_energy_total = 0 and Total Energy Source to session. The app then builds the lifetime total from completed sessions. Watch the Logs tab: it names any unmapped data point that is counting up |
| EV charger: voltage reads ~2400 V, power is far too low | Those chargers scale differently on all three quantities, and DeviceKw counts tenths of a kilowatt, not watts |
voltage_scale 0.1, amp_scale 0.1, power_scale 100. Check the result against itself: volts × amps × phases must come out near the reported power |
| EV charger: Charging state stays empty | The charger reports its state on DP 101 (DeviceState: no_connet, connect, charing, …) rather than on DP 3 (work_state), which it never sends |
Not yet read by the app. Set dp_work_state = 0 so the setting does not look configured; the tile fills once support for that vocabulary ships |
- tuyapi ^7.5.2 — Tuya LAN protocol implementation
lib/SafeTuyAPI.js— a thin subclass around it. The library parses incoming packets on the socket's own event, outside any promise, so a malformed frame threw where nothing could catch it and took the whole app down with it. The subclass guards the packet handler and routes the failure back into the connection that caused itlib/TuyaConnection.js— connection lifecycle: reconnect back-off, protocol rotation, the heartbeat and stale-data watchdogs, command queueing and pacing- Node.js built-ins:
dgram,net,os,dns - Homey App SDK v3
Bug reports and feature requests → GitHub Issues
Donations → PayPal
MIT