Hitachi RE09T1 AC Remote Emulation With an ESP8266 – Part 1: Protocol Analysis

Taiwan summer’s are hot and sticky, and would be a nightmare without air conditioning. Unfortunately this hasn’t been so kind on our electric bill. My girlfriend and I now turn off the AC unit when no one is home (after one hefty electric bill), but since we both have erratic schedules, this has limited our ability to utilize the AC’s built in timer. Meaning we often come home to a hot house. We also rent, so installing a new thermostat is also not an option. The air conditioner does have a remote control though, so if I were to reverse engineer its protocol, I could trigger it remotely with an ESP8266 and IR LED before returning home.

Acquiring Remote IR Data

Using an Arduino UNO and an Infrared Receiver Module to collect IR codes from the remote.

First thing I needed to do is find a way of gathering and analyzing the infrared transmissions from the remote. I used the following setup.

1 x Arduino UNO
1 x Infrared Receiver Module
1 x Jumper Wires Female-Male

Before I get into how I wired up and flashed the Arduino, let’s go over a lesson that I had to learn the hard way. Most (all?) manufacturers of AC remotes don’t send individual commands like remotes for Televisions, Stereos, and most other consumer electronics.

Instead they transmit their complete current state, that is to say, they send all of their settings such as temperature, fan speed, cooling/heating mode, etc. in one large transmission every time a button is pushed. I would venture to guess this is done to insure everything stays in sync; however, it also leads transmission bursts that are too long for most Arduino libraries to handle.

Fortunately, ToniA’s github provides a solution for this by expanding upon some raw IR analysis code provided by ladyada. ToniA’s github provided me with both a wiring diagram and the necessary code to get started.

First I wired up the IR Receiver to the Arduino. If you’re following along, you may have to look up the pin out to your IR Receiver, but it should follow some variation of Power, Ground, and Signal.

Power – 5v
Ground – Gnd
Signal – Digital Pin 2

Afterwards I cloned the Raw-IR-decoder-for-Arduino git project, opened up rawirdecode.ino into the Arduino IDE, and flashed it to my Arduino.

I opened my serial monitor at a 9600 baud, and was presented with a menu with 6 different options. These options correspond to the manufacturer pulse timings of your remote control. I used option number 5 for my remote, but your mileage may vary.

I was now ready to read in signals from the remote control. In one of those weird occurrences when things work first try, I aimed my remote at the IR Receiver, pushed a button, and was presented with a wonderfully long detailed dump of the data my remote sent. This included multiple lines of binary and hex numbers, a long hex string, timing information, and counts. The long hex string is what I was most interested in, since it would be the easiest to analyze.

Remote control signal burst capture

Signal Analysis

Analyzing signals was the most grueling step. I did this by hand, but I later found a tool called AnalysisIR that I believe would have sped up this process tremendously. I would push a button, copy and paste the hex to a text document, and make a note of what button I pushed. I would then repeat that step with the same remote control button, so any bytes that change, such as time, could be identified.

As you can see below, the same button was pushed for all 3 of these captures, and you’ll notice the last two bytes never match once. By pressing the same button a few times, it becomes easier to weed out what data doesn’t remain constant.

00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

01,10,00,40,BF,FF,00,CC,33,92,6D,13,EC,68,97,00,FF,00,FF,00,FF,00,FF,00,FF,53,AC,F1,0E,00,FF,00,FF,80,7F,03,FC,60,9F,00,FF,8A,75
01,10,00,40,BF,FF,00,CC,33,92,6D,13,EC,68,97,00,FF,00,FF,00,FF,00,FF,00,FF,53,AC,E1,1E,00,FF,00,FF,80,7F,03,FC,60,9F,00,FF,8E,71
01,10,00,40,BF,FF,00,CC,33,92,6D,13,EC,68,97,00,FF,00,FF,00,FF,00,FF,00,FF,53,AC,F1,0E,00,FF,00,FF,80,7F,03,FC,60,9F,00,FF,AD,52

I would repeat this step for each one of the remote control buttons, being careful to put the remote in its starting state before moving to a new button. For example, if the temperature on the remote read 25 degrees before I began pressing the temperature adjustment button, then I would be sure to change it back to 25 degrees before moving on to the fan speed button. This helped isolate button pushes when analyzing the data.

