I have central air-conditioning in my apartment, and it’s controlled by a remote, employing IR signals to send commands to the A/C control unit.
As any decent geek would, I’d like to be able to control my A/C using other means (e.g., a smartphone).
Towards that goal, I figured I should first reverse engineer the IR commands the remote sends to the A/C, so I could later send these commands using other methods.
The gist: using an Arduino Uno board with a Phototransistor circuit (see below), I was able to obtain the IR waveform using Ken Shirriff’s Arduino IRremote library (slightly modified), and even graph these waveforms with Python’s matplotlib, as shown below.
Keep reading for a full drill down, or jump straight into my home-control-arduino GitHub project for the actual code and documentation.
Building the IR Receiver Circuit
- SparkFun Inventor’s Kit for Arduino (available in Israel via 4Project.co.il, or via friends who sell their own kits (h/t YoniC) 🙂 ) (also see a similar Arduino starter kit on Amazon or on eBay), that comes with Arduino UNO R3 (Amazon, eBay), breadboard and a convenient holder for both (and lots of other useful stuff to get you going).
Assemble the components according to the schematic shown above, which will look something like this:
Connect the Arduino to the PC via USB, and compile and upload my IRACreceiver program to the board:
Capturing A/C Commands
Now, with the circuit built and the program loaded, open the Arduino Serial Monitor, aim the A/C remote at the phototransistor, and press buttons on the remote to make it transmit IR signals to the receiver:
and watch as the Arduino prints to the serial monitor the raw IR signals info:
Analyzing the A/C Commands
In order to produce nice graphs of these signals, like the one above, I created a data-set of A/C-command samples to process using my IRAnalysis Python script.
But before that, a couple of words are in place concerning the specifics of this A/C remote and how it functions.
Basically, the communication channel between the remote and the A/C control unit is one-way – from the remote to the control unit. This means, among other things, that the remote has no knowledge of the current state of the A/C (whether it’s on or off, what state it is set to at the moment with respect to operation mode, fan speed, temperature, etc.). Because of this, every press of a button on the remote will send the entire state as it is currently presented on the display of the remote, including information about whether the power button was pressed or not.
The implications of this include:
- By solely sending IR signals in lieu of the remote, it is not possible to explicitly control the On/Off state of the A/C, but only toggle the power state. If you think about this for a second, you can see this is not an issue when operating the remote locally, because the “human-in-the-loop” (you) knows the power state of the A/C, so the remote doesn’t need to. It becomes a problem once we take out the human from the loop – but that’s for another post.
There are no “relative” commands (e.g. “increase temperature by 1 degree”) – only absolute ones, which means we need to map all possible state-combinations that we want to be able to send on behalf of the remote to their corresponding IR signals.
So, in order to build this mapping, I decided that I am only interested in a subset of state-combinations that include A/C mode (cool / heat / …), fan speed (low / high / auto) and the temperature. In addition, I need to include the power-button in the mapping (whether a command with a given mode-fan-temp combination should toggle the power state or leave it as it was).
After all this, lets get back to the IRAnalysis Python script. The script expects to get a data-set of A/C-command samples as a collection of plaintext files (in a single directory). Each file has the state-mapping encoded in the filename (
Power-Mode-Fan-Temp), and at least one IR capture as the content of the file (simply copy & paste the captures from the serial monitor into the body of the file).
For example, I have included in the GitHub project three sample files, that produce the graphs shown above using the script with the “graph” command.
Since the Phototransistor is susceptible to ambient noise, together with the quantization noise that arises from the way the Arduino-IRremote library samples the signal, the readings produced may contain outliers. For that reason, it is highly recommended that all sample files contain multiple independent readings (say at least 3), so my script could try and detect anomalous readings.
The script tries to do this by comparing each reading to the average signal of all readings, and flag any single reading that has an element differing by more than 100us from the average reading as anomalous.
Whenever the script reports such anomalies, you should manually remove that outlying reading from the sample file, and maybe replace it with another, better, reading.
Finally, it is a natural path to dig deeper in the waveforms of different A/C-command samples, and characterize (reverse engineer) them up to the level of understanding which part of the signal encodes which part of the state, and then use this characterization to recreate waveforms from a given state.
I started looking into such undertakings (this is actually the reason that I implemented the graphing functionality), but pretty quickly I reached an understanding that it is not going to be easy (for example, I saw that two commands that differ only by 1 degree in the temperature value, differ in multiple regions of their respective waveforms) – so I left that part as an exercise for the devoted reader 🙂 (or a future self?)
With that, this post reaches its conclusion.
Feel free to go on and read my other posts related to my A/C-control project!