Controlling an AC unit with infrared using a proprietary protocol

Intro

In this guide I will show you how I control my air-conditioning unit with hard-coded messages due to it being impossible to decode the protocol that is being used.

This guide can be used by every infrared device that uses an proprietary protocol (not only airconditioning units)

While exploring the possibility of controlling my Dometic FreshWell 3000 under-bench air conditioner. I stumbled upon some difficulties controlling the infrared protocol supplied by the manufacturer.

Most of the airconditioning remote protocols used, send the entire configuration of their remote to the unit, even if only something small changes. This would make it possible to reverse-engineer the infrared code to see what changed between 2 messages and then determine what bits are responsible for what.

While many manufacturers of airconditioning units use a well-known protocol to transmit the data, Dometic uses some kind of encoding that makes it impossible to figure out what bits serve which purpose.

What you will need

  • ESPHome compatible device (e.g. ESP8266 or ESP32)
  • IR reader module
  • IR transmitter module
  • Jumper wires
  • AC remote control

1. Install ESPHome

I will be using ESPHome for this setup because it makes it easy to use ESP32 or ESP8266 devices to place them near the unit and control them that way.

Use this link to install ESPHome and set up a device

2. Wire up the IR receiver module and the IR transmitter module

Wiring

  • Connect the positive leads of the modules to 3.3V of the ESP
  • Connect the negative leads to the GND of the ESP
  • Connect the data leads of both modules to an GPIO pin (for example GPIO 16 and 17)

3. Setting up the ESP device

Create a basic ESPHome setup with an ESP device. In this example I will be using an ESP8266.

Use this code to dump all raw data received on the GPIO16 pin (IR Receiver) to the console so we can analyse it later.

remote_receiver:
  pin: GPIO16
  dump: raw

Use this code to transmit the IR codes on the GPIO15 pin (IR Transmitter) in the future when we have determined what codes we need to send.

remote_transmitter:
  pin: GPIO15
  carrier_duty_percent: 50%

4. Analysing the infrared codes

When you upload your config to your ESP device, navigate to the Logging component of the ESPHome device, here you should be able to see the log output from the ESP device.

Point your remote of the device you want to control towards your IR-receiver and press on a button.
You should see something like this in you log:

[6496, -7444, 672, -3332, 696, -3290, 718, -1286, 716, -1266, 704, -1296, 674, -1328, 694, -3290, 676, -3314, 674, -1328, 692, -1310, 718, -3264, 658, -3336, 706, -3300, 720, -3272, 676, -1332, 720, -1264, 672, -1328, 718, -1288, 716, -1270, 698, -1302, 656, -1350, 718, -1268, 742, -3268, 718, -1268, 672, -3340, 720, -3270, 712, -3280, 702, -3308, 718, -3270, 652, -3342, 738, -1260, 676, -3318, 670, -1330, 718, -3274, 696, -3306, 718, -3266, 654, -1350, 716, -1266, 738, -3270, 716, -1268, 670, -3338, 716, -1266, 694, -1304, 680, -1322, 716, -3270, 652, -3342, 736, -1264, 650, -3346, 668, -1360, 686, -1294, 710, -1276, 698, -3310, 710, -1276, 728, -1272, 650, -3342, 730, -1270, 710, -3284, 668, -3342, 708, -3280, 678, -1328, 706, -3280, 648, -3344, 726, -1274, 648, -3346, 644, -7518, 706]

(If nothing appears something is wrong with your configuration of wiring of you IR-receiver and you need to re check that setup.)

This array of values are actually infrared timings of the infrared led detecting pulses. So in theory if we copy these timings and re-emit those with our IR transmitter, we should be able to pass the same information to the AC unit like we received from our remote.

We can test this by adding this piece of code to our configuration:

