Arduino,  Hardware

Making my air conditioner smarter – Epilogue

Making some maintenance in my house, I decided to fix the air conditioner in my living room, a Johnson MGE-30-BC, which has been non-working for a long time.

I bought my house two years ago, and the air conditioner wasn’t working by then. I have always been delaying that repair project because I was expecting the worst possible outcome (maybe the gas escaped and I would have to find the leak, fix it and refill the circuit? maybe the compressor was broken, and I would have to replace it (and also empty and refill the circuit too), maybe more than one thing is faulty and I would have to replace the whole machine?… You know, that kind of repairs, which are not cheap), but… it turned out to be the easiest repair in a long time: the multi-wire cable that connects the inside and outside units has wires of the same color, and two of those wires were connected wrong.

I don’t understand how that would happen… ¿the person who installed it didn’t try it? Maybe he/she thought it was faulty? Why didn’t he/she go to the store to retrieve his/her money? Was he/she just lazy? The only thing that I know is that I have a working aircon in the living room now 😂.

Now that it is working, and being the owner of another aircon in my bedroom which I can control with my phone, I thought the living could not be less, and started once again decoding the remote IR codes, as I did some months ago with my bedroom unit.

IRrecvDumpV2 told me the protocol was NEC, with a length of 73:

Following the same procedure, I followed before, I noted down all the codes passing through every mode, speed, temperatures and other functions of the aircon, using the original controller. The result was a bunch of data to sort and research, in order to find patterns. Time for Excel!

To put a bit of order in the chaos, I pasted horizontally the code chain (73 values in this case) of every action (grayish-blueish rows). After each of those rows I created a row showing the difference between the previous and next values a on that position, to see which values were changing with every command. I applied a bit of conditional formatting, to mark those with high changes in red to make them more visible.

With this information I could then make these conclusions:

  • Values 4, 6 and 8 correspond to the mode (COLD, DEHUMIDIFICATION, HEAT, AUTO or FAN)
  • Value 10 corresponds to the state (ON or OFF)
  • Codes 12 and 14 correspond to the fan speed (LOW, MEDIUM, HIGH, or AUTO)
  • Code 16 corresponds to the SWING function (which makes the air guide swing back and forth so the air is distributed evenly) (ON or OFF)
  • Codes 20, 22, 24 and 26 correspond to the temperature (from 16 to 30ºC)

The values in those positions appear to have two values: around -500 and around -1600, which are representations of the logic false (0) and true (1) respectively. Following this logic, we can see the possible values for each function of the aircon are:

  • For the mode:
    • 000 – AUTO
    • 100 – COLD
    • 010 – DEHUMIDIFICATION
    • 110 – FAN
    • 001 – HEAT
  • For the state:
    • 0 – OFF
    • 1 – ON
  • For the fan speed:
    • 00 – AUTO
    • 10 – LOW
    • 01 – MEDIUM
    • 11 – HIGH
  • For the SWING function:
    • 0 – OFF
    • 1 – ON
  • For the temperature:
    • 0000 – 16ºC
    • 1000 – 17ºC
    • 0100 – 18ºC
    • 1100 – 19ºC
    • 0010 – 20ºC
    • 1010 – 21ºC
    • 0110 – 22ºC
    • 1110 – 23ºC
    • 0001 – 24ºC
    • 1001 – 25ºC
    • 0101 – 26ºC
    • 1101 – 27ºC
    • 0011 – 28ºC
    • 1011 – 29ºC
    • 0111 – 30ºC

As a curiosity, the values seem to follow an inverted binary order (first 000, then 001 which inverted is 100, then 010, 110…)

With this cleared up, now we can create an arduino sketch to test our theories. The hardware is the same as in my bedroom aircon, and the sketch is based on that one too.

We declare some arrays with the values of every command of every function:

/**
 * Another weird point here is the value for COOL here is the same as the value for OFF mode. Oh well...
 */
const byte modeCommandValues[] { 0b00000000,    //AUTO -> 000
                                 0b00000100,    //COOL -> 100
                                 0b00000010,    //DRY  -> 010
                                 0b00000110,    //FAN  -> 110
                                 0b00000001 };  //HEAT -> 001

