brunch

You can make anything
by writing

C.S.Lewis

by 시류아 Jan 11. 2021

ESP8266으로 WOL 패킷
전송 장치 만들기+안드앱

ESP8266으로 WOL 신호 전송장치 + 제어용 안드로이드 앱 만들기

얼마 전, 집에서 사용하고 있던 무선 환경도 Wi-Fi 6로 업그레이드하면서 넷기어 공유기로 메인 공유기를 변경했습니다. 이후 불편한 점 중 하나가 바로 WOL(Wake On Lan) 신호를 전혀 보낼 수 없을뿐더러 브로드캐스트(255.255.255.255)도 보낼 수 없도록 막혀있습니다.


이를 해결하기 위해 이전에 사용하던 ASUS 공유기를 유선 AP모드로 연결해서 WOL 신호를 대신 보낼 수 있도록 구성해두었는데.. 이게 ASUS에서 제공하고 있는 공식 앱으로 WOL 신호를 보내는 과정이 절차가 많을뿐더러.. AP모드에서 신호를 보내는 속도가 꽤나 오래 걸린다는 단점이 있었습니다.


어떻게 하면 조금 더 빠르고 편하게 신호를 보낼 수 있을까? 조금 생각을 해보니까.. 요즘 아두이노 등 IoT 보드에서 무선 칩셋으로 많이 사용하고 있는 ESP8266으로 충분히 WOL 매직 패킷을 보낼 수 있더라고요? 그래서 ESP8266을 사용하고 있으며, 5천 원 이하의 저렴한 가격에 구할 수 있는 NodeMCU V3 가지고 간단하게 한 번 만들어봤습니다.


아, 참고로 NodeMCU에는 칩셋에 따라 두 가지 종류로 나뉘는데.. 둘 다 사용에 있어서는 똑같기 때문에 어떤 걸 사용해도 상관없습니다.



동작 원리

동작 원리를 정리하면 다음과 같습니다.   

스마트폰에서 신호 전달을 목적으로 만든 애플리케이션으로 NodeMCU에서 돌아가는 웹서버(Web Server)로 HTTP 접속

웹서버에 접속하며 들어온 파라미터를 바탕으로 NodeMCU에서 NAS를 비롯한 지원 하드웨어로 WOL 매직 패킷 전송

이후 처리 결과에 대해서 JSON으로 반환하여 스마트폰 애플리케이션에 Toast로 표시.


간단하게 말해서, NodeMCU에 간단한 웹서버를 구현하고, 스마트폰 등 외부에서 접속하면 들어오는 파라미터를 바탕으로 WOL 신호를 보내고 결과 값을 리턴해주는 구조입니다.



ESP8266 작업 환경 구성

NodeMCU를 비롯한 ESP8266 관련 보드를 개발하기 위해서는 드라이버 설치 및 아두이노 IDE에 ESP8266 관련 보드 정보를 추가해줘야 됩니다.


아두이노 IDE에 ESP8266 관련 정보 추가는 "파일 > 환경설정"에 들어가서 추가적인 보드 매니저 URLs에 ESP8266 관련 주소를 추가해줍니다.

http://arduino.esp8266.com/stable/package_esp8266com_index.json


이후 "툴 > 보드 > 보드 매니저"로 가서 ESP를 검색하면 올라오는 ESP8266을 설치하는 것으로 간편하게 보드 정보 추가가 끝납니다.


정상적으로 문제없이 설치가 완료되었으면 "툴 > 보드"에서 ESP8266 Boards를 확인하실 수 있습니다. NodeMCU를 찾아서 선택하면 모든 작업 환경 설정은 끝났습니다.


추가사항

NodeMCU 같은 경우, 모델에 따라서 드라이버가 차이 있습니다. 아래의 드라이버 중에서 해당사항이 있는 드라이버를 설치하면 정상적으로 보드가 인식됩니다.

CH34x Windows Driver - [LINK]

CP210x Windows Driver - [LINK]


여담으로 많은 곳에서 사용되고있는 드라이버이기 때문에 둘 다 설치하셔도 무관합니다.



ESP8266 Web Server + WOL 구현

