개발 관련/아두이노,IOT

무선 인터넷으로 제어하는 가습기 개발기

snoworca 2015. 9. 24. 13:55

프로젝트 코드 및 회로도는 아래 주소에서 확인하세요.

 https://github.com/ice3x2/Wifi_Humidifier



  아두이노를 취미로 시작한지 1년이 지났다. 그 이후로 수집벽이 생겼는데,  센서나 부품을 쓰지도 않으면서 알리 익스프레스를 통하여 모으는 일이다

   

 덕분에 책상 위에 온갖 센서들이 굴러다닌다. 초창기에 구입한 ESP8266 ESP-1 도 그 중에 하나인데, 사놓고 사용하지를 않아 아까워서 이번 프로젝트에 사용하게 되었다. 단, ESP8266은 80Mhz 와 메모리 32kbyte 의 뛰어난 성능을 갖고 있는데, 그 자체로 IOT 플랫폼으로 사용할 수 있다. 하지만 ESP-1은 최신 버전인 ESP-12 와 다르게 사용할 수 있는 GPIO  포트가 얼마 되지 않고 아날로그 입력을 받도록 처리하는 것도 귀찮아서 그냥 알리익스프레스에서 1달러에 구입한 Mini 또는 nano 와 호환되는 짭두이노를 연결 하였는데, 생각해보니 벤츠 SLS 에 마티즈 엔진을 얹고 달리게 하는 것과 비슷하다. ㅡ , ㅡa 



1. 삽질의 시작.

  

요새 날씨가 건조하니 비염이 심해지기 시작했다. 그래서 아래와 같이 가습기를 구입하였다. 위x프 에서 구입한 보만 미니 가습기인데, 번들로 페트병 하나가 들어있는 것이 인상적이다. 







  

  (이 글을 작성한 시점에서는) 백수에 시간부자라 소일거리로 가습기 리뷰를 블로그에 올릴 생각으로 사진을 찍어봤다. 그리고 저 작고 앙증맞은 것이 어떻게 동작 하는지에 대한 궁금증이 생겼다. 그래서 한 번 분해해 봤다. 

   


(밑 뚜껑을 따버린 모습.)


 내부는 간단해 보인다. 아무래도 전원부를 24v 정전압 아답터로 사용하기 때문인 것 같다. 배선은 예상외로 깔끔한 모습을 보여준다. 중국 공장에서 생산 되었어도 독일 회사 브랜드를 달고 출시되어서 그런지 깔끔해 보인다. 좀 더 자세히 뜯어보면, 초음파 진동자를 구동시키기 위한 주파수를 발생 시키는 메인보드가 보이며  여기여 연결된 24v 팬과 토글 스위치를 겸비한 분부량 조절기인 1.5k옴 가변 저항이 있다.  분무량 조절기의 노브를 잡고 돌리는 느낌이 중저가형 음향기기에 달려있는 조절 노브를 돌릴 때의 느낌과 비슷하다. 그리고 물 경고등과 전원등이 연결되어 있는데 Red-Green LED 로 되어있다. 마지막으로 수위 센서가 연결되어 있다. 수위 센서라고 해서 별거 없고 그냥 막대기에 물에 떠다니는 플라스틱을 끼운 형태인데, 물이 없으면 플라스틱이 막대기를 타고 아래쪽으로 내려와 스위치를 건듦으로써 on 이 되는 원리이다. 



   이 가습기는 쓸만한 디자인에 비하여 가격이 저렴하지만, 철저하게 아날로그다. 덕분에 자면서 가습기를 틀고 아침에 일어나보면 방 안이 눅눅해져 있고 가끔 분무량 조절 노브를 가장 작게 줄여도 항상 최대치로 돌아가는 팬 소리 때문에 잠을 잘 때 거슬린다. 그래서 이 녀석의 구조도 대충 알겠다 한 번 개조해보기로 하는데...



2. 부품 쑤셔 넣기.

제목 그대로 쑤셔 넣었다.

    

    우선 아래와 같이 이번 프로젝트에 사용될 부품을 준비하였다.



첫 번째로 아두이노가 필요하다. 사진상의 아두이노는 공개하지 않은 다른 프로젝트에서 사용된 것을 적출한 것으로 케이블이 제거되지 못한 상태다. 

