Analyzing Remote Control Code with Tiqiaa (ZaZaRemote) Adaptor

Pawit Pornkitprasan
4 min readAug 12, 2024

--

Introduction

Recently, I got into the SwitchBot ecosystem, and one feature of the SwitchBot Hub is to control other devices via IR signals. The SwitchBot Hub provides the feature of learning from existing remote control and emulating the signal. However, the SwitchBot application does not expose the learned remote control code and does not allow arbitrary code to be sent without learning it from an actual remote.

Wanting to dig more and wanting to control appliances I don’t have the remote for, I ordered a USB-C IR sender/receiver from AliExpress. Originally, it’s meant to be used with the “ZaZaRemote” application on Android but luckily, other people have already reverse-engineered the USB protocol and released applications for using it from a computer.

Reading the signal with a Python script

A GitLab user, “normanr”, has created a Python script based on the reverse-engineered protocol. After installing libusb and pyusb, it works on macOS with one small change and does not need any specific kernel drivers.

This is what the output looks like:

# Note: sometimes this outputs garbage for the first press.
# Pressing the button a few time will give you usable output.
$ python3 tiqiaa_usb_ir.py -r
+8976 -4432 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -1664 +576 -544 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -544 +576 -1664 +576 -1664 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -41008 +8992 -2224 +576 #

Trying the signal

I can also use the Python script to send IR signals. By controlling the appliance with the signal sent, I can confirm whether the captured signal is correct or not.

SIGNAL="+8976 -4432 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -1664 +576 -544 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -544 +576 -1664 +576 -1664 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -544 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -1664 +576 -41008 +8992 -2224 +576 #"
echo -n $SIGNAL | python3 tiqiaa_usb_ir.py -s -

Decoding the signal

What’s the plus and minus and what data is in there? After a bit of Googling around, I’ve found that the number after “+” is the duration of the on signal (“pulse”) and the number after “-” is the duration of off signal (“space”), both in micro-seconds.

The appliance uses the NEC format which means:

  • “0” is encoded as 562.5µs pulse burst followed by a 562.5µs space
  • “1” is encoded as 562.5µs pulse burst followed by a 1.6875ms space

And thus the above signal can be decoded as follows:

# Header
+8976 -4432

# Address (first-byte)
# 0b10000000 or 128 (LSB-first)
+576 -544 # 0
+576 -544 # 0
+576 -544 # 0
+576 -544 # 0
+576 -544 # 0
+576 -544 # 0
+576 -544 # 0
+576 -1664 # 1

# Address (second-byte)
# 0b11011110 or 222 (LSB-first)
+576 -544 # 0
+576 -1664 # 1
+576 -1664 # 1
+576 -1664 # 1
+576 -1664 # 1
+576 -544 # 0
+576 -1664 # 1
+576 -1664 # 1

# Command
# 0b0000000 or 0 (LSB-first)
+576 -544 # 0
+576 -544 # 0
+576 -544 # 0
+576 -544 # 0
+576 -544 # 0
+576 -544 # 0
+576 -544 # 0
+576 -544 # 0

# Command (inverse)
# 0b11111111 or 255(LSB-first)
+576 -1664 # 1
+576 -1664 # 1
+576 -1664 # 1
+576 -1664 # 1
+576 -1664 # 1
+576 -1664 # 1
+576 -1664 # 1
+576 -1664 # 1

# Footer
+576 -41008
+8992 -2224
+576

IrScrutinizer

I’ve also found a software called “IrScrutinizer” which will decode the signal for you if you remove the final “#” and paste it.

Note: the input text area will accept the “+8976 -4432 …” format but will conver it to hex afte pressing “Scrutinize”

The output is the same as I’ve decoded above:

  • D (Address first-byte)= 128
  • S (Address second-byte) = 222
  • F (Command) = 0

Searching for undocumented IR codes

I wanted to know if my appliance supports discerete on-off code or not (code that does not toggle the device between on and off, but rather only turn it on or turn it off), because discrete code makes home automation reliable. To do that, I have created another Python script to automatically generate the signal code for each function and send them.

Unfortunately, the Iris Ohyama circulator fans do not have discerete codes.

List of code

For Japanese appliances, unlike popular global appliances, it is sometimes difficult to find the correct remote code. Thus, I would like to document them here in case anyone is searching for them.

Iris Ohyama Circulator Fan PCF-SC15T

Device Address: D=128, S=222

Functions:

  • Power: F=0
  • Increase Speed: F=8
  • Decrease Speed: F=16
  • Rythm mode: F=9
  • Timer (4 hours): F=10
  • Timer (2 hours): F=14
  • Timer (1 hour): F=18
  • Swing (left-right): F=21
  • Swing (up-down): F=22

Iris Ohyama Circulator Fan KCF-SDCC152T

Device Address: D=128, S=222

Functions:

  • Power: F=0
  • On Timer: F=8
  • Off Timer: F=12
  • Normal mode: F=9
  • Rhythm mode: F=13
  • Clothes drying mode: F=17
  • Swing (left-right): F=10
  • Swing (up-down): F=14
  • Increase Speed: F=22
  • Decrease Speed: F=20

One interesting (but unfortunate) thing is that there’s no consistency between two different models, which means that the button of the remote on one model with trigger random actions on another model!

--

--