요즘 여름이 한창이다. 올해는 상당히 더운 여름인 것 같다. 그래서 집에 있을때는 에어컨을 항상 켜놓고 생활을 하고 있다.

하지만, 저녁에 퇴근을 해서 집에 가면 집이 너무 뜨거운 상태이다. 바로 에어컨을 킨다고 해도 에어컨 바람이 나오는 곳만 금방 시원해지고, 집 전체가 시원해지려면 시간이 좀 걸린다.

그래서 집에 도착하기전에 미리 에어컨을 켜놔서 시원한 집에 들어 갈수 있도록 해보려고 한다. 그리고 간혹 에어컨을 켜놓고 나갈 경우도 있어 밖에서 에어컨을 제어할 수 있다면 굉장히 편리 할 것이다.

에어컨은 리모컨으로 제어가 가능하기 때문에 적외선 통신을 이용하면 에어컨을 제어할 수 있다. 아두이노를 이용해서 적외선 통신을 구현하고, IoT 클라우드 서비스인 Thing+를 이용해서 제어가 될 수 있도록 해보려고 한다.


적외선 통신에 대한 내용은 아래 글을 참고하길 바란다.

2016/08/04 - [IT / Development/Electronic & Circuits] - 적외선 통신을 알아보자.

Thing+ 는 Daliworks社에서 서비스를 하는 IoT 클라우드 서비스이다. Thing+ 의 자세한 설명은 아래 URL에서 확인해 보자.

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


우리는 에어컨 리모컨이 어떤 형태로 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 라이브러리 추가..." 클릭하여 다운 라이브러리를 선택하여 라이브러리를 추가한다.


에어컨 IR Code 해킹하기

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

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

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

#define RAWBUF 101

#define RAWBUF 230

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

해킹된 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 코드를 해킹하자.

<에어컨 On 코드>

<에어컨 Off 코드>

위 사진이 에어컨의 On/Off 코드이다. 두개의 코드를 보면 rawData[87]과 rawData[215]의 값만 다른 것을 확인할 수 있다. Send할 때 이 값만 바꿔서 Sned하면 On/Off가 가능할 것이다.


IR Code 검증

만약 바로옆에 에어컨이 있었으면 에어컨을 상태로 검증을 해보겠지만, 이것을 만들때 집에서 한것이 아니라 에어컨을 제어해볼 수 없었다. 그래서 아두이노 2개를 이용해서 IR code가 정상적으로 Send 되는지 확인해 보았다. 

위 사진과 같이 구성을 하고 왼쪽 보드에 "IRsendRawDemo" 펌웨어를 넣고 위에서 얻은 IR코드를 Send하고 오른쪽 보드에는  "IRrecvDumpV2" 코드를 넣고 테스트를 진행했다. 정상적으로 코드가 출력되어 입력되는 것을 확인했다.

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


하드웨어 구현

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

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

뭐 이렇게 구성해도 된다는 말이다.



구현 준비하기

우선 구현하기 전에 IR을 send 하는 것을 알기 전에 SHT11에서 온/습도 값을 읽는 것과 Thing+를 사용하는 법을 알아야 한다.


SHT11에서 온/습도 값 읽기

SHT11에서 온/습도 값을 읽는 것은 아래 URL에서 라이브러리를 다운받아 사용하면 된다.

https://github.com/practicalarduino/SHT1x

기본 예제가 있기 때문에 너무 간단히 구현이 가능하다. 아래코드는 이 라이브러리에서 지원하는 기본 예제 코드이다.아주 간단하다. 그래서 별도의 설명은 하지 않겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
 * 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);
}
cs


Thing+ 사용하기

Thing+도 크게 어려움 없이 사용 할수 있다. 우선 기본적인 사용법은 아래 URL에서 자세하게 설명되어 있다.

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

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

기본적으로 API키를 받고 게이트웨이 등록하고 센서를 등록 해야 사용 할수 있다. 아두이노 코드 또한 기본 예제가 있기 때문에 기본예제를 참고하면 간단히 구현이 가능하다. 구체적인건 시간이 좀 되면 추후에 설명 하겠다.


최종 구현 하기

위의 준비단계가 완료 되면 구현만 하면된다. 그래서 최종 결과로 아래와 같이 구현을 했다. 아두이노는 주기적으로 Thing+ 서버에 온/습도 센서 데이터를 전송하고, Thing+ 대시보드에서 powerSwitch를 On/Off 를 해서 에어컨 제어가 가능해 졌다. 

코드는 아래와 같다. 코드의 자세한 설명은 주석으로 대체 하겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//기본 라이브러리
#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,1400650,1100650,1100650,400600,450600,450600,1100600,400
                        600,450600,1150600,1150600,450550,1150550,450550,450550,1200
                        550,1150600,450550,1200550,1150550,450550,450600,1150550,500
                        550,450550,1200550,450550,450550,450550,500550,450550,500
                        550,450550,450550,450550,450550,450550,450550,450550,450
                        550,450550,450550,500550,1150600,450550,450550,1150550,450
                        550,450550,1200550,1150600,450550,450600,450550,450550,450
                        550,450550,1150550,450550,1150550,500550,450550,500550,450
                        550,500550,450550,450600,450550,1200550,450550,500550,450
                        550,450600,450550,450600,450550,450600,450550,450600,450
                        550,450550,500550,450550,500550,450550,450600,450550,450
                        600,450550,1200550,450550,500550,450550,450600,450550,450
                        600,450550,450600,450550,1200550,450550,450600,450550,450
                        600,450550,450550,1150550,1200550,1200550,450550,450600,1150
                        550,500550};
                        
//Thing+에 접속하기 위한 정보. 게이트웨이 등록 과정에서 아래 정보를 얻음. 
//본인의 APIKEY와 센서ID를 사용해야함.
//////////////////////////////////////////////////////////////////
byte mac[6= {0x900xA20xDA0x100x520xBA};         // 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();
}
cs


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

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


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

참고하자.


설치 & 동작

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

안타깝게 동작 중인 상태를 캡쳐한 것은 없다. 에어컨을 켜게 되면 온도가 낮아지는 것을 보고 에어컨이 켜진것을 확인할 수 있다. 실제로 문제 없이 아주 잘 동작을 한다.

+ Recent posts