Fully controllable legacy Air Conditioner AC with ESPHome (no IR, direct wiring to remote board)

Hi Folks,

I just wrapped up a fairly complex project that I reckon may help a few of you all.

I moved into a house with 7 existing AC units that are pretty old (probably installed around 2010) way before inverters, wifi boards or serial bus boards integrated into the units.

Wanting to avoid having IR controllers in every room, and no real information on current state of the unit I did some AI assisted hacking and found a great solution, shared below.

I patched the board's pin header that connects to the remote board with an ESP32 and managed to read the state of the compressor (measuring voltage of the LED associated to it) and push remote control signals (as if the remote had been pressed) by leaking voltage into the correct header.

I won't lie, it's a pretty involved hack, that implies:

  • Soldering and assembly of a custom board
  • Dissassembly of the AC front unit
  • Tapping directly into the AC's 220V mains to power the ESP32
  • Writing and flashing a custom ESPHome configuration to tie it all natively into Home Assistant.

If you are comfortable with basic electronics, handling mains voltage, and ESPHome, this is the ultimate way to make a "dumb" AC truly smart without relying on line-of-sight IR blasters. Here is the blueprint on how I pulled it off.

1. The Hardware Build

  • An ESP32 board (I used a standard ESP32 Dev Board, but anything will do).
  • An NPN Transistor (2N2222): This is used for the IR injection. It safely isolates the ESP32 and acts as an electronic switch to perfectly mimic the IR receiver's pulses without voltage conflicts. I tried pushing voltage straight from the ESP32 but it wasn't high enough.
  • Hi-Link HLK-PM01 Power Module: The AC's onboard 5V regulator is way too weak to handle the ESP32's WiFi spikes. Instead of messing with the low-voltage side, I used an encapsulated Hi-Link AC-to-DC module. I patched its inputs directly into the 220V line (located at the top of the control board, via the red wires) to give the ESP32 its own robust, dedicated 5V supply. (Crucial note: Even though it's on a separate power supply, you MUST tie the ESP32 ground to the AC logic ground for the data signals to work!).
  • Resistors: To safely drop the 5V status LED signal down to 3.3V so the ESP32 can read it without getting fried, and to feed the transistor base with the signal to be amplified.
  • DHT11 Sensor: I added a DHT11 sensor to the board to include sensor state of the current temperature in the room. I drilled a small hole in the casing and hot glued the DHT11 so it is in contact with the room's air for improved precision in the measurement.

2. The Wiring & "The Hack"

Older ACs usually have a ribbon cable connecting the mainboard to the front display/IR receiver. I intercepted two critical signals here:

  • Sending Commands (The rem pin): Instead of an IR LED blasting across the room, I connected the ESP32 to the demodulated IR signal pin (usually labeled rem or out on the IR receiver module). By using the NPN transistor, the ESP32 pulls this line to ground, perfectly simulating the raw digital pulses of a physical remote. The AC mainboard has no idea it didn't come from the physical remote. The transistor connects as follows:
    • Base: Receives signal from ESP32 via a 1K resistor
    • Collector: Ground
    • Emitter: Sends signal into pin REM of the AC unit.
  • Reading Status (The LED pins): To get true state feedback, I tapped the wire going to the "Run" or "Compressor" LED on the front panel. Checking the voltage I saw it never passed 3.5v, so I sent it into the ESP32 pin with a 1K resistor. When the AC turns on, the LED gets power, the ESP32 reads the voltage, and Home Assistant instantly knows the AC is actually running.
  • Adding Temperature Reading: Simply connect the DHT11 to the board to get temp and humidity readings.

3. The Software (ESPHome)

Because these units are essentially using older TCL mainboards, the IR protocols are already fully decoded in the community. I used ESPHome's climate_ir platform (specifically the tcl112 protocol).

  • I configured the transmitter_id to output on the ESP32 pin connected to my transistor.
  • Crucial Step: I set the carrier_duty_percent: 100%. Because we are injecting directly into the wire and bypassing the physical IR receiver, we have to disable the 38kHz IR carrier wave and just send the raw data envelope.
  • I mapped the LED status pin as a binary sensor to keep the Home Assistant thermostat card in perfect sync with reality.

The Result

A completely hidden, fully localized smart AC integration. No cloud, no lag, and no more guessing if the IR blaster actually hit its target. The thermostat card in HA updates instantly even if someone in the house uses the physical IR remote, because the hardware state is the ultimate source of truth.

Disclaimer: You are poking around inside an appliance connected to mains (220V) voltage. Ensure the unit is completely unplugged/unbreakered before taking off the front panel, and keep all your low-voltage ESP32 wiring safely isolated from the high-voltage lines! Do not attempt the Hi-Link installation if you aren't comfortable safely routing and insulating high-voltage AC wires.

Hope this helps someone looking to modernize their older split units!

Some pictures and wiring diagrams below:

Final board plugged into the AC unit:

Zoom view of the AC unit header where the pins are inserted (GND, REM, RUN):

Side view of the AC board: AC voltage is found at the top, behind the aligator clips in this picture.
:warning:Hey! Make sure the unit is unplugged before messing with the board.:warning:

Wiring Diagram

ESPHOME Yaml for reference:

esphome:
  name: ac-room1
  friendly_name: AC-room1

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "GENERATED-ON-INSTALL"

ota:
  - platform: esphome
    password: "GENERATED-ON-INSTALL"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Ac-room1 Fallback Hotspot"
    password: "GENERATED-ON-INSTALL"

captive_portal:

# 1. Define the "Remote" Transmitter for Direct Injection
remote_transmitter:
  pin:
    number: GPIO27 # Ensure this matches your wiring
  # CRITICAL: 100% duty cycle disables the 38kHz carrier wave. 
  # This outputs the raw demodulated signal the 'rem' pin expects.
  carrier_duty_percent: 100% 
  id: ac_transmitter

# 2. Define the TCL Climate Component
climate:
  - platform: tcl112
    name: "Climate"
    transmitter_id: ac_transmitter
    sensor: current_room_temp
    humidity_sensor: current_room_humidity 
    visual:
      min_temperature: 16 °C
      max_temperature: 31 °C
      temperature_step: 1 °C

# 3. Sensors (ADC & DHT11 merged)
sensor:
  # Your existing raw voltage sensor
  - platform: adc
    pin: GPIO34
    id: run_led_voltage
    name: "LED Voltage"
    update_interval: 200ms
    attenuation: 11db  
    filters:
      - sliding_window_moving_average:
          window_size: 5
          send_every: 1

  # Your DHT11 Temperature & Humidity sensor on GPIO5
  - platform: dht
    pin:
      number: GPIO25
      mode: INPUT_PULLUP
    model: DHT11
    temperature:
      name: "Temperature"
      id: current_room_temp
    humidity:
      name: "Humidity"
      id: current_room_humidity
    update_interval: 5s

# 4. The Smart Binary Sensor
binary_sensor:
  - platform: template
    name: "Compressor Status"
    id: ac_run_status
    lambda: |-
      // ON THRESHOLD: Voltage must drop definitively low (e.g., below 1.5V)
      if (id(run_led_voltage).state < 1.5) {
        return true;
      }
      // OFF THRESHOLD: Voltage must return definitively high (e.g., above 2.8V)
      else if (id(run_led_voltage).state > 2.8) {
        return false;
      }
      // DEADBAND: If the voltage is floating between 1.5V and 2.8V due to noise,
      // ignore it and just keep whatever state it is currently in.
      else {
        return id(ac_run_status).state;
      }
      
    filters:
      - delayed_on: 100ms
      - delayed_off: 1.5s    

A few notes on some questionable decisions and their back-story:

  • Powering the board

    • My first attempt was to use the AC's daughter board VIN, which measured at 5V and looked great. Unfortunately it didn't have enough power to run the board, and it never passed booting. The board probably uses a small regulator with no overhead to deliver more power.
    • When that failed, I looked for a 12V rail that could power steppers or other auxiliary systems off the board. All the rails I found went completely "off" on standby mode, which wouldn't work.
    • Lastly I found the mains 220v line and went with that, with the best isolation I could.
  • Voltage measuring of the "power" LED

    • The solution looks complicated because the LED is run with a square wave, so the voltage was all-over the place when the LED is on. The best I could do is to measure on the averages and that worked well enough.

Realy cool.
Did the ac unit not have a temperature sensor it uses for automatically keeping a set temperature?

I've been thinking of doing the same sort of thing for my tumble dryer.

It must have, yes.

I couldn't find a way to tap into it and it was pretty cheap / simple to integrate a DH11.

Cheers!