ESP8266과 아두이노(본 글에서는 NodeMCU)로 웹서버와 WoL을 구현하기 위해서는 다음과 같은 라이브러리가 필요로 하고 있습니다.


ESP8266 관련 라이브러리는 보드 관련 정보를 다운로드하면서 같이 하여지며, 추가적으로 사용되는 라이브러리 관련해서는 아래의 링크에서 다운로드할 수 있습니다.

WakeOnLan - [LINK]

base64 - [LINK]


초기 설계 상에서는 AES 암호화로 쉽게 알아볼 수 없도록 파라미터 정보를 숨겨버리려고 했으나.. 몇 가지 문제점으로 BASE64로 감추는 수준에서 정리했습니다. 작업하면서 발견한 문제는 다음과 같고.. 차후에 시간 있을 때 개선하려고 합니다.

파라미터 크기가 너무 커지면 디코딩 과정에서 재부팅되는 문제

AES 처리 속도가 경우에 따라서는 심각하게 오래 걸림

안드로이드에서 인코딩한 결과 값과 구현한 웹서버에서 디코딩한 결과 값이 간혹 가다가 크게 차이 남


NodeMCU에서 설정으로 사용할 항목들입니다.   

WIFISSID → 사용 중인 Wi-Fi 이름

WIFIPASS → Wi-Fi 비밀번호

CONSOLE → 시리얼 모니터링 유무, 모니터링하려면 true로 변경

BANDRATE → 시리얼 모니터링 시 Bandrate

WEBPORT → 웹서버 포트 정보, 필요에 따라 변경

WEBREDIRECT → 정해진 주소 이외에 접근하는 경우 리다이렉트 시켜버리는 주소

WEBKEY → AES 암호화 구현의 잔재물.. 지금은 구분자로 MAC 주소와 함께 묶어서 감출 때 사용

TOKEN_MAX_SIZE → BASE64로 인코딩 된 파라미터를 받아들일 수 있는 크기, 최대 256자


전역 변수는 별 것 없습니다. 웹서버, UDP, WOL을 제외하면 리다이렉트 주소만 있습니다.


setup과 loop는 심플합니다. setup에서 와이파이를 연결하고 WOL관련 설정을 한 뒤 웹서버를 정의하고 실행시키며, loop에서 웹서버 클라이언트 접속 처리 및 시리얼 모니터링 관련 처리를 진행합니다.


setup에서 사용된 WiFiConnection 함수는 와이파이 연결을 진행합니다. 5분 동안 와이파이 연결을 기다리고 있으며, 이후 연결이 되지 않는다면 ESP.restart 함수를 통해서 소프트웨어적으로 재부팅을 진행한 뒤 다시 와이파이 연결을 시도합니다.


마찬가지로 setup에서 사용된 WebPage 함수는 ESP-WOL 이외의 모든 경로로 접속한 경우에 대해서 리다이렉트 처리합니다.


그리고 ESP-WOL 경로로 접속한 경우에 대해서 파라미터를 전달받아서 Base64로 디코딩 처리하고 포함되어있는 KEY 값이 일치하는 경우, 같이 온 MAC 주소로 WOL 패킷을 발송, 이후 JSON으로 작성된 결과를 피드백해줍니다.


WebPage에서 정상적으로 접속될 경우 사용되는 getValue 함수는 스택오버플로우에서 찾은 코드로 split이 없는 아두이노에서 정해진 문자를 기준으로 문자열을 잘라서 값을 리턴해주는 함수입니다.


loop에 있는 SerialEncode 함수는 시리얼로 값을 입력하면 Base64로 인코딩해서 피드백해주는 함수입니다. 웹서버 동작 테스트 목적으로 만들어둔 함수로 없어도 사용에는 지장이 없습니다.



아두이노 전체 코드보기   

[LINK]


License

MIT ⓒ SiRyuA (HKB)




안드로이드 앱 구현

이제 안드로이드에서 사용할 앱을 만들어야겠지요? 코틀린으로 구현하는 것이 조금 더 낫겠지만.. 익숙하지 않은 언어로 힘들게 작업하는 것보다 익숙한 언어로 금방 만들었습니다. 기능을 구현하는 데 있어서 별도의 라이브러리 추가 없이 기본적으로 제공되고 있는 것만 가지고 간단하게 구현했습니다.