switch:
  - platform: template
    name: "hvac on"
    turn_on_action:
    - remote_transmitter.transmit_raw:
        carrier_frequency: 38kHz
        code: [6538, -7454, 714, -1270, 624, -3386, 714, -1268, 644, -1358, 714, -1292, 714, -1270, 700, -3316, 714, -3278, 716, -3276, 648, -1354, 714, -3278, 670, -3338, 712, -3272, 686, -3304, 700, -1302, 682, -1324, 712, -1270, 648, -1356, 712, -3278, 648, -1358, 712, -1292, 712, -1270, 698, -3312, 712, -1268, 648, -3360, 712, -3270, 714, -1292, 710, -3274, 714, -3276, 698, -3314, 712, -1268, 728, -3280, 714, -1270, 622, -3388, 712, -1268, 646, -1356, 710, -1292, 712, -1272, 698, -1306, 682, -3306, 676, -3338, 710, -1272, 646, -3366, 714, -3278, 710, -3280, 698, -3316, 712, -3278, 682, -1324, 710, -3300, 660, -1316, 712, -3272, 688, -1318, 710, -1270, 696, -1308, 682, -1324, 710, -3274, 710, -1294, 686, -3300, 686, -1318, 686, -3298, 688, -3298, 674, -3336, 712, -3278, 680, -1326, 672, -7476, 712]
    optimistic: True

If you add this, we send out the infrared code to the AC unit using our transmitter.
In Home Assistant you can now add this switch to you dashboard and you can try and flip it. It should trigger the AC unit into turning on and configuring it with the settings that were visible on your remote at the time while using the remote control.

4. Capturing all codes

Now that we saw that the code is actually working, we can now capture every possible configuration that we would like Home Assistant to control. We can do this by setting the configurations we want trough the remote and then creating something like an excel file to store every value we want to use later.

If your unit happens to be a Dometic unit you can use my code:

5. Making a configuration slider to control the AC

In the following 2 code pieces I will be configuring a Heating/Cooling selector and a temperature slider. The 2 will be interfacing with each other to determine the required configuration is.

This is the heating selector, it is a selector with Heating and cooling as option. If one or the other is selected, it sends a command to the next piece of code which is the slider. This code will then send the IR code.

select:
  - platform: template
    name: AC_mode
    id: ACmode
    optimistic: True
    options:
     - "Heating"
     - "Cooling"
    initial_option: "Heating"
    set_action:
      - delay: 1s
      - number.set:
          id: tempSlider
          value: !lambda return id(tempSlider).state;

This is a slider that sends out the IR code of the required configuration to the AC unit. It looks for the AC_mode component above to determine if the user wants heating or cooling functionality. And then sends the command accordingly.

