I have a Komeco air conditioner in my bedroom. It is controlled by an IR remote controller (ZH/JT-03) and, as a home automation hobbyist, I really like to control my home appliances with my Watch, Phone, Google assistant, Alexa, etc. You got my drill. In simple words, I’m lazy, thus I try to automate everything I can.

With that in mind I began studying to understand how an air conditioner works. Typically, the remote control stores the device state, and every time you press a button, it sends the whole state (temperature, fan speed, mode) to the air conditioner via infrared.

With this idea, the approach I decided to use is to read the IR remote commands using an Arduino Leonardo and a IR Receiver, presented in the Image 1, and then I reverse engineer the commands.

Image 1.: Schematics of the circuit used to write this post

What is IR?

The IR communication consists of an emitter and a receiver, the emitter sends infrared radiation, which is then received by the receiver to be processed and then execute whatever it needs to. An IR packet consists of On/Off pulses described by µs (microseconds) intervals. I have used an example code from this IR library for Arduino and processed each command input using this python script.

6112, 7364, 564, 1632, 672, 1536, 628, 1564, 568, 1628, 564, 1628, 676, 1508, 684, 1536, 564, 1624, 572, 548, 652, 496, 604, 520, 568, 556, 600, 540, 660, 468, 568, 552, 600, 520, 652, 1568, 564, 1624, 568, 1628, 644, 1548, 648, 1564, 564, 1624, 568, 1620, 652, 1568, 628, 492, 600, 524, 564, 552, 656, 492, 568, 552, 568, 552, 680, 468, 568, 556, 596, 520, 680, 468, 564, 1628, 568, 1628, 648, 1544, 648, 1560, 600, 1592, 568, 1620, 652, 1564, 604, 1588, 568, 556, 676, 440, 632, 516, 572, 552, 596, 520, 656, 492, 632, 1560, 600, 520, 680, 1536, 568, 548, 720, 1484, 644, 496, 600, 520, 568, 1624, 632, 492, 676, 1532, 604, 520, 600, 1588, 656, 492, 600, 1588, 572, 1616, 684, 464, 564, 1628, 572, 1624, 632, 1552, 656, 1564, 564, 1624, 568, 552, 660, 1552, 576, 1620, 568, 560, 632, 504, 576, 544, 572, 552, 568, 580, 596, 1592, 568, 552, 572, 576, 632, 488, 568, 1620, 572, 548, 656, 1556, 572, 556, 568, 1620, 656, 488, 568, 556, 568, 1620, 688, 460, 564, 1628, 568, 556, 680, 1512, 620, 520, 568, 1620, 572, 1616, 684, 7296, 572

Reading 1.: Raw IR Reading from the controller

Let’s hack (or not)

By now, I’m sure you figured that by itself, IR packets are not human-readable. Each value in reading 1 represents the interval in µs that the IR led turned on. Since IR works by sending On/Off µs pulses, let’s divide the raw reading into pairs to make the data more readable, I have decided to split in pairs after observing the raw reading and seeing that the packet follow the sequence 5XX and 16XX or 5XX(X can be any decimal value), an example of that is the second and third reading in Table 1. By dividing in pairs, the final data packet is going to much shorter and easier to understand. I have simplified the pairs table to help the reader understand better.

6112 7364 564 1632 548 652 496 604

Table 1.: Pairs from the data packet

I’ve chosen the value 1000 as the threshold for whether the pair is a 0(low) or it’s a 1(high), I decided to use this value after observing the data packet, almost every second value of each pair is either 16XX or 5XX, thus using 1000 as the threshold is a reasonable value for the logic applied here, it’s an experiential value and you might have to tweak it a little, depending on your remote controller. The first pair of values and the last doesn’t really match the threshold definition, we are going to remove them for now.

By doing that now we have a binary sequence:

111111110000000011111111000000000011111111000000101010010101011011111011000001000101010010101011

IR packet transformed into binary

To simplify things even more we can convert the binary sequence to hexadecimal:

0xff00ff003fc0a956fb0454ab

Binary sequence converted to Hexadecimal

Ta-da! We now have the values for turning the air conditioner on. Since this entire hexadecimal contains the whole state for the air conditioner we need more readings.

By applying the technique described above and reading a significant amount of IR Packets, the following pattern has been identified.

HEADER COMMAND PARAMETER TEMP MODE TEMP CHECKSUM FOOTER

Table 2.: Packet sections

Based on table 2 contents, here’s two readings, the first one is setting the temperature to 18 and the second one is setting the temperature to 19:

0xff00ff00bf40a956bb4454ab: Setting the temperature to 18

0xff00ff00bf40a9563bc454ab: Setting the temperature to 19

Now, if we split those hexadecimal commands and look for differences in those commands, we’ll end up with something like this:

HEADER COMMAND PARAMETER TEMP MODE TEMP CHECKSUM FOOTER ff00ff00 bf40 a956 b b 4 45 4ab ff00ff00 bf40 a956 3 b c 45 4ab

Comparison of two commands

The 17th and 19th digit in the hexadecimal sequence indicates the temperature we are setting. To obtain other commands we need to do the same thing, for instance, if we were to obtain the command to change the fan speed, we need to read the command for setting the fan speed to 1 and then the command for setting the fan speed to 2 and then compare using the same approach above. Keep in mind that you shouldn’t change anything else in the controller except the command you are trying to reverse engineer, otherwise you’ll end up with wrong commands.

Conclusion

Air conditioners are usually controlled by Infrared, which is old and dumb, using this post I believe the reader can now hack his/her air conditioner controller and automate the appliance, I must warn you though, the process is slow. I would suggest figuring out only the temperature commands, which is what we do the most in our daily lives.

References

How does IR works

https://www.quora.com/How-do-an-IR-transmitter-and-receiver-work

Implementation of the (ZH/JT-03) controller

https://github.com/Nixsm/arduino-ac-remote