아두이노에서 ESP8266 모듈을 통해 웹사이트에 접속하는 예
아두이노 보드가 ESP8266모듈을 웹클라이언트로 이용하는 예제를 작성해보려고 한다
아두이노 IDE의 시리얼 모니터를 이용하면 개발자의 PC에서 아두이노 보드와 시리얼통신을 통해 데이터를 전달하거나 수신하여 화면에 출력해볼 수 있다. 이 방법은 개발자가 아두이노 프로그램을 테스트하거나 디버깅 작업을 할 때 매우 유용하다. 여기서는 아두이노측에서 메시지를 시리얼 통신 (SoftwareSerial 라이브러리 사용) 으로 ESP8266 모듈에 전달하고 ESP8266 모듈에서는 WiFi 네트워크를 이용하여 웹사이트에 접속하여 응답 메시지를 받아서 다시 아두이노측으로 전달하고 아두이노측에서는 ESP8266으로부터 전달받은 문자열을 하드웨어 시리얼을 통해 PC에 전달한다.
PC의 COM 포트에 전달되는 데이터는 Arduino IDE의 시리얼 모니터를 사용하여 확인할 수 있다
ESP8266 모듈의 펌웨어 개발환경 구성은 이 링크를 눌러 확인하세요
통신 연결 개요
테스트 환경
Windows 10
아두이노 UNO
SoftwareSerial 라이브러리
ESP8266 (ESP-01)
아두이노와 ESP8266 모듈간의 SoftwareSerial 통신을 위한 연결
아래 그림과 같이 아두이노와 ESP8266 모듈을 연결하고 아두이노는 USB 케이블을 이용하여 개발자 PC와 연결한다
ESP8266의 Rx는 3.3v 입력을 요구하므로 아래 그림처럼 아두이노의 Tx측에서 출력되는 전압 5v을 1K옴, 2K옴 저항을 이용하여 전압을 분배하면 3.3v를 얻을 수 있다. 2K옴 저항 1개 대신에 1k옴 2개를 직렬연결하여 사용해도 된다. 필자는 실수로 10K옴을 사용했다가 전혀 통신이 안되어서 오랜 시간을 소비하면서 테스트하다가 결국 알게 되었다. 10K옴 3개를 사용하여 전압은 3.3v로 분배할 수 있었지만 전류량이 적어져서 신호가 전달되지 않았다고 생각하게 되었다
아래의 코드를 아두이노 IDE에서 작성하여 업로드한다
참고로, 아래 코드에서 사용된 아두이노의 2, 3번 핀은 아두이노 입장에서 각각 Rx(수신), Tx(송신)기능으로 설정한 것이므로 아두이노의 Rx는 ESP8266모듈의 Tx와, 아두이노의 Tx는 ESP8266 모듈의 Rx 와 연결해야 한다. 반드시 2,3번핀을 사용해야 하는 것이 아니라 위의 그림처럼 연결했다면 소스코드에서 해당 핀을 송수신 핀으로 설정하면 된다
아두이노 ESP8266
Rx(2번핀) <----> Tx
Tx(3번핀) <----> Rx
아두이노측 코드
10초에 한번씩 접속할 웹서버의 IP주소를 ESP8266 모듈측으로 전송한다
아두이노의 하드웨어 시리얼(Rx, Tx)핀은 디버깅을 위해 데이터를 화면에 출력하는 용도로 사용하고 있기 때문에 아두이노와 ESP8266간의 통신에는 SoftwareSerial 라이브러리를 사용했다. 위의 그림과 같이 연결했다면 아두이노의 2,3번핀은 소프트웨어 시리얼 통신용으로 다음과 같이 설정해야 한다
아두이노 2번핀 : Rx
아두이노 3번핀 : Tx
#include <SoftwareSerial.h> SoftwareSerial Serial2(2,3); void setup() { Serial.begin(9600); delay(100); Serial2.begin(9600); delay(100); } void loop() { Serial2.println("192.168.2.6"); Serial2.flush(); delay(20); while( Serial2.available() ){ Serial.println( Serial2.readStringUntil('\n')); } delay(10000); }
ESP8266 모듈측 펌웨어
Arduino IDE를 이용한 ESP8266 펌웨어 개발환경 구성을 참조하여 다음과 같이 펌웨어를 작성한다.
setup() 에서는 WiFi 네트워크에 접속하고, loop()에서는 아두이노측에서 전달되는 IP 주소를 수신하여 해당 웹서버에 전달하고 그 결과로 웹서버의 응답을 수신하여 다시 시리얼통신 출력핀을 통해 아두이노측으로 전달한다.
ESP8266에서는 하드웨어 시리얼 통신을 이용했으므로 Rx, Tx 핀을 통해 입출력이 수행된다
WiFi 네트워크를 이용하여 http://192.168.2.6:8080/showTime.jsp 에 접속하고 그 응답을 수신하고 시리얼통신을 이용하여 아두이노측으로 전송하는 예
// ESP8266 펌웨어 예제 #include <ESP8266WiFi.h> const char* ssid = "duniv_class2"; const char* password = "duniv2016"; char* host = "192.168.2.6"; const char* streamId = "...................."; const char* privateKey = "...................."; void setup() { Serial.begin(9600); delay(1000); // We start by connecting to a WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); delay(5000); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } int value = 0; void loop() { String targetIP = ""; while(Serial.available()){ targetIP = Serial.readStringUntil('\n'); } /* if(targetIP=="") { Serial.println("There is no input from Arduino"); String str(host); targetIP = str; }*/ if(targetIP=="") return; Serial.print("connecting to "); Serial.println(targetIP); char serverip[targetIP.length()+1]; targetIP.toCharArray(serverip, targetIP.length()+1); // Use WiFiClient class to create TCP connections WiFiClient client; const int httpPort = 8080; if (!client.connect(serverip, httpPort)) { Serial.println("connection failed"); return; } Serial.println("Webserver connect OK!"); // We now create a URI for the request String url = "/showTime.jsp"; /* String url = "/input/"; url += streamId; url += "?private_key="; url += privateKey; url += "&value="; url += value; (*/ Serial.print("Requesting URL: "); Serial.println(url); // This will send the request to the server client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); unsigned long timeout = millis(); while (client.available() == 0) { if (millis() - timeout > 5000) { Serial.println(">>> Client Timeout !"); client.stop(); return; } } while(!client.available()){ delay(100); } // Read all the lines of the reply from server and print them to Serial while(client.available()){ String line = client.readStringUntil('\r'); Serial.print(line); if(line.indexOf("</html>")!=-1) { Serial.println(); Serial.println("---------------------------------------"); } } Serial.println(); Serial.println("closing connection"); }
위의 코드를 정상적으로 실행되도록 하는 과정에서 시간이 많이 소비되었는데 많은 테스트를 통해 찾다보니 문자열 변환하는 부분에서 문제가 있었다. 아두이노측에서 ESP8266 측으로 전달한 IP 주소가 String 형인데 WiFiClient.connect()에서는 char * 를 요구하므로 적절한 형변환이 필요한데 특히, 아래처럼 +1 이 필요했다
char serverip [String.length() +1 ];
String.toCharArray( serverip, String.length()+1 )