위즈네트 아카데미

TUTORIAL

튜토리얼

Home  > 튜토리얼

아두이노와 클라우드를 활용한 에어컨 제어

WIZnet Academy 2016.09.09 08:33 조회 수 : 57

지난 여름은 정말 더웠던 것 같습니다. 에어컨을 켜지 않고는 잠을 이루지 못하는 밤들이 정말 많았지요.

이번 프로젝트를 구상한 저자의 경우 저녁에 퇴근을 해서 집에 돌아와 문을 열었을 때 하루종일 쌓인 열기로 들어서자 마자 불쾌감을 느낄 수 밖에 없었습니다. 그러던 중 집에 도착전에 미리 에어컨을 켜둘 수 있고, 또 혹시나 에어컨을 채 끄지않고 외출했을 경우 외부에서도 에어컨을 끌 수 있다면 정말로 편리할 것 같다는 생각을 합니다.

 

에어컨은 리모컨으로 제어가 가능하기 때문에 적외선 통신을 이용하면 에어컨을 제어할 수 있습니다. 아두이노를 이용해서 적외선 통신을 구현하고, IoT 클라우드 서비스인 Thing+를 이용해서 제어하는 방식으로 이번 프로젝트를 구현해 보겠습니다.

arduino_air_1

이번 프로젝트를 위해서는 기본적으로 적외선 통신과 Thing+ 서비스에 대한 기본적인 내용을 알고 있어야 합니다. 하기 링크를 클릭하시면 상세한 내용 확인이 가능합니다.

 

일반적으로 에어컨 리모컨이 어떤 형태로 IR 신호를 보내는지 알 수 없기 때문에 우선 에어컨 리모컨의 IR Code를 해킹해야 합니다. 리모컨 및 에어컨의 제조사 마다 고유의 IR Code로 전송을 하는데, 이번 프로젝트에서는 아두이노와 리모컨용 IR 수신부를 이용해서 해킹을 하도록 하겠습니다.

Arduino IR Remote 라이브러리 추가

우선 Arduino IR Remote 라이브러리를 추가해야 합니다. Arduino에서는 기본적으로 "RobotIRremote" 라는 이름으로 IR Remote 라이브러리가 있지만, 아래 URL에서 다운받은 라이브러리를 사용할 예정입니다. Arduino 설치 폴더에서 "RobotIRremote" 폴더를 삭제하고, 아래 URL에서 ZIP 형태로 다운받습니다.

https://github.com/z3t0/Arduino-IRremote

Arduino IDE에서 상단 툴바의 "스케치 > 라이브러리 포함하기 > .ZIP 라이브러리 추가..." 클릭하여 다운 라이브러리를 선택하여 라이브러리를 추가합니다.

arduino_air_2

에어컨 IR 코드 해킹하기

추가한 IR Remote 라이브러리에 포함된 "IRrecvDumpV2" 예제를 이용해서 IR Code를 해킹합니다. 회로는 매우 간단하기 때문에 아래 구성 사진으로 대체합니다. IRrecvDumpV2 예제에서는 수신 핀이 pin 11이지만 여기서는 pin 7연결해서 사용했으며, 당연히 IRrecvDumpV2에서 에서 pin 7로 수정을 해서 사용합니다.

arduino_air_3

펌웨어를 업로드를 하고 동작을 시켜고 시리얼 모니터를 엽니다. 에어컨 리모컨의 버튼을 누르면 아래와 같은 형태로 메시지가 출력됩니다.

arduino_air_4

일단 메시지를 보면 에어컨 리모컨의 IR Code가 너무 긴것 같습니다. IRremoteint.h 파일을 열어 #define RAWBUF 101을 #define RAWBUF 230으로 수정해서 다시 펌웨어를 업로드 합니다.

arduino_air_5

다시 펌웨어를 업로드하고 동작을 시키면 아래와 같이 메시지가 나옵니다. 에어컨 리모컨의 IR Code는 227byte인 것을 확인 할수 있습니다. 우리집 에어컨만 이런 것이지 다른 리모컨은 데이터의 사이즈는 당연히 달라집니다.

arduino_air_6

