Controlling an AC unit (via remote) using arduino

Hi, I'm trying to do a very simple circuit with Arduino to control my AC unit.

What I did so far:

  • used the IR Receiver to get the IR codes for on/off
  • I have a tempereature sensor and an IR Blaster setup on the board, I tested them both, they are correctly wired and the blaster does send some IR data

However, my AC unit (or units, I've tried with 2) don't react to that.

So now I am a bit lost a to what is going on.

#include <IRremote.hpp>
#include <DHT.h>

#define RAW_BUFFER_LENGTH 400

uint16_t rawOn[] = { 3150, 1500, 550, 1050, 550, 1000, 550, 150, 650, 150, 650, 150, 700, 1000, 550, 150, 650, 150, 650, 1050, 500, 1050, 550, 150, 650, 1050, 550, 150, 600, 150, 700, 1000, 600, 1000, 550, 150, 650, 1000, 550, 1050, 550, 150, 650, 150, 650, 1000, 600, 100, 650, 150, 700, 150, 650, 1000, 550, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 100, 700, 150, 650, 150, 650, 150, 650, 150, 700, 100, 700, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 1050, 500, 150, 700, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 650, 200, 650, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 100, 700, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 1000, 550, 150, 650, 1050, 550, 150, 650, 150, 650, 1050, 500, 1050, 550, 150, 650, 0 };
const uint16_t rawOnLen = sizeof(rawOn) / sizeof(rawOn[0]);

uint16_t rawOff[] = { 3150, 1500, 500, 1050, 550, 1050, 500, 150, 650, 150, 700, 150, 650, 1050, 550, 150, 600, 150, 700, 1000, 550, 1050, 500, 150, 700, 1000, 550, 150, 650, 150, 650, 1050, 550, 1000, 550, 150, 650, 1050, 550, 1000, 550, 150, 650, 150, 650, 1050, 550, 150, 650, 150, 650, 150, 650, 1050, 550, 150, 650, 150, 650, 150, 650, 200, 650, 150, 650, 150, 650, 150, 650, 150, 650, 200, 650, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 650, 200, 650, 150, 650, 1050, 500, 150, 650, 200, 650, 150, 650, 150, 650, 150, 650, 150, 650, 200, 650, 150, 650, 150, 650, 150, 650, 150, 650, 200, 650, 150, 650, 150, 650, 150, 650, 150, 650, 200, 650, 150, 650, 150, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 650, 200, 650, 150, 650, 150, 650, 150, 650, 150, 650, 200, 650, 150, 650, 150, 650, 150, 650, 150, 650, 200, 600, 200, 600, 200, 650, 150, 650, 150, 650, 150, 700, 150, 650, 150, 650, 150, 650, 150, 700, 100, 700, 150, 650, 150, 650, 200, 600, 200, 600, 250, 600, 200, 600, 200, 600, 150, 650, 250, 550, 250, 600, 1000, 550, 200, 600, 1000, 550, 250, 600, 200, 600, 1000, 550, 1050, 550, 200, 600, 0 };
const uint16_t rawOffLen = sizeof(rawOff) / sizeof(rawOff[0]);
// ==== END PASTE ====

// Pins
const uint8_t IR_SEND_PIN = 3;   // IR LED via NPN transistor (UNO default carrier pin)
const uint8_t DHT_PIN     = 7;
const uint8_t DHT_TYPE    = DHT11;
const uint8_t CARRIER_KHZ = 38;  // most remotes

// Thresholds & state
const float ON_THRESHOLD  = 20.0;  // >= -> send ON
const float OFF_THRESHOLD = 16.0;  // <= -> send OFF
enum State { S_UNKNOWN, S_ON, S_OFF };
State state = S_UNKNOWN;

DHT dht(DHT_PIN, DHT_TYPE);

void setup() {
  Serial.begin(9600);
  dht.begin();
  IrSender.begin(IR_SEND_PIN);   // correct IRremote 4.x signature
  Serial.println("Thermostat ready (DHT11 on D7, IR send on D3).");
}

void loop() {
  static unsigned long last = 0;
  if (millis() - last < 2000) return;  // read every ~2s
  last = millis();

  float t = dht.readTemperature();
  if (isnan(t)) {
    Serial.println("DHT read failed");
    return;
  }

  Serial.print("Temp = ");
  Serial.print(t, 1);
  Serial.println(" °C");

  if (t >= ON_THRESHOLD && state != S_ON) {
    Serial.println(">= 20°C → SEND ON");
    IrSender.sendRaw(rawOn,  rawOnLen,  CARRIER_KHZ);
    state = S_ON;
  } else if (t <= OFF_THRESHOLD && state != S_OFF) {
    Serial.println("<= 16°C → SEND OFF");
    IrSender.sendRaw(rawOff, rawOffLen, CARRIER_KHZ);
    state = S_OFF;
  }
}

This is the code I've tried so far.

Any help would be highly appreciated!

  • Always show us a good schematic of your proposed circuit. Show us good images of your ‘actual’ wiring.
    Give links to components.

What brand/model?

So updates, I managed to make it work with a Daikin unit, and now I am trying to make it work with a Start-Light unit.
However, I got the on/off codes from someone here: java - Does anyone know the IR Pattern integer for Daikin air conditioner (I want to simulate on/off signal) - Stack Overflow

So now my assumption is that my current way of getting the IR codes is not getting everything I need.
I'm a bit lost on how to get the codes for the other remote..

Made it work with a Daikin, with a Startlight not yet, but I used the codes from someone else: java - Does anyone know the IR Pattern integer for Daikin air conditioner (I want to simulate on/off signal) - Stack Overflow

Daikin is Daikin, but what is Star-light?

Feel free to post the code you use for receiving.

If you had #define RAW_BUFFER_LENGTH 400 (has to be before #include <IRremote.hpp>)
you likely got the whole code (122 bit +header).

This is the StarLight AC: Starlight AC

This is the code for receiving the IR Codes

// Arduino UNO + IRremote 4.x
// Receiver on D2. Open Serial Monitor @ 115200.
// Prints copy-pasteable microsecond arrays with length.
//
// NOTE: RECORD_GAP_MICROS set to ~9.5 ms to merge short AC repeats.

#define RAW_BUFFER_LENGTH 260
#define RECORD_GAP_MICROS 9500   // merges ~9.7 ms inter-frame repeats for AC remotes

#include <IRremote.hpp>

#ifndef MICROS_PER_TICK
  #define MICROS_PER_TICK 50
#endif

const uint8_t IR_RECV_PIN = 2;
static uint8_t tickBuf[RAW_BUFFER_LENGTH];  // captured "ticks" (each ≈50 µs)

void printUSArray(const char *name, const uint8_t *ticks, uint16_t n) {
  Serial.print("uint16_t "); Serial.print(name);
  Serial.print("["); Serial.print(n); Serial.print("] = { ");
  for (uint16_t i = 0; i < n; i++) {
    uint16_t us = (uint16_t)ticks[i] * MICROS_PER_TICK;
    Serial.print(us);
    if (i + 1 < n) Serial.print(", ");
  }
  Serial.println(" };");
  Serial.print("const uint16_t "); Serial.print(name);
  Serial.print("Len = "); Serial.print(n); Serial.println(";");
  Serial.println();
}

void setup() {
  Serial.begin(115200);
  delay(150);
  IrReceiver.begin(IR_RECV_PIN, DISABLE_LED_FEEDBACK);
  Serial.println(F("IR capture ready on D2."));
  Serial.println(F("Tap a remote button once; wait ~1 s between presses."));
}

void loop() {
  if (!IrReceiver.decode()) return;

  // rawlen = number of MARK/SPACE entries in the current frame
  auto *raw = IrReceiver.decodedIRData.rawDataPtr;
  uint16_t len = raw ? raw->rawlen : 0;

  if (len >= 20 && len <= RAW_BUFFER_LENGTH) {
    // Store compensated ticks into tickBuf[]
    IrReceiver.compensateAndStoreIRResultInArray(tickBuf);

    // Short summary (protocol / bits / gap / duration)
    IrReceiver.printIRResultShort(&Serial);
    Serial.println();

    // Paste-ready array in microseconds
    printUSArray("rawCaptured", tickBuf, len);
  }

  IrReceiver.resume();
  delay(120); // small debounce to avoid printing intra-press repeats
}

Try to augment the gap as well:

#define RAW_BUFFER_LENGTH 450   
#define RECORD_GAP_MICROS 20000