number:
  - platform: template
    name: "temperature_slider"
    id: tempSlider
    optimistic: True
    step: 1
    min_value: 16
    max_value: 31
    mode: slider
    set_action:
      - if: #16
          condition:
            lambda: 'return x == 16;'
          then:
            if:
              condition:
                lambda: return id(ACmode).state == "Heating";
              then:
                - remote_transmitter.transmit_raw:
                    carrier_frequency: 38kHz
                    code: [6496, -7444, 672, -3332, 696, -3290, 718, -1286, 716, -1266, 704, -1296, 674, -1328, 694, -3290, 676, -3314, 674, -1328, 692, -1310, 718, -3264, 658, -3336, 706, -3300, 720, -3272, 676, -1332, 720, -1264, 672, -1328, 718, -1288, 716, -1270, 698, -1302, 656, -1350, 718, -1268, 742, -3268, 718, -1268, 672, -3340, 720, -3270, 712, -3280, 702, -3308, 718, -3270, 652, -3342, 738, -1260, 676, -3318, 670, -1330, 718, -3274, 696, -3306, 718, -3266, 654, -1350, 716, -1266, 738, -3270, 716, -1268, 670, -3338, 716, -1266, 694, -1304, 680, -1322, 716, -3270, 652, -3342, 736, -1264, 650, -3346, 668, -1360, 686, -1294, 710, -1276, 698, -3310, 710, -1276, 728, -1272, 650, -3342, 730, -1270, 710, -3284, 668, -3342, 708, -3280, 678, -1328, 706, -3280, 648, -3344, 726, -1274, 648, -3346, 644, -7518, 706]
              else:
                - remote_transmitter.transmit_raw:
                    carrier_frequency: 38kHz
                    code: [6482, -7482, 680, -3334, 686, -3298, 688, -1298, 708, -1288, 680, -1326, 692, -1316, 688, -3296, 680, -3302, 680, -1326, 692, -1314, 690, -3298, 690, -3296, 678, -3334, 690, -3290, 690, -1316, 690, -1288, 704, -1300, 690, -1312, 692, -1284, 678, -3332, 692, -1288, 676, -1324, 720, -1310, 694, -3290, 718, -3276, 672, -3340, 692, -3296, 682, -1326, 694, -3294, 680, -3312, 740, -3268, 694, -1290, 672, -1328, 656, -3332, 702, -3302, 722, -3264, 678, -1326, 718, -1266, 740, -3264, 720, -1268, 692, -3312, 718, -1264, 698, -1300, 678, -1326, 720, -3266, 676, -3320, 742, -1256, 676, -3320, 670, -1330, 720, -1284, 722, -1262, 734, -3274, 724, -1262, 742, -1258, 674, -3318, 742, -1258, 722, -3272, 700, -3310, 722, -3264, 658, -1348, 720, -3264, 652, -3342, 738, -1260, 672, -3322, 644, -7518, 716]
      - if: #17
          condition:
            lambda: 'return x == 17;'
          then:
            if:
              condition:
                lambda: return id(ACmode).state == "Heating";
              then:
                - remote_transmitter.transmit_raw:
                    carrier_frequency: 38kHz
                    code: [6526, -7460, 702, -3288, 672, -3322, 720, -1296, 652, -1352, 680, -1306, 698, -1300, 706, -3268, 694, -3326, 686, -1306, 698, -1298, 650, -3324, 718, -3306, 684, -3286, 698, -3314, 700, -1300, 704, -1300, 678, -1308, 698, -1298, 652, -1354, 678, -3290, 696, -1328, 706, -1322, 680, -3302, 652, -1352, 678, -3282, 702, -3308, 686, -3300, 702, -1300, 706, -3284, 706, -3286, 650, -1378, 684, -3282, 704, -1322, 684, -3302, 662, -1344, 688, -1296, 706, -1296, 656, -1350, 690, -3296, 654, -1352, 686, -3296, 686, -1318, 688, -3300, 658, -3316, 726, -3282, 704, -3300, 654, -1352, 682, -3298, 686, -3282, 694, -1324, 658, -3312, 698, -1322, 658, -1346, 686, -1296, 708, -3298, 686, -1298, 674, -1326, 688, -3282, 696, -1322, 660, -3310, 702, -3326, 686, -3300, 658, -1348, 686, -3302, 688, -7458, 674]
              else:
                - remote_transmitter.transmit_raw:
                    carrier_frequency: 38kHz
                    code: [6516, -7472, 692, -3296, 654, -3340, 704, -1292, 652, -1352, 690, -1300, 734, -1260, 676, -3322, 734, -3272, 690, -1300, 696, -1300, 652, -3344, 710, -3294, 688, -3302, 672, -3324, 706, -1290, 676, -1332, 690, -1298, 696, -1302, 652, -1352, 688, -3302, 650, -1356, 708, -1324, 686, -1298, 708, -3304, 686, -3306, 686, -3312, 670, -3344, 686, -1298, 696, -3314, 684, -3302, 650, -3340, 734, -1266, 706, -1300, 680, -3308, 682, -3308, 668, -3340, 682, -1300, 696, -3312, 706, -1278, 730, -3282, 680, -3306, 678, -1328, 706, -1278, 670, -1334, 676, -3314, 700, -1304, 670, -3320, 700, -1300, 676, -1330, 702, -1278, 668, -1332, 676, -3316, 696, -1306, 672, -3320, 698, -1306, 648, -3342, 668, -3342, 702, -3280, 676, -3316, 692, -1308, 672, -3316, 694, -1306, 670, -3322, 698, -1306, 674, -7490, 670]

Conclusion

While it is not the most beautiful solution to control an AC unit, sadly there is no other way to solve the problem due to the proprietary encoding the manufacturer is using. :frowning:
But luckily with a bit of work we can still create the wanted result. :slight_smile:

If there are any questions or additions, please feel free to ask or add them!

4 Likes