이전 포스트에서 다루었던 아두이노를 이용한 스마트 오피스나 아이언맨 피규어 리모콘 (아래 링크 참조) 은 지금 포인투랩 사무실에서 아주 잘 사용 중 인데요, 추가적으로 포인투랩의 모든 멤버들이 인터넷으로 접속하여 사무실의 기기들을 조절할 수 있다면 어떨까 싶어 이더넷 쉴드를 사용한 웹서버를 구축하기로 하였습니다. 아래 두가지는 이미 읽어보셨다는 가정 하에 이번 포스트도 시작하겠습니다.
아두이노를 사용한 에어콘 자동 조절기 만들기: http://blog.poin2.com/2015/06/아두이노-에어콘-자동-조절기/
Iron Man Figure Remote Controller: http://blog.poin2.com/2015/06/아이언맨-피규어-리모콘
위에서 쓴것 처럼, 이번 프로젝트에는 웹 서버 구축을 위해 이더넷 쉴드를 장착한 아두이노 우노가 하나 추가로 필요합니다. 아두이노 이더넷 쉴드를 사용하는 방법은 인터넷에 많이 나와있으니 이번 포스트에서는 웹 서버의 UI를 만드는 방법과 그를 통해 아두이노의 여러 GPIO와 통신하는 방법에 더 집중하도록 하겠습니다. 이번 프로젝트에서 만드는 웹 서버는 두가지 기능을 가지는데요, 하나는 “주말 모드” 로써 온도, 주변 밝기에 따라 동작하는 에어콘 자동 조절기를 켜고 끄는 기능, 그리고 다른 한가지 기능은 수동으로 에어콘을 켜고 끄는 기능입니다. 완성된 웹서버는 아래 스크린샷과 같이 생겼습니다.
포인투랩의 웹서버 주소는 공유해드릴 수 없으니 (누구나 들어와서 사무실의 에어콘을 조작한다면 큰일이겠죠 😛 ), 동작은 하지 않는 예제는 이 사이트를 참고해주세요: http://poin2.com/example/
준비물:
Arduino UNO x 1
Arduino Ethernet Shield x 1
적외선 transmitter LED x 1
점퍼 케이블 몇개 ( + 1 x 아주 긴것도 하나 있으면 좋아요)
하드웨어 연결:
이더넷 쉴드는 아두이노 우노에 바로 장착하면 되고, 나머지 하드웨어 연결은 아주 단순합니다. 이더넷 쉴드는 아두이노의 Digital Pin 10, 11, 12, 13을 사용하니 이 4개의 핀만 피해서 연결하면 됩니다. 저는 2번 핀을 “주말 모드” 인디케이터 LED로 사용하였고, 3번 핀은 “주말 모드” 리셋 신호를 다른 아두이노로 전송하도록 하였구요, 그리고 4번 핀은 리모콘으로 사용 될 LED에 연결 하였습니다. “주말 모드”는 에어콘 자동 조절기로 사용되는 아두이노의 Reset 핀에 연결해주어 3번 핀의 상태가 LOW일 때 다른 아두이노가 동작 대기 상태로 들어가도록 해주었습니다. 리셋이 제대로 동작하려면 두 아두이노의 Ground 엮시 함께 묶어주어야 합니다.
아두이노 프로그래밍:
포인투의 다음 예제를 다운받으시고 아래 가이드라인을 따라주세요. 다운받기: WebArduino.ino
1. 아두이노 우노를 사용하여 웹 서버를 구축할 때 조심할 점 중 하나는, 아두이노 우노의 메모리가 아주 작다는 것 입니다. 그래서 메모리 오버로드가 걸리지 않도록 저는 모든 print 명령어에 print(F(“어쩌구 저쩌구”))를 사용하여 html코드 부분이 플래시 메모리 영역으로 저장되도록 하였습니다.
2. MAC과 IP 주소를 먼저 잡아줍니다. 인터넷 모뎀에 이더넷 쉴드가 바로 연결되지 않는다면 공유기 설정에 들어가서 아두이노가 연결된 IP주소를 포트포워드 해주어야 인터넷을 통해서 웹 서버에 접속이 가능합니다.
// Enter a MAC address and IP address for your controller below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAE, 0xBE, 0xEE, 0xFE, 0xEC }; IPAddress ip(192, 168, 0, 45);
3. HTML 코드 처리에 필요한 buffer와 LED 등의 조작에 필요한 Digital output 핀들을 정의해줍니다.
4. setup() 함수 시작 부분에 “주말 모드” 핀은 반드시 High로 잡아주어야 합니다. 그래야 다른 아두이노가 동작 상태를 유지하겠죠?
char buffer[8]; int WeekendPin = 3; int IRledPin = 4; void setup() { pinMode(WeekendPin, OUTPUT); pinMode(IRledPin, OUTPUT); digitalWrite(WeekendPin, HIGH);
5. loop() 함수 시작 부분에서 웹 서버 UI에 들어가는 버튼들의 동작을 정해줍니다. Textfinder라는 라이브러리를 사용하면 좀 더 간단하게 구현이 가능한데요, 동작 원리는 다음과 같습니다. 웹 서버 UI에는 “주말 모드” On/Off 두개, 그리고 에어콘 On/Off 두개 이렇게 총 4개의 버튼이 있고, 각각의 버튼이 클릭 되었을 때 출력하는 “value” 값을 정해줍니다. 해당 value가 EthernetClient cl로 들어오면 그 값을 Textfinder 라이브러리로 찾아내어 각 각 value에 따른 동작을 정해주면 됩니다. 아래 코드에서 볼 수 있듯이 먼저 Textfinder로 “pinD”라는 문자열을 찾아 pinD다음의 숫자를 저장하고, 따라오는 value 값이 0이나 1이라면 주말모드를 동작시키고, 2나 3이라면 에어콘을 수동으로 조작합니다.
void loop() { EthernetClient cl = server.available(); if (cl) { TextFinder finder(cl); int type = 0; while (cl.connected()) { if (cl.available()) { //http request start with "GET / HTTP/1.1" if (finder.getString("","/", buffer, sizeof(buffer))) { if(strcmp(buffer, "POST ") == 0) { finder.find("nr"); while (finder.findUntil("pinD", "nr")) { int pin = finder.getValue(); int val = finder.getValue(); pinMode(pin, OUTPUT); if (val == 0) { digitalWrite(pin,val); digitalWrite(WeekendPin, HIGH); } else if (val == 1) { digitalWrite(pin,val); digitalWrite(WeekendPin, LOW); } else{ AC(val); } Serial.println(pin); Serial.println(val); } }
6. 각각 버튼에 대한 기능 구현을 완료했으니 웹 서버의 HTML 코드를 작성해줍니다. 1번에서 알려드린 것 처럼 F( )를 사용하여 메모리를 많이 차지하는 Text output들을 플래시 메모리에 저장합니다.
sendHeader(cl,"Poin2 Smart Office"); cl.println(F("<h1>Poin2 Lab. Office Automation System</h1>")); cl.print(F("<h2>Click below to enable/disable Weekend Mode</h2>")); //read status of Pin2 and print it if (digitalRead(2) == 1){ cl.println(F("<h3>Weekend mode is currently <FONT COLOR="007700">enabled</FONT></h3>")); } else { cl.println(F("<h3>Weekend mode is currently <FONT COLOR="0066FF">disabled</FONT></h3>")); } //create buttons and define Val cl.print("<form action='/' method='POST'><p><input type='hidden' name='pinD2'"); cl.print(" value='0'><input type='submit' value='Off' onclick="$('#lg').show();"/></form> "); //create HTML button to turn on pin 2 cl.print("<form action='/' method='POST'><input type='hidden' name='pinD2'"); cl.print(" value='1'><input type='submit' value='On' onclick="$('#lg').show();"/></form> "); cl.print(F("<img id="lg" style="display:none;" src="i.gif" alt="" /></div><br />")); cl.println(F("<h2>Click below to control Air Conditioner.</h2>")); cl.print("<form action='/' method='POST'><p><input type='hidden' name='pinD2'"); cl.print(" value='2'><input type='submit' value='Off' onclick="$('#lg2').show();"/></form> "); //create HTML button to turn on pin 4 cl.print("<form action='/' method='POST'><input type='hidden' name='pinD2'"); cl.print(" value='3'><input type='submit' value='On' onclick="$('#lg2').show();"/></form> "); cl.print(F("<img id="lg2" style="display:none;" src="i.gif" alt="" /></div>")); cl.println("</body></html>");
7. loop() 함수 구현이 끝나면 아래쪽에 HTML header에 사용되는 함수와 적외선 LED를 이용한 리모콘 함수를 뒤에 추가합니다. 저는 jquery를 이용하여 로딩화면도 이쁘게 구현해 보았는데요, 역시나 메모리 관리 차원에서 불러오는 외부 파일이나 이미지의 이름은 최대한 줄였습니다.
8. 웹 서버 구축이 끝났습니다. 아두이노 우노에 업로드하고 테스트 해보세요. 사무실이 좀 더 스마트해졌나요?
CSS파일을 수정하여 스마트폰에서도 잘 보이도록 반응형으로 만들어 주었습니다 🙂
Mac 주소는 위의 예제에 기본으로 잡혀 있는 것으로 하면되는지요?
ip를 열어줘도 신호가 나오질 않아서 고유 맥주소 때문인가 싶기도 해서 글 남깁니다.
안녕하세요? MAC 어드레스는 같은 네트워크 안에서 고유해야 하는 걸로 알고 있습니다. 요새는 이더넷 쉴드에 스티커로 붙어서 오는 것 같던데… 임의로 수정하셔도 괜찮긴 할거에요. 저는 이 프로젝트 진행 시에 공유기에 공유기가 물려있어 외부에서 접속 시 IP 열어주기가 어려웠었던 기억이 나네요.
Ccs 수정방법좀알려주세요
그리고 소스 하나하나 해석좀 부탁드리면안될까요??
하나 하나 해석 해드리기에는 양이 좀 많네요 ^^; 특히 이해 안가시는 부분 있으시면 메일로 알려주세요. yc.chang@poin2.com
혹시 웹을 좀더 이쁘게 꾸밀라고 하면 메모리 용량때문에 제한이 있을까요??
만약에 그 제한을 해결하려면 어떻게 해야하죠???
이더넷 쉴드에 SD카드를 달아서 거기다가 저장하면 되나요???
어느 정도로 이쁘게 꾸미냐에 따라 다르겠지만 용량 제한은 있겠네요 ^^; 아두이노 우노의 경우 31.5k byte의 가용한 플래시 메모리가 있습니다. 최대한 연결될 파일들의 이름을 줄이고 (image.jpg -> i.jpg 이런 식으로) 프로그래밍 하시면 sd 카드 없이도 가능할 것 같긴 해요.
에어컨의 설정온도도 웹에서 변경이 가능 한가요?
설정온도를 24.6℃, 28.2℃…등으로 말입니다.