Afterwards I was left with a long text document that gave me a rough idea on where many of the buttons were represented in the protocol. I say rough because, the data was a little noisy from things like checksums, buttons that shared bytes with one another at the bit level, and dynamic data such as the date and time being sent across. Definitely led to some red herrings along the way.

Signal Analysis Results

These are my results after analyzing the signal from the remote. These results have not attempted to analyze the protocol for the timer and sleep commands, although I’ll notate where in the byte stream I think they’re occurring.

Bytes 0 – 8 Identifier

These bytes don’t change, and since they occur at the beginning of the byte stream they seem to be used for remote control identification.

00 0x01
01 0x10
02 0x00
03 0x40
04 0xBF
05 0xFF
06 0x00
07 0xCC 
08 0x33 

Bytes 9 – 10 Unknown

Possibly part of the Identifier bytes above.

Bytes 11 – 12 Button Pushed

Sends a code for the current button pressed on the remote control. Byte 12 is a bitwise not of byte 11.

0x13:Power
0x41:Mode
0x42:Fan
0x43:Temperature Down
0x44:Temperature Up
0x81:Vertical Fan Position
0x8C:Horizontal Fan Position

Bytes 13 – 14 Temperature

Byte 13 is the temperature. Byte 14 is a bitwise not of byte 13.

Bits 1-2 always 0.
Bits 3-7: Room temperature setting in Celsius
Bit 8: Always 0
Possible values: 16 to 32 for most modes, 10 to 32 for dehumidify.

Example:
Say that byte 13 is 0x68 in hex. First we need to convert it to binary.
0x68 = 0b01101000

Then we shift it right by two.
0b01101000 >> 2 = 0b00011010

Convert to Decimal:
0b00011010 = 26

So when byte 13 is 0x68 then that means the temperature is being set to 26 degrees Celsius.

Shift To the Right by Two.

Bytes 15 – 18 Sleep

I haven’t looked into decoding this portion of the protocol. This is my current theory.
Byte 15 Lower Byte
Byte 16 Bitwise Not of Byte 15
Byte 17 High Byte
Byte 18 Bitwise Not of Byte 17

Bytes 19 – 26 Unknown/Possibly Timer

Bytes 27 – 28 Power

Byte 27 Power. Byte 28 Bitwise Not of Bytes 27.

Bit 5 of Byte 27 controls the power.

0b00000000 Power Off
0b00010000 Power On

Bytes 29 – 32 Date

Byte 29 Day of Month
Byte 30 Bitwise Not of Byte 29
Byte 31 Month
Byte 32 Bitwise Not of Byte 31

Bytes 33 – 34 Unknown

Bytes 35 – 36 Horizontal Fan Direction

Controls the horizontal fan direction.

0x00 Automatic 
0x01 Far Right 
0x02 Right 
0x03 Center 
0x04 Left 
0x05 Far Left 

Bytes 37 – 38 Vert Fan, Internal Dry, Dehumidifier, Light

This one is a busy one. Byte 37 Controls various options as shown below and Byte 38 is a Bitwise Not of Byte 37.

Bit 5 control vertical fan oscillate.

0b00000000 Off 
0b00100000 On

Bits 2 and 4 dehumidifier

0b00000000 Off
0b00000010 Low
0b00001010 High

Bit 3 Internal Dry

0b00000000 Off 
0x00000100 On

Bit 7, 8 Light

0b01000000 Off
0b00000000 High
0b10000000 Medium
0b11000000 Low 

Bytes 39 – 42 Time

Time is represented as minutes after midnight. Since there are more than 256 minutes in a day, we need a high byte, and a low byte to represent time.

Byte 39 Upper Time Byte
Byte 40 Bitwise Not of Byte 39
Byte 41 Lower Time Byte
Byte 42 Bitwise Not of Byte 41

Example

If we bytes 39 – 42 are 01,FF,AD,52
Byte 39 = 0x01 High Time Byte
Byte 41 = 0xAD Low Time Byte

Which gives us 0x01AD or 429 in decimal.

To get hours we divide by 60 giving us: 429/60 = 7
To get minutes we mod by 60 giving us: 429%60 = 9

End of Part 1

Part 2 will focus on implementing this in code.

So the current time would be 07:09 AM