← all posts
Fri 13 Nov 2026 · 4 min read

Review: Tuya TS1201 Zigbee IR Blaster

TL;DR This blaster works. If you can get it for the right price, it’s worth picking up.

After getting my Bosch air con talking to Home Assistant through a HOBEIAN ZG-IR01, I picked up a second IR blaster for the master bedroom. This time I went for a Tuya TS1201.

The TS1201 IR blaster on a wooden table: a flat, round, matte black puck with a small button on its side and a black USB-C cable plugged into the back.

What It Is

I bought it from AliExpress for £8.99. It’s a flat, round black puck that reports itself to ZHA as manufacturer _TZ3290_7v1k4vufotpowp9z, model TS1201.

It’s powered over USB-C rather than batteries, which means no more battery swapping, but does mean it needs to be near a power source. The ZG-IR01 runs off two AAAs, but does have the advantage of a couple of extra sensors.

Pairing with ZHA

This is where it beats the ZG-IR01; it worked first time: it paired, and ZHA’s built-in ZosungIRBlaster_ZS06 quirk (from zhaquirks.tuya.ts1201) picked it up straight away. There’s no custom quirk to write, no full restart of Home Assistant, and no sequence-number bug to bodge around1.

ZHA creates three entities:

  • a switch (I don’t know what this does…)
  • a firmware update entity (it’s on firmware 0x00000043)
  • an identify button

Learning Codes

Learning works the same way as the ZG-IR01: issue IRLearn on the IR Control cluster (0xE004), point the remote at the blaster, press a button and read back last_learned_ir_code. Once it was in learn mode, it read the remote’s codes without any fuss.

The Code Format

What comes back is different though. The ZG-IR01 gives Broadlink-style JgD… codes: a header, then pulse lengths in ticks of 1/32768 s. The TS1201 returns Tuya’s own format, which mildsunrise has documented in a gist. Working from the code back to the signal:

  1. Base64-decode the string.
  2. Decompress the bytes. It’s FastLZ (level 1), a small LZ77-style scheme, which the gist’s author spotted in a later update2.
  3. Read the result as 16-bit little-endian numbers. Each one is a duration in microseconds, alternating mark (IR on) and space (IR off), starting with a mark.

So the start of the air con’s tilt code, after decompressing, looks something like this (with the timings rounded):

3011header mark: 4400 µs
3011header space: 4400 µs
F401bit mark: 500 µs
6806space: 1640 µs, a 1

The first four timings, two bytes each, least significant byte first. 0x1130 is 4400 µs, 0x01F4 is 500 µs and 0x0668 is 1640 µs.

Drawn out as the signal, those four numbers look like this:

4400 / 4400 µs500 / 1640 µs
headerfirst bit: a 1

The same four timings to scale: the IR is on for the raised parts (marks) and off for the rest (spaces). A long space after a bit’s mark makes it a 1, a short one a 0.

That’s a much more sensible unit than the Broadlink ticks, but it means codes from one blaster won’t simply paste into the other. Decoded, the timings matched the ZG-IR01’s captures of the same remote, which is how I captured the air con’s extra buttons. There’s a post on those coming soon.

Sending Codes

The same format goes the other way too. The TS1201 expects the codes it’s sent with IRSend to be in Tuya’s format, not the Broadlink-style codes the ZG-IR01 takes. My bosch_ir integration generates every code itself rather than replaying learned ones, and it only knew how to write the ZG-IR01’s format, so I had to update it to write Tuya codes for this blaster too3.

Once that was sorted, sending just worked. I’d only put the blaster on my desk for testing, without trying to line it up with the AC or anything, and it still got through fine.

Pros and Cons

The Good

  • Works with ZHA out of the box, with no custom quirk
  • No firmware bug to work around
  • Learning codes works first time
  • Sending reached the AC from my desk, without lining anything up
  • Powered over USB-C, so no batteries to flatten
  • £8.99

The Not So Good

  • No temperature or humidity sensors, unlike the ZG-IR01
  • Codes, learned and sent, are in Tuya’s format, not the Broadlink-style codes the ZG-IR01 uses, so my integration needed updating

Final Thoughts

It works. If you just want a USB-powered IR blaster, get this one. If you want the extra sensors or batteries, consider the ZG-IR01, though you’ll need to add the seq 0 fix yourself.


  1. The ZG-IR01 always asks for chunks of sequence number 0, so the stock quirk silently drops every send. The fix is in the first post. ↩︎

  2. The decompressor is short. Each block starts with a header byte h, split into a length L = h >> 5 and D = h & 0x1F. If L is 0, copy the next D + 1 bytes as they are. Otherwise it’s a back-reference: if L is 7, add the next byte to L, then take the byte after as the low 8 bits of a distance whose top bits are D, and copy L + 2 bytes from that distance plus one back. The result is little-endian 16-bit timings. ↩︎

  3. That change isn’t on GitHub yet. I’ll release a new version once I’ve finished learning some new commands. ↩︎

search.exe
esc to close