Introduction: Hacking an LG Ducted Split for Home Automation

First of all - This is not another Infrared remote control emulation hack. My particular AC has no usable interface designed for any sort of control other than the included wall mounted smart controls.

I have an LG Ducted reverse split system in my house. Unfortunately it was made at a time where IoT was not high on any manufacturers list. I discovered it had some options for 'master' control but even though the unit was only 2 years old at the time of me first attempting this, the expansion boards were unobtanium and prices were astronomical anyway. As was the 'Wireless RF Remote' addon which would have made things a lot easier but impossible to buy.

Had it been my choice, it would not be an LG but since it was installed in the house when I purchased it (and it's replacement cost would likely be in excess of $10k) it's what I had to deal with.

Aim - To be able to control the AC via MQTT for the purposes of automation via OpenHAB and IFTTT/Google Assistant

Step 1: Decoding the Data Format

I started this process 4 years ago but didn't get very far and didn't want to risk damaging the unit - Especially since parts for it seem almost impossible to find.

Ripping the controller off the wall I found 3 wires which I determined to be Ground, 12v and 'signal'

The signaling voltage on the data line was at 12v, but i did notice that it seemed to fluctuate on the multimeter (some sort of pulses on the line).

I bread boarded a a basic circuit to drive an opto isolator via the data pin and connected the other side of the opto isolator as an input on my PC's sound card and got a poor version of a scope output (Pic 1).

This is about as far as I got at the time - I could see there was something there but didn't really know how to 'decode' it.

Since getting my Coffee Machine IoT enabled, I had a refreshed interest in trying this again with a little more determination this time.

I posted my findings over at the EEVBlog forums to see if someone might be able to shed some light and a great guy named Ian came to my rescue - He laid it out in a way it completely made sense (Pic 2)

Basically, the data stream is 13 bytes of 'standard serial' - 8 data bits, one start bit and one stop bit (no parity) but at a VERY low baud rate of 104bps.

Step 2: Looking Deeper

So now that I had an idea of how the data was formatted, I needed a way to be able to read the data in a more dynamic way.

I pulled one of my controllers off the wall and hooked it up via a logic level shifter to an Arduino with a simple sketch to read 13 bytes of data via software serial port configured at 104bps and print it out:

168,18,0,8,0,192,6,22,0,0,0,0,
168,18,0,8,0,192,6,22,0,0,0,0,
40,19,0,8,0,200,6,31,0,0,0,0,
40,19,0,8,0,200,6,31,0,0,0,0,
200,18,0,8,64,0,6,25,0,0,0,0,
200,18,0,8,64,0,6,25,0,0,0,0,
168,18,0,8,0,200,6,22,0,0,0,0,
168,18,0,8,0,200,6,22,0,0,0,0,
168,18,0,8,0,200,6,22,0,0,0,0,

**Actually 12 bytes here

We had action!

By then changing the various settings on the controller, I was able to work out the bytes that change:

168,3,0,0,0,192,3,31,0,0,0,0,248,Fan LOW
168,35,0,0,0,192,3,31,0,0,0,0,248,Fan MED
168,67,0,0,0,192,3,31,0,0,0,0,152,Fan HIGH

168,67,0,0,0,248,3,33,0,0,0,0,82,Z1234
168,67,0,0,0,192,3,34,0,0,0,0,133,Z1
168,67,0,0,0,160,3,34,0,0,0,0,229,Z2
168,67,0,0,0,144,3,34,0,0,0,0,245,Z3
168,67,0,0,0,136,3,35,0,0,0,0,204,Z4

168,75,0,0,0,136,3,35,0,0,0,0,244,Mode FAN
168,79,0,0,0,136,10,35,0,0,0,0,249,Mode AUTO
168,67,0,0,0,136,3,35,0,0,0,0,204,Mode COOL
168,83,0,0,0,136,15,34,0,0,0,0,225,Mode HEAT
168,7,0,0,0,136,15,34,0,0,0,0,61,Mode DH

168,15,0,0,0,136,3,34,0,0,0,0,49,Temp 18
168,15,0,0,0,136,4,34,0,0,0,0,48,Temp 19
168,15,0,0,0,136,5,34,0,0,0,0,51,Temp 20
168,15,0,0,0,136,15,34,0,0,0,0,37,Temp 30

The numbers make much more sense when you look at them in binary but what's with the 13th byte?? It's all over the place...

Step 3: Mapping It Out

Through trial and error, I was able to determine the relevant bits in the 13 bytes of data that I would need to be able to transmit.

Step 4: Brick Wall Ahead!

This is where it got complicated. I had two hurdles to overcome

a) The 13th byte appeared to be a checksum of the data that I needed to somehow work out.
b) How do I transmit the data then? It's only one wire.

Issue 'a' turned out to be REALLY easy, but it was by pure coincidence that I managed to get past it.

In my tests, I was looking at data like:
A802000000040F61000000004B
A81200004004169A00000000FB
A81200004004159A00000000F8
A81200004004149A00000000E5
A81200084000149C00000000E7
A83200084000149C0000000087
A85200084000149C00000000A7

This is the 13bytes of data including the checksum (here in HEX instead of DEC).