두 번째로 WIFI 모듈인 ESP8266 이 필요한데, 사실 위에서 언급한대로 아두이노로 ESP8266 을 제어한다는 것은 오늘 운전면허증 받은 사람이 페라리를 운전하는 것과 비슷해서 굉장히 비효율적이다. ESP8266 이 저렴하기도 하지만 성능까지도 좋고 Lua 나 아두이노 부트로더를 올릴 수 있어 최근 메이커들 사이에서 새로운 IOT 플랫폼으로 주목받고 있다. 하지만 초창기 버전인 ESP-1 은 GPIO 포트가 부족하기도 하고 아날로그 제어도 해야 하므로 그냥 아두이노로 제어하도록 한다. 


  그리고 중요한 작업이 하나 있는데, 초기 상태의 ESP8266 은 깡통과 같다. 펌웨어가 올라가 있지만 꽤 구형 버전으로 올라가 있다. 

그러므로 반드시 펌웨어를 최신 버전으로 올려줘야 한다. 이 프로젝트에서는 AT 커맨드를 사용하기 위한 AT 펌웨어 v0.9.2.2 버전을 사용하였다.

펌웨어 설치 방법은 네이버 카페 아두이노 스토리 에서 쉽게 찾아볼 수 있으며,  하드카피 월드 에서도 살펴볼 수 있다.

  그 밖에 ESP8266 만을 위한 해외 포럼도 있다!! (http://www.esp8266.com/) 

  baud rate 는 9600으로 설정해야 한다. 디버깅을 위하여 RX,TX 핀을 희생하고 SoftwareSerial 을 사용하도록 하였으며 때문에 9600으로 설정한 것이다. 9600이면 초당 1.17 Kbyte 전송률을 갖고 있는데, 1메가 전송하려면 대략 14분하고 5초 걸린다. -_-ㅎㅎㅎ. 문제는 이것은 시리얼 통신의 속도지 WIFI 자체의 속도가 아니라는 것이다. 결국 통신 프로토콜을 잘못 짠다면 버퍼 오버플로우가 생길 것이다. 그 때문에 만약 큰 데이터를 주고받는다면 ESP8266 모듈의 ESP-12 버전을 사용하여 SPI 통신을 사용하도록 하는 것이 현명한 선택일지도 모르겠다. 


세 번째로 BLE 모듈인 HM-10 을 사용하기로 하였으나, 귀찮아서 제거하였다. 사실 이 녀석을 이용하여 스마트폰으로 무선 AP 와 서버 등을 설정하려고 하였으나 너무 귀찮았다. 그래서 버튼을 달고 5초 이상 누르고 있으면 WIFI 모듈이 무선 AP 모드로 동작하고 여기에 접속하여 설정할 수 있도록 하였다. 


그리고 온습도 센서인 DHT22 를 사용하는데, 이거 비추다. 생각보다 정확하지 않다. ㅠ_ㅠ 조만간 GY-21 로 바꿔서 테스트해볼 생각이다.



AMS 1117 3.3v 는 esp8266 에 3.3v 를 공급하는 데 필요한데, 타입별로 input, output, gnd 핀 위치가 다르니 주의하도록 한다. 


그 밖에 24v 750mA에서 안전하게 사용할 수 있는 NPN 트랜지스터와 (본인은 이전에 만든 프로젝트에서 적출한 TIP 120을 사용하였다.) DC to DC Step-down 모듈과 7805 이 필요하다. 24v를 바로 7805로 방열판 없이 연결할 경우 아마 터질지도 모른다. (진짜로 소리 나면서 깨진다) ESP8266 은 생각보다 에너지 소비량이 많다. 대략 알기로는 250mA 정도 된다고 들었다. 그렇기 때문에 전원부가 중요하다. 이 프로젝트에서는 이곳 에서 구매한 모듈을 사용하였는데, 가격도 2,000원 밖에 안 하고 크기도 소형이다. 이 DC to DC 컨버터에 달린 가변저항을 조절하여 6.5v 로 정확하게 맞춰주고 나서 7805를 연결하면 안정적으로 전원을 공급받을 수 있다. 7805 를 부착한 이유는 혹시 모를 사고로 24v가 아두이노에 입력되는 일이 없도록 하기 위해서다. 만약 5v 정전압 컨버터가 있다면 7805 없이 그것을 이용하는 것이 효율적인 측면에서 훨씬 좋을 것이다. 


아래는 직접 그려본 회로 배선도이다. 최근에 시간이 많아서 이런 잉여로운 짓을 할 수 있었다.



  



  부품과 회로에 대한 더 자세한 설명은 배선도 아래에 있는 Github 에 공개하였으니 참고바란다.


  자 이제 이 많은 부품을 어떻게 가습기 안에 쑤셔 넣어볼까...

 이 문제로 꽤 많이 고민했던 것 같다.

  

  우선 모든 부품을 케이블로 연결하여 가습기 안에 넣어보려고 하였다.





    위와같이 아두이노에  ESP8266 을 케이블을 연결 하였다...


  




   전원 모듈도 절연 효과를 위하여 방열 테이프로 감싸서 케이블로 연결하였다. 사진상에는 안 보이지만 7805 도 부착하였다.

   하지만, 이렇게 케이블로 연결해서 쑤셔 넣어보려고 해도 잘 들어가지 않았다. 무엇보다 공기 흐름을 방해하지 말아야 하는데, 부품과 케이블이 늘어날수록 공기 통로는 좁아지게 되어 결국 분무량도 떨어진다. ㅠㅠ

   

버틸수 없다...



  그래서 결국 가습기 외벽에 구멍을 뚫어서 컨트롤과 신호, 5v 전원 케이블을 뽑아내도록 하였다. 결국 내부에 남는 것은 TIP120 두 개와 5v 전원부이다. 그리고, 전원 LED 와 수위 경고 LED의 각 + 부분에 케이블을 연결한다. 

   


  

이렇게 구멍을 뚫어서 케이블을 빼준다.




배선 완료. 조만간 3D 프린터로 케이스를 뽑아 씌운다음에 깔끔하게 부착할 계획이다.


  


3. Software


    


  우선 가습기를 제어하기 위한 서버 프레임워크로 Node.js 를 택했다.  자바 스크립트를 이용하였기 때문에 개발하기도 쉬웠고 라즈베리 파이 위에서도 그럭저럭 괜찮은 성능으로 잘 돌아간다. 또한  npm 모듈로 제공되는 forever 를 이용하면 백그라운드에서 깔끔하게 돌아가기 때문에 가습기 제어용 서버 개발, 운영하는 데는 이보다 좋은 선택이 있을수가 없다. 그리고 웹 서버 프레임워크로 Express 를 사용하였다. 처음에는 TCP 프로토콜을 직접 제어하여 가습기와 커넥션을 유지하도록 하였는데, 개발 중간에 모두 HTTP 프로토콜로 변경시켜 버렸다. 원래 처음에는 모바일 앱을 만들고 서버에서 데이터를 중계하는 방식으로 개발할 계획이었다. 그런데, 생각해보니 이렇게 하면 PC에서 제어하지 못하고 귀찮게 스마트폰 꺼내서 앱 실행 시키고 로딩이 끝날 때 까지 기다렸다가 버튼 몇 개 누르고 다시 앱을 닫아야 한다니.... 이건 통신 거리가 무한대인 블루투스와 다름 없다고 판단하여 웹페이지로 제어 콘솔을 만들기로 하였다. 또, 통신 프로토콜도 HTTP 로 통합시켜 버렸다. 


로그 수집을 위한 DB 는 SQL 쿼리문 날리기도 귀찮고 ORM 사용하기에는 이런 미니 프로젝트에서는 오버 테크놀러지고, 몽고DB 같은 사용하기 편하지만, 사용 용도에 비해서 무거운 DB 는 일단 배제하였다. 파일로 직접 저장하자니 그것도 귀찮았다. npm 사이트를 뒤져보니 simple-node-db 라는 나름 쓸만한 녀석을 발견하게 되었다. 성능이나 뭐 그런 것은 안 바라고 오르지 간단하고 개발하기 편리 하다는 이유로 선택하였는데, 뭔가 느린감은 없지않았다. 조금은 구리지만 그래도 데이터는 잘 들어가니 걱정 없다. DB 테이블을 분, 시간, 날짜, 월, 년 단위로 만들어서 평균치를 구하여 저장하려고 계획하였는데 이 것도 귀찮아져서 무조건 분 단위로 저장하도록 하였다. 아니, 귀찮다기 보다는 어차피 내가 쓰려고 대강 만드는 것이고 여러 사람들이 이용하는 서비스가 아니므로 구조가 복잡해질수록 개발 시간을 비롯한 여러 자원이 낭비되기 때문이다. 


  웹 프런트 프레임워크는 Angular.js 와 Angular Material을 사용하였다. 원래 모바일 개발을 주로 해와서 MVVM 패턴을 위한 Angular.js 의 복잡한 구조도 그럭저럭 이해할 수 있었지만, 웹 개발을 많이 하시는 분들은 항상 학습 곡선이 크다고 말씀하신다. 나한테는 가장 빨리 개발하기 쉬운(그리고 대충해도 잘 나오는) 웹 프레임워크가 Angular.js 기 때문에 이 것을 선택하였다.  (사실 angular material 에서 제공하는 다양한 UI 컴포넌트를 척척 붙여서 빠르게 개발하기 위하여 선탁한 것이다.)


  

(이미지 출처 : http://nathanleclaire.com/blog/2014/01/04/5-smooth-angularjs-application-tips/)




  

  마지막으로 문제의 아두이노와 ESP8266. 진짜 개고생 했다. 무엇 때문에 고생을 했냐면, 첫 번째로 ESP8266 의 AT+COMMAND (명령어) 의 Response 값이 일관되지 못 하고 제대로 된 문서도 없다. 예를 들어 어떤 상황에서 에러가 발생하면 \r\nERROR 이라고 출력되는데 어떤 상황에서는 \nError 이라고 출력된다. 


  또, 소프트웨어 시리얼을 이용하기 때문에 많은 데이터를 주고받으면 버퍼 오버플로우가 발생하고 깨진 데이터들이 들어온다. UART 방식이 타이밍을 이용하여 데이터를 주고 받는 원시적인(?) 방식인 데 비하여 TCP 는 굉장히 세련되었기 때문에 엄청난 비효율이 아닐 수 없다. 그러므로 다음에도 이와 비슷한 프로젝트를 진행한다면 아두이노 연결 없이 ESP8266 을 기반으로 하여 프로젝트를 진행할 것이다. ㅠㅠ 


  진짜 심각한 문제는, Node.js + Express 서버와 ESP8266 을 이용하여 HTTP 프로토콜에서 Connection 값을 close로 하여 데이터를 주고받을 때 발생한다. 뭐, Keep-Alive 는 구현하기 빡쎄서 그냥 무조건 close로 하기로 했다.ㅎㅎ 어쨌든 이렇게 했을 때, Get 으로 요청하여 성공했을 때 연결이 바로 끊어져야 한다. 하지만 종종 연결이 끊어지지 않는 괴현상이 생긴다.

  이런 괴현상이 발생할 때, 서버와 연결을 시도하면 busy s... 라는 메시지가 출력되면서 그 뒤로는 어떤 명령어를 날려도 busy s... 메시지를 출력하는 고집 불통을 보여주는데, 해외 포럼의 어떤 분은 NPN 트랜지스터를 전원에 연결하여  busy s... 가 등장하면 하드웨어적으로 리셋시켜 버리는 방법을 제시하고 있다. (헐...) 이게 서버 문제인지 ESP 모듈의 펌웨어 문제인지 아직 파악 못 하였다.  

  이런 현상이 간혹 발생하긴 하지만 한 번 발생한다면 전원 케이블을 뽑았다 다시 껴야 한다. 이렇게 된다면 24시간 동작하며 온습도 자료를 수집하고, 일정 습도를 유지할 수 있도록 도와줘야 하는 가습기 에겐 치명적인 상황이다. 그냥 예전에 17달러 주고 구입한 CC3000 (아두이노 WIFI 쉴드) 을 사용할까 하다가, 불현듯이 좋은 아이디어가 떠올랐다.  그 것은 Get으로 요청한 상황에서 response가 왔을 때, Unlink 메시지가 일정 시간 이상 안 온다면(timeout 상황) AT+RST 명령어를 날려서 모듈을 리셋시켜 버리고 재접속하는 것이다.  그럼 모듈이 리셋이 되면서 마지막으로 연결 되었던 공유기에 자동으로 접속 시도하게 된다. 단, timeout 이 발생하여 임의로 리셋을하고 공유기에 재접속하는 시간까지 다 합쳐서 약 4~5초 정도 손해를 보게 된다. 


  이런 상황마다 중요한 것이 사용자에게 현재 동작 상태를 알려주는 것이다. 예를 들면 서버 접속 에러, 공유기 접속 에러, 인증에러 등을 알려줘야 한다. 그래서 이런 동작 상태를 LED 깜빡임 간격으로 알릴 수 있도록 하였다. 그러기 위해서는 HTTP 통신을 비동기인 듯 동기 같은 비동기로 처리하도록 해야 했다. 이것이 가능하도록 (대충)만든 HTTP 라이브러는 2kbyte 메모리 공간 중에서 대략 483byte를 잡아먹게 되었다. ㅎㄷㄷ (앞으로 최적화를 통하여 줄어들 수 있다. 물론 늘어날 수도 있다. ㅎㅎ)




github : https://github.com/ice3x2/Wifi_Humidifier