해킹된 IRCode를 분석 할 필요는 없지만 대충 분석해 보겠습니다. "+3800, -1400" 이 부분은 leading code 입니다. 3.8ms 동안 high, 1.4ms 동안 low인 것으로, 숫자 앞에 +가 붙으면 그 시간동안 High, -가 붙으면 그 시간동안 low 입니다. 이것은 부호를 생략하고 순차대로 rawData[227] 배열에 저장이 됩니다.

여기서는 rawData[227] 배열의 값들이 필요합니다. 이 값을 그대로 Send 한다면 리모컨 동작을 그대로 구현이 가능합니다.

이제 리모컨의 전원 버튼을 눌러서 On코드와 Off 코드를 해킹해서 메모장 같은 곳에 rawData[227]값을 복사해 놓습니다. 다른 리모컨은 어떨지 모르지만, 이번 프로젝트에서 사용하는 에어컨의 리모컨은 IR 데이터를 보낼 때마다 설정 값들을 전부다 보냅니다. 설정 온도 값, 풍량, 풍향의 방향, 에어컨 모드 등등을 모두 보내서 그 값데로 에어컨이 동작을 하게됩니다. 즉 27도, 풍향 자동, 풍량 자동으로 셋팅된 리모컨에서 On을 하면 에어컨이 켜지면 27도, 풍향 자동, 풍량 자동으로 동작을 하게 됩니다. 그렇기 때문에 미리 동작시키고자 하는 에어컨의 설정들을 미리 해놓고 리모컨의 On/Off 코드를 해킹합니다.

arduino_air_9

 

arduino_air_10

위 이미지는 에어컨의 On/Off 코드로, 두개의 코드를 보면 rawData[87]과 rawData[215]의 값만 다른 것을 확인할 수 있습니다. Send할 때 이 값 만 바꿔서 Send하면 On/Off가 가능합니다.

 

IR Code 검증

본 프로젝트를 수행할 당시 사용 중인 에어컨이 위치해 있는 곳이 아닌 사무실에서 진행을 하다보니, 바로 에어컨에 대해서 코드 검증하기가 어려운 상황이었습니다. 따라서 아래와 같이 2개의 아두이노 보드를 사용하여 IR Code 가 정상으로 Send 되는지 확인해보는 작업을 진행했습니다.

arduino_air_11

위 사진과 같이 구성을 하고 왼쪽 보드에 "IRsendRawDemo" 펌웨어를 넣고 위에서 얻은 IR코드를 Send하고 오른쪽 보드에는  "IRrecvDumpV2" 코드를 넣고 테스트를 진행합니다.

IR을 send 할때는 AVR의 내부 타이머를 사용해서 출력 신호를 보냅니다. 그렇기 때문에 정해진 핀에 IR LED를 연결해야 할 수 있습니다. 이는 "IRremoteInt.h" 파일에 정의 되어 있습니다. 여기서는 아두이노 메가를 이용했기 때문에 pin 9에 연결했습니다.

arduino_air_12

하드웨어 구현

구현은 아래 사진과 같습니다. 집의 온/습도를 모니터링 하기위한 SHT11 온/습도 센서를 연결했고, 보드의 상태를 모니터링 할 LED, 에어컨을 제어할 IR LED를 구현했고, Thing+에 데이터를 전송할 Ethernet Shield 2를 스태킹 하였습니다. 위에 설명 했듯이 IR LED는 pin 9에 연결을 했습니다.

arduino_air_13

arduino_air_14

IR LED는 38Khz로 순간적으로 켜졌다 꺼졌다 하기때문에 소모되는 전류가 적은 편입니다. 그렇기 때문에 다이렉트로 MCU에 연결해도 되지만 오히려 출력이 약해질수 있습니다. 중간에 TR을 달아서 전류량을 증폭하는 형태로 구성을 할 수도 있습니다.

arduino_air_15

 

SHT11에서 온/습도 값 읽기

SHT11에서 온/습도 값을 읽는 코드는 매우 간단하며 아래 URL에서 라이브러리를 다운받아 사용하면 됩니다.

https://github.com/practicalarduino/SHT1x
/**
* ReadSHT1xValues
*
* Read temperature and humidity values from an SHT1x-series (SHT10,
* SHT11, SHT15) sensor.
*
* Copyright 2009 Jonathan Oxer <jon@oxer.com.au>
* www.practicalarduino.com
*/

#include <SHT1x.h>

// Specify data and clock connections and instantiate SHT1x object
#define dataPin 10
#define clockPin 11
SHT1x sht1x(dataPin, clockPin);

