Skip to content

Instantly share code, notes, and snippets.

@angrammenos97
Created September 23, 2024 19:44
Show Gist options
  • Select an option

  • Save angrammenos97/237de1774637282f24202451d0b62c0f to your computer and use it in GitHub Desktop.

Select an option

Save angrammenos97/237de1774637282f24202451d0b62c0f to your computer and use it in GitHub Desktop.
Smart Air Condition (AC) control with ESP32 microcontroller

Smart AC Control with ESP32-C3

This tutorial explains creating an intelligent AC controller using an ESP32-C3 microcontroller and an IR LED. We'll use the IRremoteESP8266 library for IR communication and the SinricPro library for integrating with smart home platforms.

Hardware Requirements

  • ESP32-C3 microcontroller
  • IR LED
  • NPN transistor (e.g., 2N2222 or BC547)
  • 1kΩ resistor
  • Breadboard and jumper wires

Note

I used an ESP32-C3 Mini and an 2N2222A tranzistor.

Software Requirements

  • Arduino IDE
  • IRremoteESP8266 library
  • SinricPro library

Circuit Connection

  1. Connect the 1kΩ resistor from GPIO 4 of the ESP32-C3 to the base of the NPN transistor.
  2. Connect the emitter of the NPN transistor to GND.
  3. Connect the IR LED's cathode (shorter leg) to the collector of the NPN transistor.
  4. Connect the IR LED's anode (longer leg) to the 3.3V pin of the ESP32-C3.

This configuration allows the transistor to act as a switch, providing more current to the IR LED when activated.

Step 1: Install Required Libraries

  1. Open Arduino IDE
  2. Go to Sketch > Include Library > Manage Libraries
  3. Search for and install:
    • IRremoteESP8266
    • SinricPro

Install the additional ArduinoJson and WebSockets libraries requested for the SinricPro library.

Also, make sure that the appropriate board is installed and selected. To do so:

  1. Go to Tools > Board: > Boards Managers.
  2. Search for and install esp32 by Espressif.
  3. Choose Tools > Board: > ESP32C3 Dev Module and the correct Port.

Warning

I advise you to install the version 2.0.17, as newer versions produce error during IRremoteESP8266 library compilation.

Step 2: Find the AC Protocol

To find which protocol the AC listens to, we use one of the IRremoteESP8266 example sketches, which goes through all the types.

  1. Open the sketch File > Examples > IRremoteESP8266 > CommonAcControl
  2. Verify and Upload
  3. Point the IR towards the AC
  4. Open the serial monitor from Tools > Serial Monitor
  5. Once the AC accepts the command (Turn On/Off), observe on the serial monitor which protocol triggers it

Note

For example, mine was Coolix protocol.

Tip

If you have a phone that supports OTG, download the "Serial USB Terminal" from the Play Store and connect your phone with the ESP for a portable serial monitor.

Step 3: Set Up the SinricPro Account

  1. Go to SinricPro and create an account
  2. Create a new device of type "AC Unit"
  3. Note down the Device ID and App Key

Step 3: Code Implementation

Create a new sketch in Arduino IDE and paste the following code:

#define ENABLE_DEBUG

#ifdef ENABLE_DEBUG
  #define DEBUG_ESP_PORT Serial
  #define NODEBUG_WEBSOCKETS
  #define NDEBUG
#endif 

#include <Arduino.h>
#if defined(ESP8266)
  #include <ESP8266WiFi.h>
#elif defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
  #include <WiFi.h>
#endif

#include <IRremoteESP8266.h>
#include <IRsend.h>

#include "SinricPro.h"
#include "SinricProWindowAC.h"

#define BAUD_RATE         115200  // Change baudrate to your need

// IR LED pin
const uint16_t kIrLed = 4;

// WIFI parameters
#define WIFI_SSID         "YOUR_WIFI_SSID"    
#define WIFI_PASS         "YOUR_WIFI_PASSWORD"

// Sinric Pro parameters
#define APP_KEY           "YOUR_APP_KEY_HERE"      // Should look like "de0bxxxx-1x3x-4x3x-ax2x-5dabxxxxxxxx"
#define APP_SECRET        "YOUR_APP_SECRET_HERE"   // Should look like "5f36xxxx-x3x7-4x3x-xexe-e86724a9xxxx-4c4axxxx-3x3x-x5xe-x9x3-333d65xxxxxx"
#define ACUNIT_ID         "YOUR_DEVICE_ID_HERE"    // Should look like "5dc1564130xxxxxxxxxxxxxx"

// IR parameters and variables
//replace with the actual ac model
#include <ir_Coolix.h>  //replace with the actual ac model

#define AUTO_MODE kCoolixAuto
#define COOL_MODE kCoolixCool
#define DRY_MODE kCoolixDry
#define HEAT_MODE kCoolixHeat
#define FAN_MODE kCoolixFan

#define FAN_AUTO kCoolixFanAuto
#define FAN_MIN kCoolixFanMin
#define FAN_MED kCoolixFanMed
#define FAN_HI kCoolixFanMax

IRCoolixAC ac(kIrLed);

// AC state
float globalTemperature = 25.0;
bool globalPowerState = false;
int globalFanSpeed = 1;
String globalMode = "COOL";
bool new_request = false;

// Functions to handle web requests
bool onPowerState(const String &deviceId, bool &state) {
  Serial.printf("Thermostat %s turned %s\r\n", deviceId.c_str(), state?"on":"off");
  globalPowerState = state; 
  new_request = true;
  return true; // request handled properly
}