When I was searching the oracle that is google on 'how to reverse engineer a checksum' I came across this page on stack exchange with someone else going by the name of Nick asking pretty much the same thing as me but not only that, they talked about an air conditioner and their data was almost identical format to mine - Could it be??? In all my searching (in 4 or so years), not one person had posted any information on how to hack the protocol on these air conditioners and I just happen to stumble upon someone doing the same thing by searching for something almost completely unrelated? It was a blessing - He even posted that he worked it out and the solution was: Add up all of the Bytes of data and then XOR with "U".

With that in hand I added it to my code to calculate what I thought the checksum should be vs what it actually was but it was all WRONG!!

As it turns out, it was sort of wrong. When I started looking at the numbers in binary, it made complete sense.

The response from the 'XOR with U' always returned 9 bits of data (the 9th bit always one) but the other bits were right. I simply removed the 9th bit by taking 256 from the resulting number and then it matched!!

Had it not have been for this individual, I might still be scratching my head. Hats off to him too but I can't contact him - That was basically his only post on the stackexchange forum. Well, thank you stranger :)

The next challenge was making a circuit that would allow me to simulate the existing controller. I mapped out the schematic for the drive circuit (Pic1 and Pic 2) but it seemed way too complicated for me to need to reproduce it to get what I wanted. I was already reading the signal after all. I opted for a much simpler method - Using the arduino to drive an opto isolator to pull the 12v signal line low as required.

I also designed a simpler circuit for the Rx but this is untested, I ended up sticking with the level converter for simplicity.

Step 5: Making It Work..

Once I had the transmit circuit breadboarded, and with a racing heart, I mangled up a (static) string of 12 bytes, calculated the checksum and had the arduino send the command - Amazingly, the display updated!!! Win!

The final actual test was to add my arduino to the BUS with the 2 other controllers for a real live test and sure enough, it worked.

So now I could Read and Write to the bus but just lacked the ability to be able to do it simply.

Since I use MQTT almost exclusively for all my home automation, it was natural that this would be the same.
I wrote out the code over several days to control the 4 main elements of the AC, also reading back the existing status (from the other modules on the BUS)

The intention was to have the code running on an ESP8266 module however it would seem that the ESP8266 is not able to produce a baud rate as low as 104bps. I had to revert to a generic Arduino Uno with Wiznet ethernet but that was not hard as my comms rack was literally on the other side of the wall from one of the AC controllers.

The code is a bit all over the place but should be legible. I had a lot of problems with preventing the controller from reading it's own output but also repeating the code it it's own published topics received from MQTT back to the aircon. Basically, it would create an infinite loop. In the end, some buffer clearing and delays in the processing of code after publishing to MQTT got it sorted.

Rx,Tx pins to the AC are coded as 3,4 but change if you like

The code is configured to publish and accept commands as such:

ha/mod/5557/P 0/1 - Power
ha/mod/5557/M 0/1/2/3/4 - Mode Cool,Dehumidify, Fan, Auto, Heat
ha/mod/5557/F 0/1/2 - Fan low, med, high
ha/mod/5557/Z i.e 1111 for all zones on 1000 for just zone 1 on.

**From the controller, zones can not be set to '0000' however it would seem that if you issue the value, it will revert to '1000'.

The latest version of the code is available from my GitHub Repo: https://github.com/ahuxtable/LG_Aircon_MQTT_interface

Step 6: Something More Permanent

I gathered up an arduino prototype board and installed all of the parts as I had them bread boarded.

Step 7: OpenHAB Config

See attached file for OpenHAB Items, sitemap and rules

Combine this with the IFTTT OpenHab binding and Google Assistant/Home and you have a very powerful voice controlled and/or 'Smart' aircon that surpasses almost every commercially available product!

Step 8: Summary

In Conclusion - If you are one of the poor souls with a slightly older LG ducted split air conditioner, you are not alone. There is still hope for us!

I hope this instructable finds someone that needs it as much as I did. There is basically NO information that I could find (other than the checksum from 'Nick'). I had to start from scratch but I am ecstatic with the result.

The information is a tad vague I know but if you are in the same situation as I was, I'll be more than willing to help out.

--- Caution / Update ---
Although it is possible to change the settings on the AC with the unit Off, I have found that when it comes to the Zone control it seems to mess with it. I done a lot of testing with the unit off and I found that the zones would show as inactive but when the unit is operating, it seems that the dampers are not fully closed (but not fully open either). I reset the unit at the main breaker and this resolved the issue. Since only changing zones when the unit is on, this has not been a problem.

I have also updated the code to only publish (to MQTT) changes that come from the master controller and not the main unit. Once again, this could cause problems because the main unit will send '0000' for the zones (which could also have been the problem).

Updated code also introduces some timing constraints to try to prevent the arduino from transmitting at the same time of the master and main unit. I'm sure there is probably a method that the controller uses to initiate a data send like pulling the line low for Xms before sending but I have not discovered it yet if there is.

I discovered that the main unit will send data every 60 seconds and the master controller sends every 20 seconds. The code attempts to stall sending data within 2 seconds of receiving data packet. However, sometimes the master and main unit transmit very close to each other. This will probably be refined more soon.
----------------------------

**May work on newer units

*** Some information found in my research travels indicated Panasonic ducted split might use the same protocol. YMMV.

Internet of Things Contest 2017

Participated in the
Internet of Things Contest 2017