Toshiba Air Conditioner IR signal Reverse Engineering

Introduction

I am in the process of installing some Toshiba air conditioners in my house, and am planning to control them remotely using OpenHab (http://www.openhab.org/).
The first step to be able to control the air conditioner is to be able to emulate IR signals as they are sent by the AC remote.

In order to do that I have modified an open source IR library (https://github.com/r45635/HVAC-IR-Control) to add support for the Toshiba AC units.

Air Conditioning remotes work in a slightly different way than standard remotes as they usually transmit a packet containing all information related to the AC as opposed to, say, TV remotes where every keypress transmits only a single information like a button press.
This is a typical packet sent from a Toshiba Remote (in Hexadecimal):
#KeyHex    # Bits
1fan1F2 0D 03 FC 01 00 40 00 41 F2 0D 03 FC 01 00 40 00 41    144
it is a 72 bit packet that is transmitted twice (I imagine to rule out transmission errors), this is the binary representation:

11110010 00001101 00000011 11111100 00000001 00000000 01000000 00000000 01000001 11110010 00001101 00000011 11111100 00000001 00000000 01000000 00000000
and this is the graphic representation, with timings for the packet header:

In this post I'll try to explain how I proceeded to analyse different signals and discover how to generate them using code as opposed to memorise all possible signals and repeat them back (not doable given all the possible permutations and the limited memory available on the ESP8266/Arduino platforms)


Tools used for the reverse engineering:


  • AnalysIR (paid version): a tool that really makes decoding IR signals easy for moderately competent software engineers

The tool facilitates recording and analising IR signals, it already has supports for a lot of IR protocols (TOSHIBA AC remotes included) and is able to:
    • Record IR signals using multiple IR sensors hardware (arduino,esp8266,raspberry, A.IR shields) on two separate channels for easy comparison
    • Analyze visually the signal and quickly calculate IR base settings like timings for marks, ones and zeros to e.g. configure common IR libraries
    • Export the signal to source code for various platform
    • help decoding the signal and identifying CRC methods

    • quickly find variations on different IR signals



  • A.IR Shield: an arduino nano shield that is able to receive and log IR signals to AnalysIR. It is not necessary for AnalysIr, but for 20 euro for the shield and an Arduino nano clone it can get you started really quickly in the IR decoding business. The A.IR shield also has IR sending capabilities if needed
  • SendIR module: an arduino/esp8266 controllable module that has two high power/high range IR emitters, used to replicate the AC remote IR signals

  • ESP8266 based dev board: used to control the SendIR module, any arduino will do, in my case I will use the ESP8266 to control multiple SendIr modules by forwarding data to it from Openhab

Protocol Basics

The Toshiba IR protocol, as far as I could understand uses three possible signal lengths
  • 144 bits for signals that control
    • power
    • temperature
    • ac mode (auto/hot/dry/cool)
    • fan speed 
  • 160 bits for signals that control eco/hi power mode
  • 112 bits for signals that control swing mode
I have worked in decoding and reproducing only the 144 bit signals, so far
The 144 bit signal is in reality a 72 bit (9byte signal) repeated twice

Let's consider this signal:

#KeyHex    # Bits
1fan1F2 0D 03 FC 01 00 40 00 41 F2 0D 03 FC 01 00 40 00 41    144
the first 9 bytes are:
F2 0D 03 FC 01 00 40 00 41
  • F2 0D 03 FC 01 : bytes 1-5 are fixed for the 144 bit signal
  • 00 : byte 6 stores two kind of information
    • first 4 bits: temperature in the range: 17-30

17F2 0D 03 FC 01 00 00 00 01 F2 0D 03 FC 01 00 00 00 01    144

18F2 0D 03 FC 01 10 00 00 11 F2 0D 03 FC 01 10 00 00 11    144

19F2 0D 03 FC 01 20 00 00 21 F2 0D 03 FC 01 20 00 00 21    144

20F2 0D 03 FC 01 30 00 00 31 F2 0D 03 FC 01 30 00 00 31    144

21F2 0D 03 FC 01 40 00 00 41 F2 0D 03 FC 01 40 00 00 41    144

22F2 0D 03 FC 01 50 00 00 51 F2 0D 03 FC 01 50 00 00 51    144

23F2 0D 03 FC 01 60 00 00 61 F2 0D 03 FC 01 60 00 00 61    144

24F2 0D 03 FC 01 70 00 00 71 F2 0D 03 FC 01 70 00 00 71    144

25F2 0D 03 FC 01 80 00 00 81 F2 0D 03 FC 01 80 00 00 81    144

26F2 0D 03 FC 01 90 00 00 91 F2 0D 03 FC 01 90 00 00 91    144

27F2 0D 03 FC 01 A0 00 00 A1 F2 0D 03 FC 01 A0 00 00 A1    144

28F2 0D 03 FC 01 B0 00 00 B1 F2 0D 03 FC 01 B0 00 00 B1    144

29F2 0D 03 FC 01 C0 00 00 C1 F2 0D 03 FC 01 C0 00 00 C1    144
26ON->30F2 0D 03 FC 01 D0 00 00 D1 F2 0D 03 FC 01 D0 00 00 D1    

    • second 4 bits: on/off state
      • 00 is on
      • 02 is off
  • 40: byte 7 stores two kind of information
    • first 4 bits: fan speed
717-fan autoF2 0D 03 FC 01 00 00 00 01 F2 0D 03 FC 01 00 00 00 01    144
8fan5F2 0D 03 FC 01 00 C0 00 C1 F2 0D 03 FC 01 00 C0 00 C1    144
9fan4F2 0D 03 FC 01 00 A0 00 A1 F2 0D 03 FC 01 00 A0 00 A1    144
10fan3F2 0D 03 FC 01 00 80 00 81 F2 0D 03 FC 01 00 80 00 81    144
11fan2F2 0D 03 FC 01 00 60 00 61 F2 0D 03 FC 01 00 60 00 61    144
12fan1F2 0D 03 FC 01 00 40 00 41 F2 0D 03 FC 01 00 40 00 41    144
    • second 4 bits: AC mode
317-fan autoF2 0D 03 FC 01 00 00 00 01 F2 0D 03 FC 01 00 00 00 01    144
4hotF2 0D 03 FC 01 50 03 00 52 F2 0D 03 FC 01 50 03 00 52    144
5dryF2 0D 03 FC 01 50 02 00 53 F2 0D 03 FC 01 50 02 00 53    144
6coldF2 0D 03 FC 01 50 01 00 50 F2 0D 03 FC 01 50 01 00 50    144
  • 00: byte 8 unused as far as I can tell
  • 41: checksum, obtained by XORing the previous eight bytes

Reverse Engineering Process

I started by recording multiple signals from the Toshiba remote and assigning an identifier like hot-dry-cold-auto when cycling the AC mode setting



after that I used the reverse engineering tool to identify patterns in the signal:

#KeyHex    # Bits
1fan1F2 0D 03 FC 01 00 40 00 41 F2 0D 03 FC 01 00 40 00 41    144
217-fan autoF2 0D 03 FC 01 00 00 00 01 F2 0D 03 FC 01 00 00 00 01    144
317-fan autoF2 0D 03 FC 01 00 00 00 01 F2 0D 03 FC 01 00 00 00 01    144
4hotF2 0D 03 FC 01 50 03 00 52 F2 0D 03 FC 01 50 03 00 52    144
5dryF2 0D 03 FC 01 50 02 00 53 F2 0D 03 FC 01 50 02 00 53    144
6coldF2 0D 03 FC 01 50 01 00 50 F2 0D 03 FC 01 50 01 00 50    144
717-fan autoF2 0D 03 FC 01 00 00 00 01 F2 0D 03 FC 01 00 00 00 01    144
8fan5F2 0D 03 FC 01 00 C0 00 C1 F2 0D 03 FC 01 00 C0 00 C1    144
9fan4F2 0D 03 FC 01 00 A0 00 A1 F2 0D 03 FC 01 00 A0 00 A1    144
10fan3F2 0D 03 FC 01 00 80 00 81 F2 0D 03 FC 01 00 80 00 81    144
11fan2F2 0D 03 FC 01 00 60 00 61 F2 0D 03 FC 01 00 60 00 61    144
12fan1F2 0D 03 FC 01 00 40 00 41 F2 0D 03 FC 01 00 40 00 41    144
1317F2 0D 03 FC 01 00 00 00 01 F2 0D 03 FC 01 00 00 00 01    144
1418F2 0D 03 FC 01 10 00 00 11 F2 0D 03 FC 01 10 00 00 11    144
1519F2 0D 03 FC 01 20 00 00 21 F2 0D 03 FC 01 20 00 00 21    144
1620F2 0D 03 FC 01 30 00 00 31 F2 0D 03 FC 01 30 00 00 31    144
1721F2 0D 03 FC 01 40 00 00 41 F2 0D 03 FC 01 40 00 00 41    144
1822F2 0D 03 FC 01 50 00 00 51 F2 0D 03 FC 01 50 00 00 51    144
1923F2 0D 03 FC 01 60 00 00 61 F2 0D 03 FC 01 60 00 00 61    144
2024F2 0D 03 FC 01 70 00 00 71 F2 0D 03 FC 01 70 00 00 71    144
2125F2 0D 03 FC 01 80 00 00 81 F2 0D 03 FC 01 80 00 00 81    144
2226F2 0D 03 FC 01 90 00 00 91 F2 0D 03 FC 01 90 00 00 91    144
2327F2 0D 03 FC 01 A0 00 00 A1 F2 0D 03 FC 01 A0 00 00 A1    144
2428F2 0D 03 FC 01 B0 00 00 B1 F2 0D 03 FC 01 B0 00 00 B1    144
2529F2 0D 03 FC 01 C0 00 00 C1 F2 0D 03 FC 01 C0 00 00 C1    144
26ON->30F2 0D 03 FC 01 D0 00 00 D1 F2 0D 03 FC 01 D0 00 00 D1    144


and the checksum calculator tool to verify that the Checksum byte was indeed calculated with an XOR algorithm




Then I added a new method to the HVAC IR library that would translate this findings into an actual IR signal.

To do that I had to define a couple of constants:

       

#define HVAC_TOSHIBA_HDR_MARK    4400
#define HVAC_TOSHIBA_HDR_SPACE   4300
#define HVAC_TOSHIBA_BIT_MARK    543
#define HVAC_TOSHIBA_ONE_SPACE   1623
#define HVAC_MISTUBISHI_ZERO_SPACE  472
#define HVAC_TOSHIBA_RPT_MARK    440
#define HVAC_TOSHIBA_RPT_SPACE   7048 // Above original iremote limit

       
 

  • HVAC_TOSHIBA_HDR_MARK is the time duration of an header mark (in microseconds): it is a HIGH signal sent at the beginning of the signal to identify the start point
  • HVAC_TOSHIBA_HDR_SPACE is the time duration of an header space (in microseconds): it is a LOW signal sent after the mark and precedes the bit stream
  • HVAC_TOSHIBA_BIT_MARK is the time duration of a mark for a bit (either 0 or 1,in microseconds): it is a HIGH signal sent at the beginning of the bit to indicate a new bit is incoming
  • HVAC_TOSHIBA_ONE_SPACE is the time duration of a space for a bit with value 1 (in microseconds): it is a LOW signal sent after the bit mark 
  • HVAC_TOSHIBA_ZERO_SPACE is the time duration of a space for a bit with value 0 (in microseconds): it is a LOW signal sent after the bit mark 
  • HVAC_TOSHIBA_RPT MARK is the time duration of an header mark (in microseconds): it is a HIGH signal sent at the end of the first half of the signal to identify the start point of the repetition
  • HVAC_TOSHIBA_RPT SPACE is the time duration of an header mark (in microseconds): it is a LOW signal sent after the repetition mark and marks the beginning of the second half of the bit stream
And here is the actual code that implements the protocol above:




       

/****************************************************************************
/* Send IR command to Toshiba HVAC - sendHvacToshiba
/***************************************************************************/
void sendHvacToshiba(
  HvacMode                HVAC_Mode,           // Example HVAC_HOT  
  int                     HVAC_Temp,           // Example 21  (°c)
  HvacFanMode             HVAC_FanMode,        // Example FAN_SPEED_AUTO  
  int                     OFF                  // Example false
)
{
 
#define HVAC_TOSHIBA_DATALEN 9
#define  HVAC_TOSHIBA_DEBUG;  // Un comment to access DEBUG information through Serial Interface

  byte mask = 1; //our bitmask
  //F20D03FC0150000051
  byte data[HVAC_TOSHIBA_DATALEN] = { 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00 };
  // data array is a valid trame, only byte to be chnaged will be updated.

  byte i;

#ifdef HVAC_TOSHIBA_DEBUG
  Serial.println("Packet to send: ");
  for (i = 0; i < HVAC_TOSHIBA_DATALEN; i++) {
    Serial.print("_");
    Serial.print(data[i], HEX);
  }
  Serial.println(".");
#endif

  data[6] = 0x00;
  // Byte 7 - Mode
  switch (HVAC_Mode)
  {
    case HVAC_HOT:   data[6] = (byte) B00000011; break;
    case HVAC_COLD:  data[6] = (byte) B00000001; break;
    case HVAC_DRY:   data[6] = (byte) B00000010; break;
    case HVAC_AUTO:  data[6] = (byte) B00000000; break;
    default: break;
  }


  // Byte 7 - On / Off
  if (OFF) {
    data[6] = (byte) 0x07; // Turn OFF HVAC
  } else {
     // Turn ON HVAC (default)
  }

  // Byte 6 - Temperature
  // Check Min Max For Hot Mode
  byte Temp;
  if (HVAC_Temp > 30) { Temp = 30;}
  else if (HVAC_Temp < 17) { Temp = 17; } 
  else { Temp = HVAC_Temp; };
  data[5] = (byte) Temp - 17<<4;

  // Byte 10 - FAN / VANNE
  switch (HVAC_FanMode)
  {
    case FAN_SPEED_1:       data[6] = data[6] | (byte) B01000000; break;
    case FAN_SPEED_2:       data[6] = data[6] | (byte) B01100000; break;
    case FAN_SPEED_3:       data[6] = data[6] | (byte) B10000000; break;
    case FAN_SPEED_4:       data[6] = data[6] | (byte) B10100000; break;
    case FAN_SPEED_5:       data[6] = data[6] | (byte) B11000000; break; 
    case FAN_SPEED_AUTO:    data[6] = data[6] | (byte) B00000000; break;
    case FAN_SPEED_SILENT:  data[6] = data[6] | (byte) B00000000; break;//No FAN speed SILENT for TOSHIBA so it is consider as Speed AUTO
    default: break;
  }

  // Byte 9 - CRC
  data[8] = 0;
  for (i = 0; i < HVAC_TOSHIBA_DATALEN - 1; i++) {
    data[HVAC_TOSHIBA_DATALEN-1] = (byte) data[i] ^ data[HVAC_TOSHIBA_DATALEN -1];  // CRC is a simple bits addition
  }

#ifdef HVAC_TOSHIBA_DEBUG
  Serial.println("Packet to send: ");
  for (i = 0; i < HVAC_TOSHIBA_DATALEN; i++) {
    Serial.print("_"); Serial.print(data[i], HEX);
  }
  Serial.println(".");
  for (i = 0; i < HVAC_TOSHIBA_DATALEN ; i++) {
    Serial.print(data[i], BIN); Serial.print(" ");
  }
  Serial.println(".");
#endif

  enableIROut(38);  // 38khz
  space(0);
  for (int j = 0; j < 2; j++) {  // For Toshiba IR protocol we have to send two time the packet data
    // Header for the Packet
    mark(HVAC_TOSHIBA_HDR_MARK);
    space(HVAC_TOSHIBA_HDR_SPACE);
    for (i = 0; i < HVAC_TOSHIBA_DATALEN; i++) {
      // Send all Bits from Byte Data in Forward Order (MSB)
      for (mask = 10000000; mask > 0; mask >>= 1) { //iterate through bit mask
        if (data[i] & mask) { // Bit ONE
          mark(HVAC_TOSHIBA_BIT_MARK);
          space(HVAC_TOSHIBA_ONE_SPACE);
        }
        else { // Bit ZERO
          mark(HVAC_TOSHIBA_BIT_MARK);
          space(HVAC_MISTUBISHI_ZERO_SPACE);
        }
        //Next bits
      }
    }
    // End of Packet and retransmission of the Packet
    mark(HVAC_TOSHIBA_RPT_MARK);
    space(HVAC_TOSHIBA_RPT_SPACE);
    space(0); // Just to be sure
  }
}


To debug my code without having a real AC unit go crazy because of fake/wrong signals I used AnalysIr to check that the generated signals are the same with respect to the ones recorder from the real AC remote

The full version of the code (and a test ESP8266 sketch) is available on Github

Commenti

Joseph ha detto…
HVAC contractors will be always in demand because individuals and businesses constantly need their HVAC systems either serviced, repaired, or replaced. air conditioning
Unknown ha detto…
If you want to do reverse engineering then you will need a 3D laser scanner. There are so many companies that can provide you 3D laser scanner service. Onsite3D provides the best 3D laser scanning service at an affordable price. Best reverse engineering Houston, Texas
Coool Air ha detto…
We read your blog site, share most helpful details in blog. Split System Air Conditioner Installation
Onu Ranni ha detto…
What is going wrong?


Arduino: 1.8.13 (Windows 10), Board: "Arduino Nano, ATmega328P"





















In file included from sketch\IRremote2.cpp:24:0:

sketch\IRremoteInt2.h:153:0: warning: "HVAC_MISTUBISHI_ZERO_SPACE" redefined

#define HVAC_MISTUBISHI_ZERO_SPACE 472



sketch\IRremoteInt2.h:143:0: note: this is the location of the previous definition

#define HVAC_MISTUBISHI_ZERO_SPACE 420



sketch\IRremote2.cpp:668:28: warning: ISO C++11 requires whitespace after the macro name

#define HVAC_TOSHIBA_DEBUG; // Un comment to access DEBUG information through Serial Interface

^

C:\Users\Ranni\Documents\Arduino\toshaaaa\toshaaaa.ino:21:28: warning: ISO C++11 requires whitespace after the macro name

#define HVAC_TOSHIBA_DEBUG; // Un comment to access DEBUG information through Serial Interface

^

toshaaaa:12:23: error: variable or field 'sendHvacToshiba' declared void

void sendHvacToshiba(

^

toshaaaa:12:23: error: 'HvacMode' was not declared in this scope

sketch\IRremote2.cpp: In function 'void sendHvacToshiba(HvacMode, int, HvacFanMode, int)':

IRremote2.cpp:744:3: error: 'enableIROut' was not declared in this scope

enableIROut(38); // 38khz

^~~~~~~~~~~

C:\Users\Ranni\Documents\Arduino\toshaaaa\toshaaaa.ino:12:23: note: suggested alternative: 'pinMode'

void sendHvacToshiba(

^

pinMode

toshaaaa:12:43: error: expected primary-expression before 'int'

void sendHvacToshiba(

^

toshaaaa:12:58: error: 'HvacFanMode' was not declared in this scope

void sendHvacToshiba(

^

IRremote2.cpp:745:3: error: 'space' was not declared in this scope

space(0);

^~~~~

toshaaaa:12:84: error: expected primary-expression before 'int'

void sendHvacToshiba(

^

toshaaaa:13:3: error: variable or field 'sendHvacToshiba' declared void

HvacMode HVAC_Mode, // Example HVAC_HOT

^~~~~~~~

toshaaaa:13:3: error: 'HvacMode' was not declared in this scope

sketch\IRremote2.cpp:745:3: note: suggested alternative: 'isSpace'

space(0);

^~~~~

isSpace

IRremote2.cpp:748:5: error: 'mark' was not declared in this scope

mark(HVAC_TOSHIBA_HDR_MARK);

^~~~

sketch\IRremote2.cpp:748:5: note: suggested alternative: 'mask'

mark(HVAC_TOSHIBA_HDR_MARK);

^~~~

mask

sketch\IRremote2.cpp:752:19: warning: large integer implicitly truncated to unsigned type [-Woverflow]

for (mask = 10000000; mask > 0; mask >>= 1) { //iterate through bit mask

^~~~~~~~

C:\Users\Ranni\Documents\Arduino\toshaaaa\toshaaaa.ino:13:3: note: suggested alternative: 'pinMode'

HvacMode HVAC_Mode, // Example HVAC_HOT

^~~~~~~~

pinMode

toshaaaa:14:3: error: expected primary-expression before 'int'

int HVAC_Temp, // Example 21 (°c)

^~~

toshaaaa:15:3: error: 'HvacFanMode' was not declared in this scope

HvacFanMode HVAC_FanMode, // Example FAN_SPEED_AUTO

^~~~~~~~~~~

toshaaaa:16:3: error: expected primary-expression before 'int'

int OFF // Example false

^~~

exit status 1

variable or field 'sendHvacToshiba' declared void



This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
Francis Smith ha detto…
When you’re experiencing extreme heat or cold, a comfortable temperature inside is the goal. Commercial mechanical contactors can help solve that issue.
Faizan Shaikh ha detto…
AC replacement online quotes Thanks for taking the time to discuss this, I feel strongly about it and love learning more on this topic. If possible, as you gain expertise, would you mind updating your blog with extra information? It is extremely helpful for me.
nobita ha detto…
Do you know how to program you Ge Universal Remote Codes? When you want to program your RCA universal remote you need to make use of RCAuniversal remote codes.
technology ha detto…
Those who are paying for these services are not the only ones who will benefit from the results. Even common people are taking advantage of the gains presented by modern scanners. 3d laser scanning survey Sydney
Hanna Smith ha detto…
lucky patcher2021 is a wonderful Android app enabling you to patch as well as modify files in a format through solving the space limitation issue. You can change permissions, avoid irritating ads, simply backup apps, convert apps to system apps, transfer apps and games to the SD card, and a lot more. The app is also a perfect solution for unlocking levels, tools, coins, characters, and other resources in games and other apps. You can use the app on your PC also via using the Bluestacks. It’s the most common rooted apps made by developer Chelpus.


Hanna Smith ha detto…
tubemate apk 2020 is a free app that lets you download any YouTube video to your Android phone. The app gives you a surprising number of download options too.
This program can be great if you're looking to have more control about the video’s quality, whether you only want the audio, and where to store the file, like a phone’s internal memory or an external SD card.
Chicagoland Air Duct ha detto…
A very delightful article that you have shared here.air duct cleaning chicago Your blog is a valuable and engaging article for us, and also I will share it with my companions who need this info. Thankful to you for sharing an article like this.
NEOAMICO ha detto…
Your blog contains lots of valuable data. It is a factual and beneficial article for us.NEOAMICO Thankful to you for sharing an article like this.
Joe Lie ha detto…
That's great to hear about your plans to install Toshiba air conditioners and control them remotely using OpenHab! Your initiative to modify an open-source IR library to add support for Toshiba AC units is commendable. It showcases your technical skills and adaptability. By emulating IR signals, you'l l have the convenience of controlling your air conditioners seamlessly. Additionally, if you ever require assistance with an economics case study help or any academic queries, feel free to reach out. Best of luck with your installation project!

Post popolari in questo blog

ESP8266 - Air Conditioner Command and Control Unit