void setup()
{
Serial.begin(38400); // Open serial connection to report values to host
Serial.println("Starting up");
}

void loop()
{
float temp_c;
float temp_f;
float humidity;

// Read values from the sensor
temp_c = sht1x.readTemperatureC();
temp_f = sht1x.readTemperatureF();
humidity = sht1x.readHumidity();

// Print the values to the serial port
Serial.print("Temperature: ");
Serial.print(temp_c, DEC);
Serial.print("C / ");
Serial.print(temp_f, DEC);
Serial.print("F. Humidity: ");
Serial.print(humidity);
Serial.println("%");

delay(2000);
}

Thing+ 사용법 익히기

Thing+ 클라우드 서비스의 기본 적인 사용법은 아래 URL 에 자세하게 설명되어 있습니다. 기본적으로 API 키를 ㅂㄷ고 게이트웨이 등록과 센서 등록을 하면 사용이 가능합니다. 아두이노 코드 또한 기본 예제가 제공되고 있기 때문에 기본 예제를 활용하면 간단히 구현이 가능합니다.

http://support.thingplus.net/ko/user-guide/preparation.html

http://support.thingplus.net/ko/open-hardware/arduino-noSSL-user-guide.html

 

최종 구현 코드

아래는 최종 구현 코드입니다. 아두이노는 주기적으로 Thing+ 서버에 온/습도 센서 데이터를 전송하고, Thing+ 대시보드에서 powerSwitch를 On/Off 를 해서 에어컨 제어가 가능하도록 합니다.

코드에 대한 자세한 설명은 주석 처리하였으니, 확인해 보시면 됩니다.
//기본 라이브러리
#include <Arduino.h>
#include <SPI.h>
#include <Ethernet.h>
#include <SHT1x.h>
#include <Thingplus.h>
#include <TimeLib.h>
#include <IRremote.h>

//SHT11 센서 정의 및 생성
#define dataPin 5
#define clockPin 6
SHT1x sht1x(dataPin, clockPin);

//IRsend 생성 및 선언
IRsend irsend;
decode_results results; // Somewhere to store the results

//IR 변수 선언
int khz = 38; // 38kHz carrier frequency for the NEC protocol
unsigned int irLen = 227;
unsigned int irCode[] = {3800,1400, 650,1100, 650,1100, 650,400, 600,450, 600,450, 600,1100, 600,400,
600,450, 600,1150, 600,1150, 600,450, 550,1150, 550,450, 550,450, 550,1200,
550,1150, 600,450, 550,1200, 550,1150, 550,450, 550,450, 600,1150, 550,500,
550,450, 550,1200, 550,450, 550,450, 550,450, 550,500, 550,450, 550,500,
550,450, 550,450, 550,450, 550,450, 550,450, 550,450, 550,450, 550,450,
550,450, 550,450, 550,500, 550,1150, 600,450, 550,450, 550,1150, 550,450,
550,450, 550,1200, 550,1150, 600,450, 550,450, 600,450, 550,450, 550,450,
550,450, 550,1150, 550,450, 550,1150, 550,500, 550,450, 550,500, 550,450,
550,500, 550,450, 550,450, 600,450, 550,1200, 550,450, 550,500, 550,450,
550,450, 600,450, 550,450, 600,450, 550,450, 600,450, 550,450, 600,450,
550,450, 550,500, 550,450, 550,500, 550,450, 550,450, 600,450, 550,450,
600,450, 550,1200, 550,450, 550,500, 550,450, 550,450, 600,450, 550,450,
600,450, 550,450, 600,450, 550,1200, 550,450, 550,450, 600,450, 550,450,
600,450, 550,450, 550,1150, 550,1200, 550,1200, 550,450, 550,450, 600,1150,
550,500, 550};

//Thing+에 접속하기 위한 정보. 게이트웨이 등록 과정에서 아래 정보를 얻음.
//본인의 APIKEY와 센서ID를 사용해야함.
//////////////////////////////////////////////////////////////////
byte mac[6] = {0x90, 0xA2, 0xDA, 0x10, 0x52, 0xBA}; // MAC ADDRESS
const char *apikey = "-_96WYVuNweM8z4M9bT4oehY4yM="; // APIKEY