bool onTargetTemperature(const String &deviceId, float &temperature) {
  Serial.printf("Thermostat %s set temperature to %f\r\n", deviceId.c_str(), temperature);
  globalTemperature = temperature;
  new_request = true;
  return true;
}

bool onAdjustTargetTemperature(const String & deviceId, float &temperatureDelta) {
  globalTemperature += temperatureDelta;  // calculate absolut temperature
  Serial.printf("Thermostat %s changed temperature about %f to %f", deviceId.c_str(), temperatureDelta, globalTemperature);
  temperatureDelta = globalTemperature; // return absolut temperature
  new_request = true;
  return true;
}

bool onThermostatMode(const String &deviceId, String &mode) {
  Serial.printf("Thermostat %s set to mode %s\r\n", deviceId.c_str(), mode.c_str());
  globalMode = mode;
  new_request = true;
  return true;
}

bool onRangeValue(const String &deviceId, int &rangeValue) {
  Serial.printf("Fan speed set to %d\r\n", rangeValue);
  globalFanSpeed = rangeValue;
  new_request = true;
  return true;
}

bool onAdjustRangeValue(const String &deviceId, int &valueDelta) {
  globalFanSpeed += valueDelta;
  Serial.printf("Fan speed changed about %d to %d\r\n", valueDelta, globalFanSpeed);
  valueDelta = globalFanSpeed;
  new_request = true;
  return true;
}

// Function to control AC with IR LED
void send_command() {
  if (globalPowerState) { // set state
    ac.on();

    ac.setTemp((uint8_t)globalTemperature); // set temperature 

    if (globalMode == "AUTO") { // set operation
      ac.setMode(AUTO_MODE);
      ac.setFan(FAN_AUTO);
      globalFanSpeed = 0;
    } else if (globalMode == "COOL") {
      ac.setMode(COOL_MODE);
    // } else if (globalMode == "ECO") {
    //   ac.setMode(DRY_MODE);
    } else if (globalMode == "HEAT") {
      ac.setMode(HEAT_MODE);
    } else if (globalMode == "ECO") {
      ac.setMode(FAN_MODE);
    }

    if (globalMode != "AUTO") { // set fan speed
      if (globalFanSpeed == 0) {
        ac.setFan(FAN_AUTO);
      } else if (globalFanSpeed == 1) {
        ac.setFan(FAN_MIN);
      } else if (globalFanSpeed == 2) {
        ac.setFan(FAN_MED);
      } else if (globalFanSpeed == 3) {
        ac.setFan(FAN_HI);
      }
    }
  } else {
    ac.off();
  }

  ac.send();  // transmit IR signal
}

// Functions to setup WIFI and Sinric Pro
void setupWiFi() {
  Serial.printf("\r\n[Wifi]: Connecting");

  #if defined(ESP8266)
    WiFi.setSleepMode(WIFI_NONE_SLEEP); 
    WiFi.setAutoReconnect(true);
  #elif defined(ESP32)
    WiFi.setSleep(false); 
    WiFi.setAutoReconnect(true);
  #endif

  WiFi.begin(WIFI_SSID, WIFI_PASS);  

  while (WiFi.status() != WL_CONNECTED) {
    Serial.printf(".");
    delay(250);
  }
  IPAddress localIP = WiFi.localIP();
  Serial.printf("connected!\r\n[WiFi]: IP-Address is %d.%d.%d.%d\r\n", localIP[0], localIP[1], localIP[2], localIP[3]);
}

void setupSinricPro() {
  SinricProWindowAC &myAcUnit = SinricPro[ACUNIT_ID];
  myAcUnit.onPowerState(onPowerState);
  myAcUnit.onTargetTemperature(onTargetTemperature);
  myAcUnit.onAdjustTargetTemperature(onAdjustTargetTemperature);
  myAcUnit.onThermostatMode(onThermostatMode);
  myAcUnit.onRangeValue(onRangeValue);
  myAcUnit.onAdjustRangeValue(onAdjustRangeValue);

  // setup SinricPro
  SinricPro.onConnected([](){ Serial.printf("Connected to SinricPro\r\n"); }); 
  SinricPro.onDisconnected([](){ Serial.printf("Disconnected from SinricPro\r\n"); });
  SinricPro.begin(APP_KEY, APP_SECRET);
}

// Arduino functions
void setup() {
  Serial.begin(BAUD_RATE); Serial.printf("\r\n\r\n");
  setupWiFi();
  setupSinricPro();
  ac.begin();
  delay(1000);
}

void loop() {
  SinricPro.handle();
  if (new_request) {
    send_command();
    new_request = false;
  }
}

Step 4: Configure the Code

Replace the following placeholders in the code:

  • YOUR_WIFI_SSID: Your WiFi network name
  • YOUR_WIFI_PASSWORD: Your WiFi password
  • YOUR_APP_KEY_HERE: Your SinricPro App Key
  • YOUR_APP_SECRET_HERE: Your SinricPro App Secret
  • YOUR_DEVICE_ID_HERE: Your SinricPro Device ID

Also, modify according to your protocol with the following:

  • AUTO_MODE
  • COOL_MODE
  • DRY_MODE
  • HEAT_MODE
  • FAN_MODE
  • FAN_AUTO
  • FAN_MIN
  • FAN_MED
  • FAN_HI
  • IRCoolixAC

Step 5: Upload and Test

  1. Connect your ESP32-C3 to your computer
  2. Select the correct board and port in Arduino IDE
  3. Upload the code to your ESP32-C3
  4. Open the Serial Monitor to check for a successful connection to WiFi and SinricPro

Step 6: Control Your AC

You can now control your AC using:

  • SinricPro mobile app
  • Voice commands through Alexa or Google Home (after setting up the integration in SinricPro)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment