앞에서 익힌 http를 이용해 통신하고 html로 웹에 하이퍼텍스트를 만든뒤
하이퍼텍스트 클릭을 통해서 LED를 제어하는 기능을 수행해 보겠습니다.
우선 Wemos D1 보드에 기본으로 장착되어있는 LED를 사용합니다.
Uno 보드에서는 디지털13번 이었지만 이 보드에서는 14번핀을 사용합니다
아두이노 코드의 loop 전 부분까지는
#define led 14와
LED의 pinMode 설정 정도만 추가해줍시다.
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 | #include <ESP8266WiFi.h> #define led 14 //1 const char* ssid = "와이파이이름"; const char* password = "와이파이비밀번호"; WiFiServer server(80); void setup() { pinMode(led, OUTPUT); //2 Serial.begin(115200); delay(1000); Serial.println(); WiFi.mode(WIFI_STA); Serial.println(); Serial.print(ssid); Serial.println("에 접속중"); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(100); Serial.print("."); } Serial.println(""); Serial.println("연결되었습니다."); server.begin(); Serial.println(WiFi.localIP()); } void loop() { WiFiClient client = server.available(); if(!client) return; //31 에서 WiFiClient를 통해 만든 클라이언트(client)가 서버에 연결되어 있고 읽을 수 있는 데이터가 있는 상태가 아니라면 loop로 도로 return 해서 접속할 때 까지 다른 기능을 수행하지 않습니다. String request = client.readStringUntil('\r'); //문자열 request에 client가 서버에 요청한 리퀘스트 헤더를 \r이 나올때까지 읽어서 저장합니다 if(request.indexOf("/ledoff")!=-1){ //문자열의 위치(index)를 찾는 indexof함수(찾지못하면 -1을 return 합니다.)를 이용해 request에 /ledoff라는 문자열이 있으면 14번핀을 끕니다(led를끕니다) digitalWrite(led,LOW); } else if(request.indexOf("/ledon")!=-1){ // 위와 유사합니다. digitalWrite(led,HIGH); } else{ digitalWrite(led,digitalRead(led)); //다른경우라면 led의 현상태를 읽어 유지합니다. } while(client.available()){ //그외의 정보는 이 구현에선 필요하지 않으므로 버퍼를 비우기 위해 수신된 데이터를 모두읽습니다. client.read(); } client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(); client.println("<!DOCTYPE html>"); client.println("<html>"); client.println("<head>"); client.println("<meta charset=\"UTF-8\">"); client.println("<title>LED 제어</title>"); client.println("</head>"); client.println("<body>"); client.println("<h1>LED 제어콘솔</h1>"); client.println("<a href='/ledon'>LED ON</a>"); client.println("<a href='/ledoff'>LED OFF</a>"); client.println("LED 상태: "); client.println((digitalRead(led)) ? "ON" : "OFF"); client.println("</body>"); client.println("</html>"); delay(10); } | cs |
String request = client.readStringUntil('\r');
문자열 request 속에 전송받은 데이터에서 \r이 나올 때 까지 읽어서 저장하는 코드입니다.
이 부분은 HTTP Request 형식을 보면 이해하기 좋습니다.
client.readStringUntil('\r');
이 부분에서 \r까지 읽는 이유는
우리가 텍스트를 적다가 한줄을 내리는것
html에서 br 태그를 이용해 개행하는것, 아두이노 ide에서 println을 사용하여 표시 후 개행하는것이
HTTP 헤더 에서는 \r(캐리지리턴)과 \n(라인피드)를 함께 사용해서 작동하기 때문입니다.
즉 가장먼저 \r\n (개행)이 오는 부분은 Requset Line 마지막부분 입니다.
클라이언트가 서버에 요청한 정보 중 /1.1 부분 까지 읽습니다 우리의 예시에서는
a href='/ledon 부분 때문에 하이퍼텍스트를 누를때 URL 뒤에 /ledon이 붙게 되고
그로인해 문자열 request에 /ledon 부분도 저장되게 됩니다.
그렇기 때문에 if(request.indexof("/ledon")!=-1) 부분에서 문자열에 ledon이나 ledoff를 찾게 되고
하이퍼텍스트를 누름에 따라 보드에 연결된 LED를 제어하는 기능을 구현할 수 있는 것입니다.
앞서 넘어갔던 내용인데 print가 아닌 println을 사용하는데도
client.println("Content-Type: text/html");
client.println();
와 같이 따로 한줄을 삽입하는 이유는
client.println("Content-Type: text/html"); 에서 다음 줄로 커서를 내린 것 뿐이고
client.println();를 하나 더 삽입해두어야 header 뒤에 빈 줄이 한줄 생기기 때문입니다.
위와 같이 코드를 작성 후 실행해보면 앞선 예와 마찬가지로 공유기에 접속 된 뒤 브라우저에 입력할 URL이 나옵니다.
LED ON 을 누르고 관리자 도구로 리퀘스트 헤더를 확인했을 때
첫줄이
GET /ledon HTTP/1.1 \r\n 으로 되어 있는 것을 확인할 수 있습니다
잘 작동하는 것을 확인할 수 있습니다.
이제 다른 액추에이터를 작동하는데 응용할 수 있고
변수를 선언해 anarodRead값을 저장해둔 뒤
client.println(변수)를 넣으면 웹상에서 센서가 읽은 값을 모니터링 하는 등으로 응용할 수 있습니다.