const char *temperatureId = "temperature-90a2da1052ba-0"; // TEMPERATURE ID
const char *percentId = "percent-90a2da1052ba-0"; // PERCENT ID (Humidity)
const char *powerSwitchid = "powerSwitch-90a2da1052ba-0"; // IR Control ID
//////////////////////////////////////////////////////////////////

int LED_GPIO = 7; //LED Init
int reportIntervalSec = 60; //전송 주기

//온/습도 변수 선언
float temp_c;
float humidity;

static EthernetClient ethernetClient; //Ethernet Client 선언
static void _serialInit(void)
{
Serial.begin(115200); // Serial Init
while (!Serial);// wait for serial port to connect.
Serial.println("Hello Arduino!!");
}
static void _ethernetInit(void)
{
Ethernet.begin(mac); // Ethernet begin, use dhcp
Serial.print("[INFO] IP:");
Serial.println(Ethernet.localIP());
}
static void _gpioInit(void) {
pinMode(LED_GPIO, OUTPUT);
digitalWrite(LED_GPIO, HIGH); // LED off
}

//Thing+ Callback 함수. Thing+로 부터 제어신호(액츄에이터) 신호가 수신되면 아래 함수 실행
char* actuatingCallback(const char *id, const char *cmd, const char *options) {
//수신된 센서ID가 powerSwitchid이면
if (strcmp(id, powerSwitchid) == 0) {
//powerSwitchid의 값이 on이면
if (strcmp(cmd, "on") == 0) {
digitalWrite(LED_GPIO, LOW);
irCode[87] = 1150;
irCode[215] = 1200;
irsend.sendRaw(irCode, irLen, khz); //On Code Send
return (char*)"success";
}
//powerSwitchid의 값이 off이면
else if (strcmp(cmd, "off") == 0) {
digitalWrite(LED_GPIO, HIGH);
irCode[87] = 450;
irCode[215] = 450;
irsend.sendRaw(irCode, irLen, khz); //Off Code Send
return (char*)"success";
}
}
return NULL;
}
void setup() {
_serialInit();
_ethernetInit();
_gpioInit();
Thingplus.begin(ethernetClient, mac, apikey); //Thing+ 초기화
Thingplus.actuatorCallbackSet(actuatingCallback); //Thing+ Callback 함수 등록
Thingplus.connect(); //Thing+ 접속하기
}
time_t current;
time_t nextReportInterval = now();
void SensorsUpdate() {
// Read values from the sensor
temp_c = sht1x.readTemperatureC();
humidity = sht1x.readHumidity();

// Print the values to the serial port
Serial.println(now());
Serial.print("Temperature: ");
Serial.print(temp_c, DEC);
Serial.print("C / ");
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println("%");
}
void loop() {
current = now();
if (current > nextReportInterval) {
Thingplus.gatewayStatusPublish(true, reportIntervalSec * 3);
SensorsUpdate();
//Thingplus.sensorStatusPublish(temperatureId, true, reportIntervalSec * 3);
Thingplus.valuePublish(temperatureId, temp_c); //온도 값 전송
//Thingplus.sensorStatusPublish(percentId, true, reportIntervalSec * 3);
Thingplus.valuePublish(percentId, humidity); //습도 값 전송
nextReportInterval = current + reportIntervalSec;
}
Thingplus.loop();
}

위의 코드로 Thing+와 연동 되는 것을 확인할 수 있습니다. Thing+ 대시보드에 온/습도 값이 표시되는 것과, powerSwitch 를 On/Off해서 IR code가 출력 되는 것이 확인 됩니다. 아래 그림은 Thing+ 대시보드의 모습으로, 대시보드의 우측 상단의 "+" 를 클릭하면 센서나 액츄에이터를 대시보드에 추가 할 수 있습니다.

arduino_air_16

powerSwitch의 on/off 동작이 성공하면 아래와 같이 표시되고,

arduino_air_17

실패하면 아래와 같이 표시됩니다.

arduino_air_18

 

설치 & 동작

공유기 옆에 아래 사진과 같이 보드를 설치를 합니다. 설치를 한후에 Thing+ 대시보드에 접속을 해서 온/습도 값이 올라오는 것을 확인했고, powerSwitch를 on/off 로 설정해서 에어컨이 켜지고 꺼지는 것을 확인 할 수 있었습니다.

arduino_air_19