/**
 * Speed values follow a reverse binary count, being 00 = AUTO and counting up 01 LOW,
 * which once reversed gives 10.
 */
const byte speedCommandValues[] { 0b00000000,   //AUTO -> 00
                                  0b00000010,   //LOW  -> 10
                                  0b00000001,   //MED  -> 01
                                  0b00000011 }; //HIGH -> 11

/**
 * Temperatures follow a reverse binary count, being 0000 = 16ºC and counting up 0001,
 * which once reversed gives 1000.
 */
const byte temperatureCommandValues[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  //Filler positions
                                        0b00000000,                       //16ºC -> 0000
                                        0b00001000,                       //17ºC -> 1000
                                        0b00000100,                       //18ºC -> 0100
                                        0b00001100,                       //19ºC -> 1100
                                        0b00000010,                       //20ºC -> 0010
                                        0b00001010,                       //21ºC -> 1010
                                        0b00000110,                       //22ºC -> 0110
                                        0b00001110,                       //23ºC -> 1110
                                        0b00000001,                       //24ºC -> 0001
                                        0b00001001,                       //25ºC -> 1001
                                        0b00000101,                       //26ºC -> 0101
                                        0b00001101,                       //27ºC -> 1101
                                        0b00000011,                       //28ºC -> 0011
                                        0b00001011,                       //29ºC -> 1011
                                        0b00000111 };                     //30ºC -> 0111

And when sending the complete command, we can mix them in a 64 bit variable. Even though the complete command is 73 bits long, the values are repeated twice, and including 3 values at the start which are sent automatically by the library. We only need to use the 70 bits (which really are 35).

  uint64_t command;
  command = modeCommandValues[modeState];             //Mode
  command <<= 1;
  command |= (powerState?1:0);                        //On-Off
  command <<= 2;
  command |= speedCommandValues[speedState];          //Speed
  command <<= 1;
  command |= (swingState?1:0);                        //Swing enabled/disabled
  command <<= 5;
  if (modeState != 0) {
    command |= temperatureCommandValues[tempState];   //Temperature
  } else {
    command |= temperatureCommandValues[25];          //25ºC for auto mode
  }
  command <<= 20;
  command |= 0b1010;                                  //End of command
  command <<= 3;

Let’s explain this last code a bit: The command variable is a uint64_t (unsigned 64 bit integer), and what we are doing is load the bits of every function without erasing the bits of the previous function (an OR boolean operation. For example, 100 OR 001 = 101), and then we apply a left shift by the number of positions of the next function (for example, 111 << 3 = 111000). All that this does in to “concatenate” the bit values of every function of the command.

As a special case, there is the “AUTO” mode. In this mode, this model of aircon expects the temperature to be 25 degrees (1001) and no other value. In case of sending another value, the fan stops and never starts. So, when we are in this mode, we will send manually the temperature value 1001.

As the protocol used in the aircon is NEC, we can use irsend.sendNEC(), indicating the command variable and the length of the command, in this case, 35.

  irsend.sendNEC(command, 35);
  delay(40);

And with this our small controller board works! Well, we need to make the boring configuration in our IoT system, in my case OpenHAB, but I will not detail the process here, because it is exactly the same as in the last aircon project, and very similar than my smart washing machine. The number of functions differs (this aircon has the SWING function, so another MQTT topic and another item in OpenHAB are needed, but apart from that, the process is the same.

It is a total luxury being able to control your aircon with your phone or any other device that has a web browser, and the possibility of breaking something (having a minimal knowledge in electronics) is almost zero, since there is not really electrical connection between the microcontroller board and the aircon itself. The commands are sent via infrared.

With this I consider my aircon adventures done. I have another two aircons that will be modified in the future, but both of them are the same model (or compatible) as these two I shared with you here, so I will just do a copy-paste. In the future maybe I buy another one, for the last room that has no aircon. In case it does not come with WiFi, I’ll let you know 😊

You can find the code list down below, and the arduino sketch on my github.

See you in the next post!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Ver
Privacidad