A TS0601 device pairs to Zigbee2MQTT without any errors, then shows up as unsupported, or worse, interviews successfully and exposes almost nothing useful. Neither outcome means Zigbee2MQTT failed to recognize the device. TS0601 is not a device family. It’s a generic modelID that a large slice of Tuya’s Zigbee modules report regardless of what the finished product actually does, so radiator valves, curtain motors, multi-sensors, and dozens of other unrelated products all show up under the exact same label.
This is a different problem from Zigbee2MQTT’s more common no converter available error, which happens when a device has no converter at all. A TS0601 device usually does have some converter path already written somewhere in Zigbee2MQTT’s codebase. The trouble is figuring out which one applies, and Zigbee2MQTT can’t do that from the modelID alone. Neither can you, until you go find out exactly what your specific unit sends.
The fix stays entirely local, which matters if you moved to Zigbee2MQTT to get off Tuya’s cloud in the first place. It’s also the kind of problem that shows up right after migrating a Tuya gateway to Zigbee2MQTT, when devices that worked fine under the Tuya app suddenly need Zigbee2MQTT to know what to do with them. This is Zigbee2MQTT’s own documented process for exactly this situation: turn on debug logging, read the values your device actually sends, and write a small external converter that maps them to something usable. No cloud account, no support ticket, no waiting on a pull request to land.
“TS0601” is a label, not a device
Tuya’s Zigbee modules commonly report a modelID of TS0601 regardless of what they’re built into. A curtain motor, a radiator valve, and a multi-function sensor can all report the identical string. Zigbee2MQTT’s own reference documentation on supporting new Tuya devices spells this out. modelID alone can’t identify what you’re holding.
To work around it, Zigbee2MQTT matches a fingerprint instead: the modelID combined with the manufacturerName, a string that looks like _TZE200_d0yu2xgi or _TZE204_xxxxxxxx. That manufacturerName is specific enough to point at a particular product, or a small family of rebadged ones, where the modelID alone is not.
This applies to any TS0601-labeled device, not one product category. The mechanism is the same whether the unmapped device is a valve, a curtain motor, or something else entirely. Zigbee2MQTT’s own docs on this are written for contributors submitting new device support, not first-time readers, which is a lot of why this specific failure mode confuses people who’ve otherwise gotten comfortable with Zigbee2MQTT.
Why “not supported” and “missing entities” are different problems
If Zigbee2MQTT has no fingerprint entry matching your device’s manufacturerName at all, you get the plain not supported result. Nothing is mapped, so nothing useful shows up.
If your manufacturerName does match an existing converter, you inherit whatever datapoints that converter’s author already mapped. When some entities are still missing anyway, it’s usually one of two things: the original contributor mapped only a subset of the datapoints their unit exposed, or your particular unit is a firmware or hardware revision that reports extra datapoints under the same manufacturerName. Either way, the unmapped values show up as unhandled lines in the log even though the device technically has support.
Either case, the fix is the same process. Find the unmapped datapoints, and either add to an existing converter or write a new one.
Step 1: turn on debug logging and capture what your device actually sends
Zigbee2MQTT’s documented approach is to enable debug-level logging, then physically trigger the device. Set log_level to debug under the advanced: section of your configuration.yaml (or change the log level under Settings in the Zigbee2MQTT frontend), then press its buttons, change its state, whatever it does. Every datapoint your device reports that Zigbee2MQTT doesn’t already have mapped for your manufacturerName shows up as a log line giving you the datapoint ID and the raw value.
Datapoint '106' with value '77' not defined for '_TZE200_d0yu2xgi'
That single line is the whole discovery mechanism. The datapoint ID is 106. The raw value at the moment you triggered the device was 77. The manufacturerName is _TZE200_d0yu2xgi. Trigger a different function and you get a different line, same format, different numbers.
Step 2: read the log lines against what you just did
Say the unmapped device is a TS0601 radiator valve. The mechanism here applies identically to a curtain motor or a multi-sensor, since discovery has nothing to do with what the device physically does. Set a target temperature, and a datapoint fires. Open the valve fully, and a different datapoint fires. Note the datapoint ID and the value each time, next to the action you just took.
This is trial and error, not documentation lookup. There’s no public spec sheet mapping datapoint IDs to functions for a given product. (Tuya’s IoT developer platform can list a product’s datapoints, but that means creating a developer account and linking the device back through Tuya’s cloud — the opposite of what you’re here for.) So you reverse-engineer it locally, one action at a time, by watching which datapoint changes when you do something.
Do this methodically. Trigger one function, note the line, wait a moment, trigger the next. Mash every button before checking the log and you end up with a pile of datapoint IDs and no idea which action produced which one.
Step 3: write a minimal tuyaDatapoints converter
Zigbee2MQTT’s Tuya-specific converters use a tuyaDatapoints array. Each row follows the format [datapoint_id, 'state_key_name', valueConverter], mapping one raw datapoint number to a published state key through a value transformer.
fingerprint: [
{modelID: 'TS0601', manufacturerName: '_TZE200_d0yu2xgi'},
],
meta: {
tuyaDatapoints: [
[106, 'state_key_name', valueConverter],
// one row per datapoint your own debug log surfaces
],
},
The fingerprint block is what solves the modelID collision problem from the first section. It tells Zigbee2MQTT that this specific manufacturerName, not every device that happens to report TS0601, should use this converter. The snippet above is only the TS0601-specific part. A complete converter file also needs the surrounding definition boilerplate: the fromZigbee and toZigbee Tuya datapoint handlers, plus an exposes block declaring the entities each datapoint maps to. Zigbee2MQTT’s reference documentation on supporting new Tuya devices carries the current full-file template, and because those field names shift between versions, copy the skeleton from there rather than from an older third-party example. The companion piece on the generic no converter available error covers installing and loading an external converter file itself. What’s specific to TS0601 is the fingerprint and the datapoint mapping above it.
Common value converters, and when to reach for each
| Value converter | What it does | Typical use |
|---|---|---|
| tuya.valueConverter.raw | Publishes the datapoint’s value unchanged | States already correct as sent, like a plain on/off flag |
| tuya.valueConverter.divideBy10 | Scales the integer down by a factor of ten | Temperature or humidity datapoints sent as whole-number integers |
| tuya.valueConverterBasic.lookup({…}) | Maps numeric codes to readable string states | Mode selectors and other enumerated states |
Match the converter to what the raw value looks like in your log. A value like 210 for what should be a 21.0-degree setpoint is a divideBy10 case. A value that only ever shows 0 or 1 for a state you can toggle is usually raw. A value that cycles through a small fixed set of integers when you switch modes is a lookup table waiting to happen.
When a working converter suddenly breaks after a Zigbee2MQTT update
External converter syntax isn’t guaranteed stable across Zigbee2MQTT versions. A converter that worked fine for months can stop working after an update, with no change on your end.
Multiple issue threads opened across 2026 describe this exact pattern: a device that was working, an update, then broken exposes with no configuration change on the user’s side. If a TS0601 converter that used to work suddenly doesn’t, checking whether it’s an update-related syntax break is a reasonable first step, not just something to check after first pairing a device.
Check first: has someone already solved your manufacturer string
Before writing a converter from scratch, search for your exact manufacturerName string. Someone else’s TS0601 device reporting the identical _TZE200_ or _TZE204_ string is functionally the same hardware as yours, so their converter, or their GitHub issue describing the datapoint mapping, saves you the entire discovery step. A converter written for a different manufacturerName is a different device, even if it’s also labeled TS0601, and won’t apply to yours.
Worth knowing: a matching GitHub issue for your exact manufacturer string doesn’t guarantee a drop-in converter file. Expose naming and coverage vary between contributors. But it reliably tells you what each datapoint means, which is the part that actually takes time.
The fingerprint-based design is a reasonable tradeoff given how thoroughly Tuya’s module-and-relabel model has commoditized this modelID. A single all-purpose TS0601 converter would either expose entities that don’t exist on your device or silently miss ones that do. Matching on manufacturerName is more work upfront, but it’s the only version of this that’s actually correct per device.
If your device pairs and interviews cleanly but the entity list still looks wrong for reasons that have nothing to do with datapoints, like ghost entries, duplicate devices, or phantom rejoin attempts, that’s a separate class of problem.
What this covers, and what to check on your own device
The fingerprint mechanism, the tuyaDatapoints array format, and the three common value converters above are all sourced from Zigbee2MQTT’s own reference documentation on supporting new Tuya devices. The update-breaking pattern is cross-referenced against multiple separate GitHub issue threads describing the same symptom on different converters. None of this involved a specific device on a test bench. It’s a documented, device-agnostic mechanism, not something verified hands-on for one particular TS0601 unit here.
The whole workflow stays local. Discovery happens in your own Zigbee2MQTT log. The converter file lives on your own machine. None of it touches Tuya’s cloud or requires a Tuya account at any point.
What still depends on outside information: there’s no public spec sheet mapping a given datapoint ID to a function for a specific device, so the mapping is inferred locally by watching what changes when you trigger a function, not looked up. Before you start, confirm your own manufacturerName string from your pairing log or device page, and search existing GitHub issues under that exact string first. Keep the finished converter file backed up somewhere outside Zigbee2MQTT’s own directory. It isn’t part of the version-controlled repository, so nothing protects it from an update or a config reset.
If your converter eventually gets formally merged into zigbee-herdsman-converters, the external file becomes redundant and you can delete it, which is about the best outcome a workaround like this can have.