구현하는 데 사용한 것   

RecyclerView - 리스트

FloatingActionButton - 추가 버튼

CustomDialog - 항목 추가 및 수정 Dialog

AlertDialog - 수정 또는 삭제 Dialog

HttpURLConnection - Request 전달

SharedPreferences - 리스트 저장 및 수정


HTTP로 WOL 요청 관련하여 몇 가지 주요 코드를 살펴보면 다음과 같습니다.


RecyclerTextAdapter.java에서 ViewHolder를 통해서 클릭 이벤트를 처리합니다. 사용자가 리스트 내의 아이템을 클릭하면, 아이템이 몇 번째 아이템인지 getAdapterPosition을 통해서 받은 뒤 MainActivity.java의 WoLSend 함수로 전달합니다.


WoLSend 함수에서는 아이템 정보를 바탕으로 WOL 관련 정보가 들어있는 ArrayList에서 해당 정보를 불러온 뒤, Base64로 인코딩 처리하고 주소를 생성해서 Http Request 처리를 담당하는 WoLSendProcessHttp 함수로 전달합니다.


HTTP로 Request를 보내는 과정에서는 안드로이드 권장에 따라 별도의 스레드로 동작하며, Base64로 인코딩 된 파라미터가 전송되고 난 이후, 결과 값을 읽어 들여서 JSON으로 반환, WoLSendProcessJson 함수로 전달합니다.


(애초에 별도의 스레드가 아니면 HttpURLConnection이 동작하지 않습니다..)


전달받은 결과 값에 따라서 성공 또는 실패 여부를 판단한 뒤 Toast로 안내합니다. Toast 안내 과정에서는 스레드 처리 관련 문제로 제대로 출력이 안되기 때문에 Looper.prepare로 다른 스레드를 생성해서 출력이 이루어집니다.


이렇게 구현된 안드로이드 앱은 다음과 같이 동작을 하고 있습니다.   

우측 하단 플로팅 버튼을 통해 아이템 추가 Dialog 출력

항목 추가 Dialog에서 입력 후 추가 버튼을 누르면 리스트에 항목 추가

리스트에 있는 아이템을 클릭하는 것으로 WOL 패킷 전송

리스트에 있는 아이템을 길게 클릭하는 것으로 수정 또는 삭제 Dialog 출력

수정 또는 삭제 Dialog에서 수정을 누를 경우 수정 Dialog 출력

수정 또는 삭제 Dialog에서 삭제를 누를 경우 항목 삭제



안드로이드 앱 전체 코드보기

[LINK]


안드로이드 앱 다운로드

[LINK]


License

MIT ⓒ SiRyuA (HKB)




동작 확인

구현이 완료되었으니, 테스트를 해봐야겠지요? 일단, 안드로이드 스튜디오(Android Studio)의 안드로이드 예뮬레이터(Android Emulator)를 통해서 항목을 추가하고 ESP8266 웹서버에 신호를 보내본 결과 정상적으로 처리되고, WOL신호를 보낸 뒤 결과를 반환하는 것을 확인했습니다.


이제 완성된 앱을 서명(Singed) 처리하고 사용 중인 스마트폰에 설치해서 실제 동작을 확인해보겠습니다.


Mission complete.



마치며

PIN 부분만 대충 절연 처리하고 방치된 NodeMCU..

다른 제조사의 공유기를 사용하거나, 기존 구성되어있던 환경에서 몇 번 클릭하고 기다리면 충분히 되는 것 가지고 정말 귀찮고 갑갑해서 간단하게 만들어봤습니다. 내부 아이피 말고도 포트 포워딩 설정 후 DDNS를 통해서 외부에서 몇 번 신호를 보내보고 테스트해봤는데.. 문제없이 잘 됩니다. 구현 과정에서 약간 걱정했던 부분인데 잘 되니까 다행입니다.


그리고 정말 오랜만에 아두이노랑 안드로이드 앱을 만져봤는데.. 아직까지 감이 죽지 않아 천만다행입니다. 나중에 여유가 조금 더 있으면 또 다른 무언가를 한 번 만들어봐야겠습니다 :)

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari