You are looking for information, articles, knowledge about the topic nail salons open on sunday near me 아두 이노 와이파이 데이터 전송 on Google, you do not find the information you need! Here are the best content compiled and compiled by the toplist.Experience-Porthcawl.com team, along with other related topics such as: 아두 이노 와이파이 데이터 전송 아두이노 데이터 전송, 아두이노 와이파이 통신 거리, 아두이노 esp8266, 아두이노 wifi 모듈, 아두이노 와이파이 연결, 와이파이 모듈이란, 아두이노 esp8266 웹서버
아두이노 – 와이파이, ESP01 wifi 모듈 무선 원격제어 그리고 시리얼 통신 – 6편 :: postpop
- Article author: postpop.tistory.com
- Reviews from users: 7013 Ratings
- Top rated: 3.3
- Lowest rated: 1
- Summary of article content: Articles about 아두이노 – 와이파이, ESP01 wifi 모듈 무선 원격제어 그리고 시리얼 통신 – 6편 :: postpop 이번 글에서는 아두이노 와이파이(wifi) 모듈 ESP-01을 이용하여 wifi AP를 설정하고 스마트폰과 wifi AP 연결을 통한 데이터 전송과 와이파이로 수신 … …
- Most searched keywords: Whether you are looking for 아두이노 – 와이파이, ESP01 wifi 모듈 무선 원격제어 그리고 시리얼 통신 – 6편 :: postpop 이번 글에서는 아두이노 와이파이(wifi) 모듈 ESP-01을 이용하여 wifi AP를 설정하고 스마트폰과 wifi AP 연결을 통한 데이터 전송과 와이파이로 수신 … 이번 글에서는 아두이노 와이파이(wifi) 모듈 ESP-01을 이용하여 wifi AP를 설정하고 스마트폰과 wifi AP 연결을 통한 데이터 전송과 와이파이로 수신된 데이터를 시리얼 통신을 통해 아두이노에서 받고..홍성호
- Table of Contents:
아두이노 – 와이파이 ESP01 wifi 모듈 무선 원격제어 그리고 시리얼 통신 – 6편
티스토리툴바
MFK_075 : 아두이노 WiFi 통신하기 1 (서버와 데이터 주고받기) : 네이버 블로그
- Article author: m.blog.naver.com
- Reviews from users: 32263 Ratings
- Top rated: 3.3
- Lowest rated: 1
- Summary of article content: Articles about MFK_075 : 아두이노 WiFi 통신하기 1 (서버와 데이터 주고받기) : 네이버 블로그 서버에서 데이터를 보내면 해당 데이터를 시리얼 모니터에 보여줍니다. 그리고 모듈에서는 0~30까지의 숫자를 반복적으로 1초마다 전송하게 되어있습니다. …
- Most searched keywords: Whether you are looking for MFK_075 : 아두이노 WiFi 통신하기 1 (서버와 데이터 주고받기) : 네이버 블로그 서버에서 데이터를 보내면 해당 데이터를 시리얼 모니터에 보여줍니다. 그리고 모듈에서는 0~30까지의 숫자를 반복적으로 1초마다 전송하게 되어있습니다.
- Table of Contents:
카테고리 이동
마이크로펀
이 블로그
MFK_Serise
카테고리 글
카테고리
이 블로그
MFK_Serise
카테고리 글
아두이노와 ESP8266으로 wifi에 연결해서 웹서버 만드고, 센서값 출력하기
- Article author: diyver.tistory.com
- Reviews from users: 24079 Ratings
- Top rated: 3.7
- Lowest rated: 1
- Summary of article content: Articles about 아두이노와 ESP8266으로 wifi에 연결해서 웹서버 만드고, 센서값 출력하기 아두이노에 ESP8266 모듈을 장착하면 아두이노로 wifi연결을 통해 인터넷에 접속할 수 있다. 그리고 웹 서버도 만들 수 있는데, 이 웹서버를 통해서 … …
- Most searched keywords: Whether you are looking for 아두이노와 ESP8266으로 wifi에 연결해서 웹서버 만드고, 센서값 출력하기 아두이노에 ESP8266 모듈을 장착하면 아두이노로 wifi연결을 통해 인터넷에 접속할 수 있다. 그리고 웹 서버도 만들 수 있는데, 이 웹서버를 통해서 … <목표> – 몇년 전부터 아두이노를 통한 IoT 개발이 정말 많이 이루어지고 있다. 자료가 많이 없어서 이렇게 글을 써보려 한다. 아두이노에 ESP8266 모듈을 장착하면 아두이노로 wifi연결을 통해 인터넷에 접속할..
- Table of Contents:
태그
관련글
댓글12
공지사항
최근글
인기글
최근댓글
태그
티스토리툴바
25. 와이파이 연결하기
- Article author: infoinno.tistory.com
- Reviews from users: 25833 Ratings
- Top rated: 4.9
- Lowest rated: 1
- Summary of article content: Articles about 25. 와이파이 연결하기 와이파이 모듈 ESP-01; 모듈연결하기; 보드레이트 변경하기 … VCC -> 아두이노 3.3V, RX -> 아두이노 TX (3번핀) … AT+CIPSEND : 데이터 전송 …
- Most searched keywords: Whether you are looking for 25. 와이파이 연결하기 와이파이 모듈 ESP-01; 모듈연결하기; 보드레이트 변경하기 … VCC -> 아두이노 3.3V, RX -> 아두이노 TX (3번핀) … AT+CIPSEND : 데이터 전송 와이파이 모듈 ESP-01 모듈연결하기 보드레이트 변경하기 공유기 연결하기 1) 와이파이 모듈 ESP-01 ( ESP8266 ) 와이파이 모듈을 사용해 인터넷에 접근하여 여러가지 센서의 값을 관리하거나 액추에이터를 작동시..
- Table of Contents:
태그
관련글
댓글0
티스토리툴바
ESP8266 – ARDUINO IDE 예제 (WiFi 통신) | Hard Copy World
- Article author: www.hardcopyworld.com
- Reviews from users: 21646 Ratings
- Top rated: 3.5
- Lowest rated: 1
- Summary of article content: Articles about ESP8266 – ARDUINO IDE 예제 (WiFi 통신) | Hard Copy World 본 문서는 아두이노 개발환경(IDE)를 이용해서 ESP8266 모듈을 다루는 예제들을 … 연결을 유지하게 해 줌으로써 양방향 데이터 전송도 지원합니다. …
- Most searched keywords: Whether you are looking for ESP8266 – ARDUINO IDE 예제 (WiFi 통신) | Hard Copy World 본 문서는 아두이노 개발환경(IDE)를 이용해서 ESP8266 모듈을 다루는 예제들을 … 연결을 유지하게 해 줌으로써 양방향 데이터 전송도 지원합니다. 본 문서는 아두이노 개발환경(IDE)를 이용해서 ESP8266 모듈을 다루는 예제들을 포함하고 있습니다. ESP8266 – ARDUINO IDE 개발환경 설치 ESP8266 – ARDUINO IDE 예제 (GPIO 제어) ESP8266 – ARDUINO IDE 예제 (WiFi 통신) ESP8266 – ARDUINO IDE 예제 (MQTT) . ESP8266을 위한 다양한 예제가 이미 갖추어져 있습니다. [Arduino IDE – File – Examples – ESP8266xxx] 예제들을 보면 다양한 […]
- Table of Contents:
ESP8266 – ARDUINO IDE 예제 (WiFi 통신)
WiFi 통신 기본
WiFi Client (HTTP Request)
Web server
Web Socket (server)
아두 이노 와이파이 모듈 | 【 아두이노 완공#23】 Esp8266 Esp-01 스마트폰 Wifi 접속 Led 제어하기 With Android App Inventor 앱만들기 모든 답변
- Article author: you.covadoc.vn
- Reviews from users: 7552 Ratings
- Top rated: 4.5
- Lowest rated: 1
- Summary of article content: Articles about 아두 이노 와이파이 모듈 | 【 아두이노 완공#23】 Esp8266 Esp-01 스마트폰 Wifi 접속 Led 제어하기 With Android App Inventor 앱만들기 모든 답변 이번 글에서는 아두이노 와이파이(wifi) 모듈 ESP-01을 이용하여 wifi AP를 설정하고 스마트폰과 wifi AP 연결을 통한 데이터 전송과 와이파이로 수신 … …
- Most searched keywords: Whether you are looking for 아두 이노 와이파이 모듈 | 【 아두이노 완공#23】 Esp8266 Esp-01 스마트폰 Wifi 접속 Led 제어하기 With Android App Inventor 앱만들기 모든 답변 이번 글에서는 아두이노 와이파이(wifi) 모듈 ESP-01을 이용하여 wifi AP를 설정하고 스마트폰과 wifi AP 연결을 통한 데이터 전송과 와이파이로 수신 …
- Table of Contents:
아두 이노 와이파이 모듈 주제에 대한 동영상 보기
d여기에서 【 아두이노 완공#23】 ESP8266 esp-01 스마트폰 WiFi 접속 LED 제어하기 with Android App Inventor 앱만들기 – 아두 이노 와이파이 모듈 주제에 대한 세부정보를 참조하세요
아두 이노 와이파이 모듈 주제에 대한 자세한 내용은 여기를 참조하세요
주제와 관련된 이미지 아두 이노 와이파이 모듈
주제에 대한 기사 평가 아두 이노 와이파이 모듈
아두이노(Arduino) 인터넷 하기 – Wifi (ESP-01 ESP8266)연결하는 방법
[아두이노 강좌] WIFI ESP8266(ESP-01) 모듈 사용방법 알아보기 [아두이노] 와이파이 모듈 ESP8266(ESP-01) 사용법아두이노 – 와이파이 ESP01 wifi 모듈 무선 원격제어 그리고 시리얼 통신 – 6편
라즈이노 iOT 【 아두이노모듈#25】ESP8266 esp-01 활용하기#1 펌웨어 업뎃(내용보강-완료 영상추가)
아두이노 와이파이 ESP8266 ESP-07 모듈과 안테나
와이파이 모듈 ESP8266 아두이노 WIFI ESP-01
ESP8266 Wifi 모듈ESP-01Arduino아두이노와이파이
키워드에 대한 정보 아두 이노 와이파이 모듈
사람들이 주제에 대해 자주 검색하는 키워드 【 아두이노 완공#23】 ESP8266 esp-01 스마트폰 WiFi 접속 LED 제어하기 with Android App Inventor 앱만들기
Recent Posts
아두 이노 와이파이 통신 간단정리 – Eon
- Article author: eon.grommash.net
- Reviews from users: 46782 Ratings
- Top rated: 3.1
- Lowest rated: 1
- Summary of article content: Articles about 아두 이노 와이파이 통신 간단정리 – Eon 아두 이노 와이파이 통신 와 관련된 백과사전 검색 결과입니다. 와이파이 · Wi-Fi는 wireless felity(무선 데이터 전송 시스템)의 … …
- Most searched keywords: Whether you are looking for 아두 이노 와이파이 통신 간단정리 – Eon 아두 이노 와이파이 통신 와 관련된 백과사전 검색 결과입니다. 와이파이 · Wi-Fi는 wireless felity(무선 데이터 전송 시스템)의 … 아두 이노 와이파이 통신 을(를) 탐구해보도록 하겠습니다. 이 글을 전체적으로 읽으시면 아두 이노 와이파이 통신 을(를) 이해하게 될 것입니다. 아두 이노 와이파이 통신 가 궁금하시다면 모두 읽어주시면 도움이 될 것입니다 이제 아두 이노 와이파이 통신 을(를) 알아보도록 합시다.
- Table of Contents:
아두 이노 와이파이 통신 와 관련된 블로그 검색 결과입니다
아두 이노 와이파이 통신 와 관련된 백과사전 검색 결과입니다
아두 이노 와이파이 통신 와 관련된 카페 검색 결과입니다
아두 이노 와이파이 통신 와 관련된 웹문서 검색 결과입니다
Recent Posts
Recent Comments
ESP 모듈 와이파이 연결 : HTTP 통신
- Article author: www.robotstory.co.kr
- Reviews from users: 25320 Ratings
- Top rated: 3.6
- Lowest rated: 1
- Summary of article content: Articles about ESP 모듈 와이파이 연결 : HTTP 통신 이번에는 웹에서 아두이노를 제어하기위해 HTTP 통신으로 ESP 모듈과 통신해 … 약자로 웹브라우저상에서 HTML 문서를 전송하는 프로토콜을 말합니다. …
- Most searched keywords: Whether you are looking for ESP 모듈 와이파이 연결 : HTTP 통신 이번에는 웹에서 아두이노를 제어하기위해 HTTP 통신으로 ESP 모듈과 통신해 … 약자로 웹브라우저상에서 HTML 문서를 전송하는 프로토콜을 말합니다. 이번에는 웹에서 아두이노를 제어하기위해 HTTP 통신으로 ESP 모듈과 통신해보겠습니다.HTTP는 HyperText Transfer Protocol의 약자로 웹브라우저상에서 HTML 문서를 전송하는 프로토콜을 말합니다. 클라이언트에서 서버로 요청(Request)을 보내면 서버로부터 응답(Response)를 받는 단방향 통신입니다ESP-01, ESP8266, HTTP 통신, 웹페이지, 와이파이 연결
- Table of Contents:
로봇스토리
댓글 많은글
추천 많은글
조회 많은글
See more articles in the same category here: toplist.Experience-Porthcawl.com/blog.
아두이노 – 와이파이, ESP01 wifi 모듈 무선 원격제어 그리고 시리얼 통신 – 6편
이번 글에서는 아두이노 와이파이(wifi) 모듈 ESP-01을 이용하여 wifi AP를 설정하고 스마트폰과 wifi AP 연결을 통한 데이터 전송과 와이파이로 수신된 데이터를 시리얼 통신을 통해 아두이노에서 받고 코드를 실행하는 원격제어를 할 수 있도록 코딩해 보자.
ESP-01 pin map
아두이노와 연결하기
TX -> 아두이노 RX
RX -> 아두이노 TX
VCC -> 아두이노 3.3V
CH_PD -> 아두이노 3.3V
GND -> 아두이노 GND
아두이노의 출력 핀 TTL 전압은 5V이고 ESP-01 모듈은 3.3V이다. 따라서 아두이노 TX핀에서 출력되는 신호 전압을 TTL 레벨 쉬프트를 통해 ESP-01 모듈의 RX 핀에 3.3V의 신호 전압으로 변경해주어야 하지만, 테스트상에서는 별 문제가 없어서 아래와 같이 TTL 레벨 쉬프트 없이 연결하였다. 이 연결 방식은 장시간 사용 시 ESP-01 모듈에 손상을 줄 가능성이 있다.
장시간 사용할 예정이라면 아두이노 TTL 레벨 쉬프트를 검색하여 적용하기 바란다.
연결을 하였다면 AT command를 통해 정상 작동 여부를 확인해 보자.
아래 파일을 아두이노에 업로드해준다.
#include
#define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); void setup() { Serial.begin(115200); //시리얼 모니터 esp01.begin(115200); //와이파이 시리얼 } void loop() { if (esp01.available()) { Serial.write(esp01.read()); //블루투스 측 내용을 시리얼 모니터에 출력 } if (Serial.available()) { esp01.write(Serial.read()); //시리얼 모니터 내용을 블루투스 측에 쓰기 } } ESP-01의 기본 baud rate는 115200이다. 현재 상태의 작동 여부를 확인하기 위해 하드웨어와 소프트웨어 시리얼 baud rate를 둘 다 115200으로 맞추어 주었다. 115200으로 해놓아도 AT command의 사용에는 지장이 없다.
아두이노 시리얼 모니터의 전송 옵션을 Both NL & CR, 보드 레이트를 115200으로 맞추어 주고 아두이노 시리얼 모니터 입력창에 AT를 입력하고 엔터를 친다.
응답으로 OK가 들어온다면 기기의 정상작동과 연결이 잘 되었음을 확인할 수 있다. 아래 그림처럼 수신된 데이터에 읽을 수 없는 문자가 섞여 있을 수 있다. 하지만 OK만 확인된다면 문제는 없다.
아두이노에서 softwareSerial을 통해 안정적으로 사용하기 위해서는 baud rate를 9600으로 변경해야 한다.
ESP-01의 baud rate를 변경하는 방법으로는 기본 baud rate가 9600으로 설정된 펌웨어를 모듈에 업데이트하는 방법과 AT command를 사용하여 변경해주는 방법이 있는데 이 글에서는 AT command를 사용하여 진행하겠다. 펌웨어 업데이트에 관해서는 인터넷상에 관련 글들이 많이 있으므로 참조하길 바란다.
아두이노 시리얼 모니터 입력창에 AT+UART_DEF=9600,8,1,0,0 를 복사한 뒤 붙여 넣고 엔터를 쳐준다.
아래처럼 OK 응답이 표시된다면 ESP-01의 baud rate가 9600으로 변경된 것이다.
ESP-01의 baud rate가 9600으로 변경되었으니 위의 코드의 baud rate를 115200에서 9600으로 아래 그림과 같이 변경해주고 업로드한다. 그리고 시리얼 모니터의 보드 레이트도 9600으로 변경한 뒤 AT를 입력하여 정상 작동 여부를 확인하면 준비는 끝나게 된다.
확인이 되었으면 스케치 상 보드 레이트를 9600 상태에서 저장을 시켜놓자. 이제 보드 레이트 115200은 사용하지 않게 된다.
ESP-01 wifi 모듈을 이용한 아두이노 원격제어의 방법은 아래와 같다.
ESP-01 모듈을 soft AP로 설정(공유기 기능)하여 스마트폰의 wifi가 AP의 ip로 연결할 수 있게 하고 또한, server로 설정하여 soft AP 통해 연결된 스마트폰이 server로 웹페이지를 요청할 수 있도록 하게 된다. 이렇게 함으로써, 만약 서버의 ip가 192.168.4.1로 설정되었을 경우, 스마트폰 웹브라우저 주소창에 http://192.168.4.1/on 입력하여 서버에 on 페이지에 대한 요청을 할 수 있게 된다. 이때 ESP-01 모듈은 들어온 웹페이지 요청 값을 시리얼 통신을 통해 아두이노에 전송하게 되고 아두이노는 수신된 웹페이지 요청 값을 코드에 따라서 원격제어에 필요한 on 만을 분리해내고 그 값에 해당하는 코드를 실행시켜 아두이노 원격제어를 구현하게 된다. 만약 on에 대한 응답 코드가 아두이노에 설정되어 있다면 아두이노는 시리얼 통신을 통해 ESP-01 모듈에 웹페이지 요청에 대한 응답을 보내라고 명령하게 되고 ESP-01 모듈은 그 명령에 따라 스마트폰에 응답을 보내게 된다. 이러한 과정을 통하여 스마트폰과 아두이노 간의 원격제어용 데이터 송신 및 수신이 이루어지게 된다.
상기의 작업을 수행할 수 있도록 ESP-01를 설정하는데 필요한 AT command에 대해 살펴보자.
AT+RST // ESP-01 리셋 AT+CWMODE=2 // 1 = Station mode (client), 2 = AP mode (host), 3 = AP + Station mode AT+CWSAP=”esp01″,”1234test”,5,3 // AT+CWSAP= softAP SSID, Password, channel id, ecn ecn(보안설정) : 0 = OPEN, 2 = WPA_PSK, 3 = WPA2_PSK, 4 = WPA_WPA2_PSK AT+CIFSR // AP IP 주소 AT+CIPMUX=1 // 0: Single connection, 1: Multiple connections (0 ~ 4), 서버 설정 시 “1” 강제 사항 AT+CIPSERVER=1,80 // AT+CIPSERVER= mode, port mode: 0: Delete server, 1: Create server, port number
상기의 AT command를 앞서 보드 레이트 변경 시와 같이 주석 앞부분을 복사하여 차례대로 아두이노 시리얼 모니터 입력창에 붙여 넣기 한 뒤 엔터를 치면 아래와 같이 ESP-01 모듈이 설정되는 것을 볼 수 있다.
ESP-01 모듈의 soft AP의 기본 설정 ip 주소는 192.168.4.1이다. 현재 soft AP의 주소가 기본 설정값인 192.168.4.1 임을 확인할 수 있다.
스마트폰에서 wifi 장치를 켜게 되면 상기에서 설정한 대로 SSID “esp01″이 검색될 것이다. 클릭하고 설정해 놓은 비밀번호를 입력하고 연결해 보자. 연결 후 네트워크 설정 관리에 들어가 보면 스마트폰이 할당받은 ip 주소를 확인할 수 있다. 아두이노 원격제어에서 우리가 할당받은 ip주소를 사용할 일은 거의 없다. 단지, soft AP의 주소와 비슷하여 혼동을 방지하기 위해 확인이 필요한 것뿐이다.
스마트폰이 soft AP에 접속이 되면 아래와 같이 시리얼 모니터상에 connection id: 0이 연결됐다는 표시와 +IPD,0,459:GET /hi HTTP/1.1 수신 데이터가 표시되고, 접속장비와 soft AP의 ip 주소를 확인할 수 있고 데이터 수신 후에 id 0번의 연결을 끊은걸 확인할 수 있다.
데이터의 수신
+IPD,0,158:GET / HTTP/1.1 // +IPD,id,len:GET /data HTTP/1.1 // id: id no. of connection, len: data length, data: data received
“+IPD,0,158:GET /” 이하가 수신된 데이터이다. 수신 시에는 AT+CIPMUX=1 옵션 설정에 따라 멀티 커넥션 id 0부터 4까지 자동으로 할당되어 사용하게 되며 수신이 완료되면 자동으로 연결을 닫게 되는데 연결을 닫기 전에 수신되는 데이터는 다른 커넥션 id로 자동 할당되어 수신되는 걸 테스트를 통해 확인할 수 있었다.
데이터의 전송
AT+CIPSEND=0,30 AT+CIPSEND=length // normal send (single connection). AT+CIPSEND=id,length // normal send (multiple connection), id: ID no. of connection, length: data length, MAX 048 bytes AT+CIPCLOSE=0 // id: ID no. of connection to close, Close TCP or UDP connection.For multiply connection mode
ESP-01을 통해 데이터 송신 시에는 아두이노에서 시리얼 통신을 통해 상기의 데이터 전송 AT command를 사용하여 전송 데이터와 함께 보내야만 데이터가 스마트폰으로 전송된다. 시리얼 통신으로 연결된다는 것 자체가 데이터의 전송 속도에 제한을 걸게 되는데, 이 상황에 더불어 모듈이 AT command를 수신하고 작동하는 시간이 소요되게 되어 아두이노에서 어떤 작동의 응답으로 ESP-01 모듈의 wifi를 통해 데이터 전송할 경우 약 1초 에서 2초의 시간이 걸리게 된다. 이 얘기는 짧은 시간 동안 연속되는 데이터의 전송하는 데 있어서 문제를 야기하게 된다고 할 수 있다. 필자는 ESP-01의 이러한 데이터 전송 특성 때문에 발생하는 사용의 불편함(긴 응답 시간)에 따라 이 기능의 효용성이 낮다고 보아 아두이노에서 스마트폰으로 데이터를 전송하는 기능을 아예 사용하지 않기로 하였다.
상기와 같이 아두이노 시리얼 모니터를 통해 ESP-01을 일일이 설정하는 것은 많이 불편하다. 코드상에서 아두이노 실행 시 자동으로 설정되도록 하는 코드를 인터넷에서 쉽게 찾아볼 수 있었고 이를 이용하기로 한다.
주요 코드를 아래와 같이 코딩해 주었다.
String sendData(String command, const int timeout, boolean debug) { // 스트링 타입 AT command 전송 함수 String response = “”; // 스트링 타입 지역변수 선언 및 초기화 esp01.print(command); // ESP-01 모듈에 스트링 타입의 AT command 전송 long int time = millis(); while( (time+timeout) > millis()) { // ESP-01 모듈의 명령 실행 후 응답에 필요한 시간이 경과되면 while(esp01.available()) { // 시리얼 버퍼에 ESP-01 모듈의 응답을 있을 경우 char c = esp01.read(); // 1byte 데이터를 char타입 변수 c에 저장 response+=c; // c에 저장된 문자를 문자열로 변경 } } if(debug) Serial.print(response); // debug가 참이면 시리얼 모니터에 출력 return response; }
전송 실행 함수: sendData(문자열 명령, 응답에 필요한 시간, 시리얼 모니터 출력 플래그);
sendData(“AT+RST\r
“,2000,DEBUG); //리셋 sendData(“AT+CWMODE=2\r
“,1000,DEBUG); // configure as access point (working mode: AP+STA) sendData(“AT+CWSAP=\”ESP-01\”,\”1234test\”,11,3\r
“,1000,DEBUG); // join the access point sendData(“AT+CIFSR\r
“,1000,DEBUG); // get ip address sendData(“AT+CIPMUX=1\r
“,1000,DEBUG); // configure for multiple connections sendData(“AT+CIPSERVER=1,80\r
“,1000,DEBUG); // turn on server on port 80
상기 코드 중 wifi 연결 시 비밀번호 연결을 비활성화하고자 한다면 아래처럼 3을 0으로 변경해주면 된다.
sendData(“AT+CWSAP=\”ESP-01\”,\”1234test\”,11,0\r
“,1000,DEBUG);
이제 수신 데이터를 필요한 값만 추출해내는 parsing에 대해 살펴보겠다.
parsing을 하기 위해서는 String class를 활용해야만 한다.
상기 AT command 설정 테스트에서 데이터 수신이 +IPD,0,158:GET / HTTP/1.1 형식으로 들어온 걸 확인했었다.
만약 웹브라우저에서 http://192.168.4.1/hi라고 입력하면 +IPD,0,459:GET /hi HTTP/1.1 데이터가 수신될 것이다. 즉, 모든 데이터 수신에는 +IPD,0,158:GET / 형식의 코드가 선행된다. 데이터 수신의 확인을 위해 “+IPD,”를 이용하여 하기로 하자.
if (esp01.find(“+IPD,”)) { // 만약 시리얼 버퍼에 “+IPD, “가 있으면, “+IPD,”가 확인될 경우 “+IPD,”는 삭제된다.
수신 데이터를 스트링 타입 income_wifi 변수에 저장해 주면 “0,158:GET / HTTP/1.1″라는 스트링이 저장된다.
income_wifi = esp01.readStringUntil(‘\r’); // 스트링 타입 income_wifi 변수에 ‘\r’ 문자까지 저장 웹브라우저 주소 끝에는 자동으로 ‘\r’ 문자가 붙는다.
필요한 data는 “GET /” 이후에 들어오고 종료 문자 역할을 하는 “HTTP/1.1″의 앞 공백 문자에서 끝나게 된다.
String class에서는 스트링 중의 일부를 떼어내어 저장할 수 있는 string.substring(start index, end index); 함수를 제공하고 있으며, 저장할 스트링의 시작 인덱스 번호와 종료 인덱스 번호를 필요로 한다. 이 함수를 이용하기 위해 “GET /”와 “HTTP/1.1″의 인덱스 번호를 알아내 보자.
income_wifi 스트링에서 “GET /”의 시작 인덱스 위치를 확인하는 코드는 income_wifi.indexOf(“GET /”)가 되고 “HTTP/1.1″의 시작 인덱스 위치를 확인하는 코드는 income_wifi.indexOf(“HTTP/1.1”)가 된다.
인덱스 번호를 사용하여 스트링에서 특정 위치의 스트링을 추출해내는 코드는 아래와 같게 된다.
income_wifi.substring(income_wifi.indexOf(“GET /”)+5, income_wifi.indexOf(“HTTP/1.1”)-1);
income_wifi.indexOf(“GET /”)는 “GET /”의 시작 인덱스 번호를 반환한다. 그러므로 필요한 위치의 인덱스 번호는 “GET /”의 글자 수 5를(공백 문자 포함) 더한 위치 값이 되게 된다.
income_wifi.indexOf(“HTTP/1.1”)는 “HTTP/1.1″의 시작 인덱스 번호를 반환한다. 하지만 앞에 공백 문자(space)가 있으므로 -1을 해준 위치 값이 필요로 하는 위치 값이 되고, 상기의 코드에서는 data가 없으므로 두 위치 값은 같은 값일 것이다.
아래 코드를 아두이노에 업로드하고 스마트폰에서 soft AP에 접속해 보자.
#include
#define DEBUG true String income_wifi = “”; SoftwareSerial esp01(2,3); void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(“AT+RST\r “,2000,DEBUG); // reset module sendData(“AT+CWMODE=2\r
“,1000,DEBUG); // configure as access point (working mode: AP+STA) sendData(“AT+CWSAP=\”ESP-01\”,\”1234test\”,11,0\r
“,1000,DEBUG); // join the access point sendData(“AT+CIFSR\r
“,1000,DEBUG); // get ip address sendData(“AT+CIPMUX=1\r
“,1000,DEBUG); // configure for multiple connections sendData(“AT+CIPSERVER=1,80\r
“,1000,DEBUG); // turn on server on port 80 } void loop() { if (esp01.available()) { if (esp01.find(“+IPD,”)) { income_wifi = esp01.readStringUntil(‘\r’); String wifi_temp = income_wifi.substring(income_wifi.indexOf(“GET /”)+5, income_wifi.indexOf(“HTTP/1.1”)-1); Serial.println(wifi_temp); } } } String sendData(String command, const int timeout, boolean debug) { String response = “”; esp01.print(command); // send the read character to the esp01 long int time = millis(); while( (time+timeout) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } } if(debug) Serial.print(response); return response; }
스마트폰 웹브라우저 주소창에서 192.168.4.1/hi를 입력하고 연결을 클릭하면 아래와 같이 시리얼 모니터에 hi가 표시된 것을 볼 수 있다.
앞에서 살펴본 AT command 설정 시에는 스마트폰 접속 시 관련 정보들이 시리얼 모니터에 출력되었었지만 지금은 data를 제외한 모든 값은 출력이 안되게 된다.
이렇게 추출된 스트링 데이터를 이용하여 LED의 제어를 할 수 있게 된다.
아래와 같이 아두이노 기본 LED를 웹브라우저를 통해 제어할 수 있도록 스트링 LED 제어 코드를 추가해 주었다.
업로드하고 스마트폰 웹브라우저에 http://192.168.4.1/on을 입력하면 LED가 켜지는 것을 볼 수 있고 http://192.168.4.1/off를 입력하면 LED가 꺼지는 것을 볼 수 있다. “on” 또는 “off”가 아닌 텍스트를 입력한다면 시리얼 모니터에 출력된다.
#include
#define DEBUG true #define ledPin 13 String income_wifi = “”; SoftwareSerial esp01(2,3); void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different pinMode(ledPin, OUTPUT); sendData(“AT+RST\r “,2000,DEBUG); // reset module sendData(“AT+CWMODE=2\r
“,1000,DEBUG); // configure as access point (working mode: AP+STA) sendData(“AT+CWSAP=\”ESP-01\”,\”1234test\”,11,0\r
“,1000,DEBUG); // join the access point sendData(“AT+CIFSR\r
“,1000,DEBUG); // get ip address sendData(“AT+CIPMUX=1\r
“,1000,DEBUG); // configure for multiple connections sendData(“AT+CIPSERVER=1,80\r
“,1000,DEBUG); // turn on server on port 80 } void loop() { if (esp01.available()) { if (esp01.find(“+IPD,”)) { income_wifi = esp01.readStringUntil(‘\r’); String wifi_temp = income_wifi.substring(income_wifi.indexOf(“GET /”)+5, income_wifi.indexOf(“HTTP/1.1”)-1); if(wifi_temp == “on”){ // wifi_temp는 지역변수로서 “if (esp01.find(“+IPD,”)){} 함수를 나가면 초기화됨. digitalWrite(ledPin, HIGH); } else if(wifi_temp == “off”){ digitalWrite(ledPin, LOW); } else { Serial.println(wifi_temp); } } } } String sendData(String command, const int timeout, boolean debug) { String response = “”; esp01.print(command); // send the read character to the esp01 long int time = millis(); while( (time+timeout) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } } if(debug) Serial.print(response); return response; }
이제 웹브라우저를 이용하는 대신 안드로이드 앱을 이용하여 원격제어를 해보자.
arduino bluetooth controller PWM 안드로이드 앱의 wifi를 이용한 원격제어용 데이터 전송 프로토콜은 다음과 같이 코딩해 주면 된다.
디지털 버튼 제어 프로토콜: “%%F0” + 스트링 값 + “%%F1” 스트링 값 = “10” 버튼1 off, 스트링 값 = “11” 버튼1 on, “20” 버튼2 off, “21” 버튼2 on, …… PWM 값 프로토콜: 1번 슬라이드 “%%F31” + 스트링 값 + “%%F1” 2번 슬라이드 “%%F32” + 스트링 값 + “%%F1” 3번 슬라이드 “%%F33” + 스트링 값 + “%%F1”
상기 예제 코드에서는 스트링을 parsing 할 때 시작 문자열로서 “GET /” 종료 문자열로서 “HTTP/1.1″를 사용했다. 이들을 상기 프로토콜에 적용하여 코드를 바꾸어 주었다. 또한 스트링으로 데이터를 한 번에 받기 때문에 “%%F1″와 “%%F0″가 스트링에 있다면 그 데이터의 검증이 완료된 것으로 볼 수 있다. 앞선 블루투스 원격제어에서는 검증 시 여러 단계가 필요했으나 스트링으로 데이터를 한꺼번에 받을 경우 코드가 간단해진다.
if (income_wifi.indexOf(“%%F1”) != -1) { // 만약 스트링 중에 “%%F1” 있고 if (income_wifi.indexOf(“%%F0”) != -1) { // “%%F0” 있으면 디지털 버튼 상태 값 검증이 되어 String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F0”)+4, income_wifi.indexOf(“%%F1”)); // 값 저장 if (income_wifi.indexOf(“%%F31”) != -1) { // 만약 스트링 중에 “%%F31” 있고 if (income_wifi.indexOf(“%%F0”) != -1) { // “%%F0” 있으면 슬라이드 1 PWM 값 검증이 되어 String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F31”)+5, income_wifi.indexOf(“%%F1”)); // 값 저장
기타 프로토콜에 해당되지 않는 텍스트는 앞선 parsing 방법을 사용한다.
String wifi_temp = income_wifi.substring(income_wifi.indexOf(“GET /”)+5, income_wifi.indexOf(“HTTP/1.1”)-1);
앞선 설명중 데이터 수신에서 멀티 커넥션 id에 관해 언급했었다. ESP-01 모듈은 데이터 수신 시 5개의 id를 사용하여 연결을 하게 되는데 그 id 번호는 0부터 4까지이다. 상기에 링크를 걸었던 ESP-01 모듈 AT command 참조 사이트에 의하면 만약 0 ~ 4까지 모두 사용하고 있는 상태에서 추가 연결이 있을 경우(id 값이 5가 될 경우) 모든 연결은 끊긴다고 한다. 필자가 확인해 본 결과 모두 끊기면서 더 이상 연결이 되지 않는다. 이런 상황이 되었을 경우 데이터의 송 수신이 안되게 되어 닫힌 멀티커넥션 기능을 열기 위해서는 리셋을 해주어야만 했다.
추가로 설명하자면, 데이터 수신 시 id 0번부터 받게 되고 수신이 완료되면 id 0번의 연결을 끊는 것을 앞선 예제에서 확인했었다. id 0번의 연결이 끊기게 되면 이때 id 0번이 다시 데이터를 받을 수 있는 상태로 초기화 되게 된다. 만약 id 0번의 연결이 끊기 전에 데이터가 들어오게 된다면, 다음 id인 1번으로 넘어가게 되고 다시 id 0번이 끊겨 초기화가 되면 다시 id 0번으로 데이터를 수신하게 된다. 즉 연속된 데이터를 id 순서대로 받다가 앞선 번호에서 초기화가 되면 그 id를 우선 사용하게 된다. 수신되는 데이터 간격이 길어 id 0번이 수신 완료하고 초기화되었다면 계속에서 id 0번을 사용하게 된다. 문제는 id의 연결을 끊고 초기화시키는데 시간이 걸린다는 것이다. 데이터가 빠르게 연속으로 들어올 경우 id가 초기화되기 전에 id 0부터 id 4까지 모두 연결된 상태가 되어 모든 연결을 끊고 더 이상 데이터를 수신하지 못하는 현상이 발생하게 되었다.
이를 해결하기 위해서 데이터를 읽는 시간 간격을 강제하고 활성화된 id를 AT command를 통해 강제로 끊는 코드를 아래와 같이 추가해 보았으나 그것 만으로는 충분하지 않았다.
connectionId = income_wifi.charAt(0); unsigned long int one_millis = 0; void wifi_delay() { // 50 millis 마다 연결된 id 가 있으면 그 아이디를 종료시키고 데이터 수신확인 if (millis() – one_millis > 50) { one_millis = millis(); if (connectionId == ‘0’) esp01.write(“AT+CIPCLOSE=0\r
“); else if (connectionId == ‘1’) esp01.write(“AT+CIPCLOSE=1\r
“); else if (connectionId == ‘2’) esp01.write(“AT+CIPCLOSE=2\r
“); else if (connectionId == ‘3’) esp01.write(“AT+CIPCLOSE=3\r
“); else if (connectionId == ‘4’) esp01.write(“AT+CIPCLOSE=4\r
“); wifi_read(); } }
또 다른 문제로는 수신된 데이터 각각의 id로 분산되어 받게 될 경우 그 순서가 뒤바뀔 수 있다는 것이다. 한 개의 아이디로 연속된 데이터를 받는다면 순서는 뒤바뀌지 않는다. 모듈에서 멀티 커넥션 id 연결 시 데이터 수신 시점의 시간 값에 대한 검증은 하지 않는 것 같으며 마지막에 출력되어야 할 값이 그전 값보다 먼저 출력되는 현상을 여러 번 확인했다.
사실 wifi 연결에 대한 응답 server의 구동에 있어 멀티 커넥션 자체가 다중 접속을 고려한 것이지 한 사용자의 연속된 데이터를 전송받기 위한 구성은 아닐 것이라 생각되며 웹페이지 요청 순서는 중요하지 않을 것이다.
어찌 되었든지 간에 원격제어를 하기 위해서는 신뢰할 수 있는 값의 순서가 필요하고 이런 문제를 해결하기 위해서는 한 개의 id만을 사용하여 받을 수 있도록 스마트폰에서 데이터를 전송하는 간격을 늘려주는 방법 외에는 찾을 수가 없었다.
ESP-01 wifi 모듈로 원격제어를 하는것은 블루투스 모듈의 사용에 비해 적당한 방법은 아니라고 생각이 되나 연결거리가 블루투스 보다 길어 또한 필요하게 된다.
ESP-01 wifi 모듈의 특징을 이해하고 모듈의 성능에 맞게 필요 기능이 적용되도록 코딩해야 한다.
1. 데이터 전송 시 시리얼 통신을 통하여 AT command를 매번 실행시켜주어야 한다. 2. 서버로서 데이터 수신 시 연결 옵션으로 멀티 커넥션 사용이 강제되어 있고 수신에 사용된 id가 사용 중이거나 종료되지 않은 경우에 추가되는 요청은 다음 id가 요청받게 된다. 3. 연결용 id 5개가 모두 연결된 상태에서 추가 요청이 올 경우 모두 닫힌다. -> 리셋해야만 다시 사용 가능해진다. 4. 3번의 경우를 방지하기 위해 데이터 수신이 완료되면 반드시 id연결을 끊고 대기 상태로 하여야 한다. 5. 연속되는 데이터를 받을 경우 id가 바뀌면서 데이터를 수신하게 되는데 그때 데이터 값의 순서가 바뀔 수 있다.
다음 편에 살펴볼 NODE MCU 1.0(ESP-12E, esp8266 칩셋)이나 ESP32 Dev Module의 경우 상기 ESP-01의 특징 중 2, 3, 5번은 동일한 거 같으나 모듈 자체에 wifi가 내장되어있어 ESP-01의 경우처럼 모듈과 wifi간 시리얼 통신을 사용하지 않을 뿐만 아니라 AT command도 사용하지 않게 되어 사용 id의 종료가 상대적으로 빠르다고 할 수 있다. 하지만 이 두 모델도 연속되는 빠른 데이터 수신 시 5번의 현상이 발견되었고 이를 해결하기 위해서 스마트 폰에서 데이터 전송 간격을 조정해주어야만 했다.
스마트폰에서 이 두 모듈의 데이터 전송 간격은 ESP-01 모듈보다는 짧고 블루투스 모듈보다는 길게 된다.
위의 코드를 아두이노에 업로드한 뒤 스마트폰에서 ESP-01의 soft AP에 접속한다.
arduino bluetooth controller PWM 안드로이드 앱을 실행한 뒤 wifi 아이콘을 클릭하고 ESP-01의 soft AP 192.168.4.1을 입력하고 esp01 체크 박스에 체크를 해준다. 앱에는 기본적으로 100 밀리 초마다 soft AP ip 주소로 응답 요청을 하도록 프로그램되어있다. 하지만 현재 ESP-01을 활용한 아두이노 스케치 코드에는 응답에 대한 어떠한 코드도 없으므로 스마트폰은 요청에 대한 응답을 받지 못하고 오류를 발생하게 된다. esp01 체크 박스에 체크를 해주면 100 밀리 초마다 soft AP ip 주소에 응답 요청을 하지 않게 되어 사용 가능하게 된다.
arduino bluetooth controller PWM – 아두이노 원격제어 안드로이드 앱 버전 3.5 다운로드
arduino bluetooth controller PWM 매뉴얼
(*** 앱에서 와이파이 연결은 안드로이드8 [갤럭시S7]이하 버전에서만 작동합니다 ***)
Confirm을 클릭한 뒤 버튼 1번을 클릭하면 아두이노 기본 LED가 켜지는 것을 볼 수 있고 버튼 2번 부터는 시리얼 모니터에 작동 상태가 표시된다. PWM 제어용 슬라이드는 천천히 움직일 경우 연속되는 데이터가 전송되고 빠르게 움직이면 최종 정지했을 때의 값만 전송된다.
ESP-01 모듈 연결 시는 안드로이드 앱에서 wifi를 통해 연결되었다는 어떠한 표시도 볼 수 없다. 아두이노에서 스마트폰으로 응답을 주는 코드가 없기 때문이다.
NODE MCU 1.0(ESP-12E, esp8266 칩셋)이나 ESP32 Dev Module의 경우 체크박스에 체크를 한 상태에서 Confirm을 클릭하게 되면 응답 요청을 하지 않게 되어 아두이노 측에서 입력된 값을 스마트폰에 출력을 하지 못하게 만든다. 아두이노 시리얼 모니터에 hello를 입력하면 스마트폰에 hello가 표시되어야 하나 표시가 되지 않는다. 이는 서버의 특징으로 스마트폰(클라이언트 또는 마스터)의 요청 시에만 서버(슬레이브)는 연결된 id를 통해 응답을 할 수 있기 때문에 요청이 없는 상태에서는 아두이노에서 스마트폰으로 데이터를 전송하지 못하게 된다. 또한 현재 연결되어 응답을 수신하고 있다는 표시도 할 수 없게 되어, 와이파이가 중간에 끊어져도 알 수 없게 된다. 하지만 ESP-01 모듈처럼 스마트폰에서 모듈의 제어를 하는 기능은 문제없이 사용 가능하다.
NODE MCU 1.0(ESP-12E, esp8266 칩셋)이나 ESP32 Dev Module의 경우에는 esp01 체크 박스에 체크하지 않고 Confirm을 클릭해야만 wifi를 통해 연결되었을 때 응답을 수신하고 현재 연결된 상태라는 것을 표시하게 되고 만약, 가변저항이 연결되어 있다면 가변저항의 조정 상태를 슬라이드 바로 표시할 수 있게 된다.
2019.11.22 추가
이제까지 ESP01의 soft AP에 연결하여 아두이노를 제어했다.
ESP01을 station모드로 공유기에 연결하고 내부 네트워크를 통한 아두이노 원격 제어해보자.
ESP01을 staion 모드로 공유기에 연결하면 공유기는 ESP01에 ip주소를 할당해 준다.
이 주소를 통해 내부 네트워크용 안에서 원격제어를 할 수 있게 되는데 이를 위해서는 반드시 시리얼 모니터에 표시되는 할당받은 ip주소를 확인한 뒤에 연결해야만 한다. (공유기에서 ESP01에 지정 ip를 할당하는 설정을 할 수 없는 경우) 또는 한번 받은 ip 주소를 메모해 두었다가 다시 연결 시 그 주소를 입력하여 사용할 수도 있다.
하지만 시리얼 모니터에서 ip주소를 확인하거나 ip주소가 변경되어 메모해둔 ip주소로 연결할 수 없는 경우도 발생할 수 있어 불편하다.
상기 이유로 내부 네트워크 이용 원격제어가 불필요하다고 생각하여 설명하지 않았었는데, 공유기에 스마트폰이 연결된 상태에서는 soft AP를 이용한 원격제어처럼 와이파이를 따로 연결하지 않아도 되는 편리한 점 때문에 설명을 추가하게 되었다.
ESP01을 station 모드로 공유기에 연결하기 위해서 아래와 같이 setup() 함수 코드를 변경해 주었다.
void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different pinMode(ledPin, OUTPUT); sendData(“AT+RST\r
“,2000,DEBUG); // reset module sendData(“AT+CWMODE=1\r
“,1000,DEBUG); // configure as access point (working mode: AP+STA) sendData(“AT+CWDHCP=1,1\r
“,1000,DEBUG); sendData(“AT+CWJAP=\””+ ssid +”\”,\””+pass+”\”\r
“,8000,DEBUG); sendData(“AT+CIFSR\r
“,1000,DEBUG); // get ip address sendData(“AT+CIPMUX=1\r
“,1000,DEBUG); // configure for multiple connections sendData(“AT+CIPSERVER=1,80\r
“,1000,DEBUG); // turn on server on port 80 }
아래 코드를 업로드하고 시리얼 모니터를 통해 공유기에서 할당받은 ip를 확인하고 ip 주소 192.168.4.1 대신 공유기에서 할당받은 ip를 입력하고 연결해 주면 된다.
2021.03.06 추가
일정 시간 경과 후 와이파이 연결 및 데이터 전송에 관한 테스트
공유기를 통해 테스트하였습니다.
공유기 아이디: skynet
공유기 비번: skynet00
스마트폰의 와이파이가 공유기 skynet에 연결된 상태에서 arduino bluetooth controller PWM 앱을 이용해 테스트했습니다.
아두이노 코드
#include
#define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid = “skynet”; // your network SSID (name) const String pass = “skynet00”; // your network password const String ssid_AP = “ESP-01”; // your network SSID (name) const String pass_AP = “1234test”; // your network password String ip = “”; bool ipCheck = false; #define DEBUG true #define ledPin 13 uint8_t pin_val = 0; // 디지털 버튼 제어용 변수 uint16_t pwm1 = 0; // pwm 제어용 변수 uint16_t pwm2 = 0; uint16_t pwm3 = 0; String text = “”; char connectionId; // 연결 id 저장 변수 String income_wifi = “”; void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different pinMode(ledPin, OUTPUT); sendData(“AT+RST\r “,2000,DEBUG); // reset module sendData(“AT+CWMODE=3\r
“,1000,DEBUG); // configure as access point (working mode: AP+STA) sendData(“AT+CWDHCP=1,1\r
“,1000,DEBUG); sendData(“AT+CWSAP=\””+ ssid_AP +”\”,\””+pass_AP+”\”,11,0\r
“,1000,DEBUG); // join the access point sendData(“AT+CWJAP=\””+ ssid +”\”,\””+pass+”\”\r
“,8000,DEBUG); sendData(“AT+CIFSR\r
“,1000,DEBUG); // get ip address sendData(“AT+CIPMUX=1\r
“,1000,DEBUG); // configure for multiple connections sendData(“AT+CIPSERVER=1,80\r
“,1000,DEBUG); // turn on server on port 80 } void loop() { wifi_delay(); if(Serial.available() > 0){ // 아두이노 모듈 작동 확인 String temp = Serial.readStringUntil(‘
‘); Serial.println(temp); } } unsigned long int one_millis = 0; void wifi_delay() { // 100 millis if (millis() – one_millis > 50) { one_millis = millis(); if (connectionId == ‘0’) esp01.write(“AT+CIPCLOSE=0\r
“); else if (connectionId == ‘1’) esp01.write(“AT+CIPCLOSE=1\r
“); else if (connectionId == ‘2’) esp01.write(“AT+CIPCLOSE=2\r
“); else if (connectionId == ‘3’) esp01.write(“AT+CIPCLOSE=3\r
“); else if (connectionId == ‘4’) esp01.write(“AT+CIPCLOSE=4\r
“); wifi_read(); } } void wifi_read() { if (esp01.available()) { // check if the esp is sending a message if (esp01.find(“+IPD,”)) { income_wifi = esp01.readStringUntil(‘\r’); Serial.println(income_wifi); connectionId = income_wifi.charAt(0); if (income_wifi.indexOf(“%%F1”) != -1) { if (income_wifi.indexOf(“%%F0”) != -1) { String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F0”)+4, income_wifi.indexOf(“%%F1”)); pin_val = wifi_temp.toInt(); Serial.println(pin_val); pin_control(); } else if (income_wifi.indexOf(“%%F31”) != -1) { String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F31”)+5, income_wifi.indexOf(“%%F1”)); pwm1 = wifi_temp.toInt(); Serial.print(“pwm1: “); Serial.println(pwm1); } else if (income_wifi.indexOf(“%%F32”) != -1) { String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F32”)+5, income_wifi.indexOf(“%%F1”)); pwm2 = wifi_temp.toInt(); Serial.print(“pwm2: “); Serial.println(pwm2); } else if (income_wifi.indexOf(“%%F33”) != -1) { String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F33”)+5, income_wifi.indexOf(“%%F1”)); pwm3 = wifi_temp.toInt(); Serial.print(“pwm3: “); Serial.println(pwm3); } } else { // 텍스트 출력 코드 String wifi_temp = income_wifi.substring(income_wifi.indexOf(“GET /”)+5, income_wifi.indexOf(“HTTP/1.1”)); Serial.println(wifi_temp); } income_wifi = “”; } } } String sendData(String command, const int timeout, boolean debug) { String response = “”; if (command.indexOf(“CIFSR”) != -1) ipCheck = true; else ipCheck = false; esp01.print(command); // send the read character to the esp01 long int time = millis(); while( (time+timeout) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } } if (ipCheck) { ip = response.substring(response.indexOf(“STAIP,”)+7,response.indexOf(“+CIFSR:STAMAC”)-3); } if(debug) Serial.print(response); return response; } void pin_control() { if (pin_val != 0) { switch (pin_val) { case 11: digitalWrite(ledPin, true); // button 1 : on break; case 10: digitalWrite(ledPin, false); // button 1 : off break; case 21: Serial.println(“button 2 : on”); break; case 20: Serial.println(“button 2 : off”); break; case 31: Serial.println(“button 3 : on”); break; case 30: Serial.println(“button 3 : off”); break; case 41: Serial.println(“button 4 : on”); break; case 40: Serial.println(“button 4 : off”); break; case 51: Serial.println(“button 5 : on”); break; case 50: Serial.println(“button 5 : off”); break; case 61: Serial.println(“button 6 : on”); break; case 60: Serial.println(“button 6 : off”); break; case 71: Serial.println(“button 7 : on”); break; case 70: Serial.println(“button 7 : off”); break; case 81: Serial.println(“button 8 : on”); break; case 80: Serial.println(“button 8 : off”); break; case 91: Serial.println(“button 9 : on”); break; case 90: Serial.println(“button 9 : off”); break; case 101: Serial.println(“button 10 : on”); break; case 100: Serial.println(“button 10 : off”); break; case 111: Serial.println(“button 11 : on”); break; case 110: Serial.println(“button 11 : off”); break; case 121: Serial.println(“button 12 : on”); break; case 120: Serial.println(“button 12 : off”); break; } pin_val = 0; } }
상기 코드 업로드 후 시리얼 모니터에서 공유기에서 할당해준 ip 주소 192.168.1.9 확인
스마트폰 와이파이 공유기 연결
arduino bluetooth controller PWM 앱에서 esp01 ip 주소 설정
앱에서 텍스트 hi 전송 및 1번 버튼 온/오프 메시지
데이터 수신 및 동작 확인 후 일정 시간 지난 뒤 다시 제어할 경우 가끔씩 esp01 모듈이 sleep 상태로 전환되어 있는 것처럼 첫 번째 데이터를 수신하지 못하는 경우를 확인하였습니다.
모듈의 특성인지는 모르겠지만 앱에서 와이파이를 제어한다는 것이 인터넷 브라우저에서 제어하는 것과는 약간의 차이가 있게 됩니다. 웹브라우저는 서버에서 보내주는 “OK 200″확인 메시지를 받지 못하면 일정기간 또는 일정 횟수 동안 같은 메시지를 반복해서 보내게 되는데 앱에서는 한 번만 보내도록 되어 있어 발생하는 것으로 생각됩니다. 블루투스로 연결해서 사용할 경우에는 이러한 문제가 발생하지 않을 것입니다. 왜냐하면 블루투스는 상시 연결(BLE 제외)을 기준으로 하기 때문 일 것입니다.
일정 시간 뒤 버튼을 눌러 제어를 하고자 했는데 esp01 모듈이 데이트를 받지 못하는 상황을 방지하기 위해서는 텍스트 입력창에 어떤 텍스트라도 입력하여 전 송한 뒤 esp01이 데이터를 확실하게 수신할 수 있도록 깨워주는(?) 선행 작업이 필요할 것으로 생각됩니다.
2022년 5월 31일 업데이트
1. AT command의 딜레이 시간을 제거하고 회신 값에 따라 다음 코드가 실행되게 하여 오류 방지 및 setup 완료 시간 최적화
2. 공유기에 접속할 수 있도록 AT+CWJAP 추가
3. 공유기 연결 실패 시 재시도하도록 코드 추가
위 사진의 ip 주소처럼 정상적으로 wifi 공유기에 연결되고 ip 주소를 할당받은 경우에는 컴퓨터의 웹브라우저 주소창에 해당 아이피와 테스트 문구 “192.168.1.12/hi”를 입력하여 테스트할 수 있다.
#include
#define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[33] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r “); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘
‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“out”)); break; } } sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address } String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘
‘); if (income_wifi.startsWith(F(“+IPD,”))) { String wifi_temp = income_wifi.substring(income_wifi.indexOf(F(“GET /”))+5, income_wifi.indexOf(F(“HTTP/1.1”))-1); Serial.println(wifi_temp); } } }
웹페이지를 통한 요청에 대해 응답을 하도록 코드를 작성해 주었다.
void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; cip += Data.length()+19; cip += F("\r "); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r
\r
“)); // +19 esp01.print(Data); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; disconnectID(); }
웹페이지 주소창에서 할당받은 아이피 주소에 on/off/message를 입력해 보자.
주소창에 192.168.1.12/on 입력후 회신받은 메세지
주소창에 192.168.1.12/off 입력후 회신받은 메세지
주소창에 192.168.1.12/Hello World! 입력후 회신받은 메세지
#include
#define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[33] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r “); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } #define ledPin 13 void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘
‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“out”)); break; } } sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address } uint8_t connectionId = 255; // 연결 id 저장 변수 String Data = “”; void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; cip += Data.length()+19; cip += F("\r "); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r
\r
“)); // +19 esp01.print(Data); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; disconnectID(); } String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘
‘); if (income_wifi.startsWith(F(“+IPD,”))) { income_wifi.remove(0,5); connectionId = income_wifi.charAt(0); int ed = income_wifi.lastIndexOf(F(“HTTP/1.1”))-1; income_wifi.remove(ed); int st = income_wifi.indexOf(F(“GET /”))+5; income_wifi.remove(0,st); Serial.println(income_wifi); if(income_wifi == F(“on”)){ digitalWrite(ledPin, HIGH); Data += F(“
LED ON
“); } else if(income_wifi == F(“off”)){ digitalWrite(ledPin, LOW); Data += F(“
LED OFF
“); } else { income_wifi.replace(“%20″, ” “); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F(“
“); Data += income_wifi; Data += F(“
“); } http_response(); } income_wifi = “”; } }
웹페이지를 이용하여 아두이노 우노의 기본 LED를 제어해 보자
웹페이지 코드
const char HEADER[] PROGMEM = // HTML HEADER “
” “” ““; const char FOOTER[] PROGMEM = “\r
“; // HTML FOOTER const char BACK[] PROGMEM = “
“; void ipPage() { Data = (const __FlashStringHelper *)HEADER; // 아두이노 PROGMEM 읽는 코드 Data += F(“
SSID: “); Data += ssid; Data += F(“
“); Data += F(“
IP Address: “); Data += ip; // 와이파이 공유기에서 할당받은 아이피 주소 Data += F(“
“); Data += F(“
“); Data += (const __FlashStringHelper *)FOOTER; } void buttonPage() { Data = (const __FlashStringHelper *)HEADER; Data += F(“
Pin Control
“); Data += F(“
“); Data += F(“
“); Data += F(“
“); // 데이터 폼 종료 Data += (const __FlashStringHelper *)BACK; Data += (const __FlashStringHelper *)FOOTER; }
주소창에 192.168.1.12 입력
Button을 클릭했을때 들어가는 페이지
버튼 1을 클릭하면 아두이노 우노의 기본 LED가 켜지고 버튼 1이 ON색상으로 변경된 웹페이지를 받게 된다.
ㅓ
상기 시리얼 모니터에 표시된 AT+CIPSEND=1,912중 “912”가 웹페이지 전체 문자열 길이이고 이 중 Data 스트링 변수의 전체 길이는 912 – 19 = 893이다.
스케치는 프로그램 저장 공간 12138 바이트(37%)를 사용. 최대 32256 바이트.
전역 변수는 동적 메모리 427바이트(20%)를 사용, 1621바이트의 지역변수가 남음. 최대는 2048 바이트.
상기 코드를 업로드한 후에 아두이노 IDE에 현재 가용 메모리가 1621바이트 남아있다고 한다. 실제로는 아두이노 부팅 후 사용되는 함수 안의 스트링 지역 변수 등은 돌려받게 되지만 남은 메모리 1621바이트 전체를 사용할 수 없는 게 일반적이다. 변수에 공간을 할당하고 회수하는 데에 있어서 흔적들 또는 유실되는 영역들이 발생하므로 실제 가용 메모리에 대해서는 추정적이나 실험적으로 결정해야 한다. 버튼 웹페이지의 Data 문자열 길이가 현재보다 길어진다면 메모리 부족으로 인해 데이터가 일부만 전송될 수 있다. PROGMEM을 이용한 추가적인 페이지는 더 만들 수 있으나 상기 코드에서는 웹페이지의 Data 문자열 변수의 길이를 대략 900 이하로 맞추어 주어야 한다.
#include
#define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[33] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r “); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } #define ledPin 13 void setup() { pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘
‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“out”)); break; } } sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address } uint8_t connectionId = 255; // 연결 id 저장 변수 String Data = “”; void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; cip += Data.length()+19; cip += F("\r "); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r
\r
“)); // +19 esp01.print(Data); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; disconnectID(); } #include “webPage.h” String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘
‘); if (income_wifi.startsWith(F(“+IPD,”))) { income_wifi.remove(0,5); connectionId = income_wifi.charAt(0); int ed = income_wifi.lastIndexOf(F(“HTTP/1.1”))-1; income_wifi.remove(ed); int st = income_wifi.indexOf(F(“GET /”))+5; income_wifi.remove(0,st); Serial.println(income_wifi); if(income_wifi == F(“on”)){ digitalWrite(ledPin, HIGH); Data += F(“
LED ON
“); } else if(income_wifi == F(“off”)){ digitalWrite(ledPin, LOW); Data += F(“
LED OFF
“); } else { if (income_wifi.indexOf(F(“ip”)) != -1) ipPage(); else if (income_wifi.indexOf(F(“Button”)) != -1) buttonPage(); else if (income_wifi.indexOf(F(“button”)) != -1) { String temp = income_wifi.substring(income_wifi.indexOf(‘?’)+4); uint8_t val = temp.toInt(); if (val == 10) digitalWrite(ledPin, LOW); else digitalWrite(ledPin, HIGH); buttonPage(); } else { Serial.println(F(“enter”)); if (income_wifi == “”) ipPage(); else { income_wifi.replace(“%20″, ” “); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F(“
“); Data += income_wifi; Data += F(“
“); } } } http_response(); } income_wifi = “”; } if(Serial.available() > 0){ // 아두이노 모듈 작동 확인 String temp = Serial.readStringUntil(‘
‘); Serial.println(temp); if (temp.startsWith(F(“AT”))) { temp.remove(0,3); Serial.println(temp); sendData(temp); } else if (temp == F(“1”)) { } } }
상기의 Data 문자열 변수의 길이를 줄여 메모리 문제를 해결하기 위해 boolean 변수 page를 설정하고 page 변수에 따라 웹페이지의 html header와 footer를 Data 문자열 변수에 저장하지 않고 PROGMEM에서 바로 읽어서 전송할 수 있도록 코드를 수정해 주었다.
void http_response(bool page) { String cip = F(“AT+CIPSEND=”); cip += connectionId-48; cip += ‘,’; if (page) cip += Data.length()+19+sizeofHeader+sizeofFooter; else cip += Data.length()+19; cip += F(“\r
“); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r
\r
“)); // +19 if (page) { esp01.print((const __FlashStringHelper *)HEADER); esp01.print(Data); esp01.print((const __FlashStringHelper *)FOOTER); } else esp01.print(Data); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; page = false; disconnectID(); }
#include
#define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[33] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r “); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } #define ledPin 13 uint16_t sizeofHeader = 0; uint16_t sizeofFooter = 0; bool page = false; String Data = “”; #include “webPage.h” void setup() { pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘
‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“out”)); break; } } sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address sizeofHeader = sizeof(HEADER)-1; // -1: ‘\0’ sizeofFooter = sizeof(FOOTER)-1; // -1: ‘\0’ } uint8_t connectionId = 255; // 연결 id 저장 변수 void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; if (page) cip += Data.length()+19+sizeofHeader+sizeofFooter; else cip += Data.length()+19; cip += F("\r "); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r
\r
“)); // +19 if (page) { esp01.print((const __FlashStringHelper *)HEADER); esp01.print(Data); esp01.print((const __FlashStringHelper *)FOOTER); } else esp01.print(Data); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; page = false; disconnectID(); } String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘
‘); if (income_wifi.startsWith(F(“+IPD,”))) { income_wifi.remove(0,5); connectionId = income_wifi.charAt(0); int ed = income_wifi.lastIndexOf(F(“HTTP/1.1”))-1; income_wifi.remove(ed); int st = income_wifi.indexOf(F(“GET /”))+5; income_wifi.remove(0,st); Serial.println(income_wifi); if (!income_wifi.startsWith(F(“fav”))) { // favicon.ico 는 통과 if(income_wifi == F(“on”)){ digitalWrite(ledPin, HIGH); Data += F(“
LED ON
“); } else if(income_wifi == F(“off”)){ digitalWrite(ledPin, LOW); Data += F(“
LED OFF
“); } else { if (income_wifi.indexOf(F(“ip”)) != -1) ipPage(); else if (income_wifi.indexOf(F(“Button”)) != -1) buttonPage(); else if (income_wifi.indexOf(F(“button”)) != -1) { String temp = income_wifi.substring(income_wifi.indexOf(‘?’)+4); uint8_t val = temp.toInt(); if (val == 10) digitalWrite(ledPin, LOW); else digitalWrite(ledPin, HIGH); buttonPage(); } else { Serial.println(F(“enter”)); if (income_wifi == “”) ipPage(); else { income_wifi.replace(“%20″, ” “); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F(“
“); Data += income_wifi; Data += F(“
“); } } } http_response(); } } income_wifi = “”; } if(Serial.available() > 0){ // 아두이노 모듈 작동 확인 String temp = Serial.readStringUntil(‘
‘); Serial.println(temp); if (temp.startsWith(F(“AT”))) { temp.remove(0,3); Serial.println(temp); sendData(temp); } else if (temp == F(“1”)) { } } }
와이파이 매니저
게시글 [arduino] – 아두이노 – ESP01 와이파이 매니저, soft AP이용 공유기 연결용 아이디와 비밀번호 설정하기, wifimanager에서 구현한 와이파이 매니저를 WiFiEsp.h 라이브러리를 사용하지 않고 AT commnad를 사용하여 구현하였다.
* 아두이노 IDE에서 와이파이 설정값 변경한 경우 EEPROM에 값 반영하는 방법
리부팅시 변경된 와이파이 설정값을 반영해주기 위해서는 시리얼 모니터에서 “1”을 입력하고 엔터를 쳐준 뒤에 아두이노를 리부팅 해준다.
설정에 따라 공유기에 연결이 안된 경우
Wifi 설정 페이지 – 와이파이 연결유무, 아이디, 패스워드 설정
공유기 연결 설정
설정 저장 및 공유기 연결중 메세지
공유기 연결 후 할당받은 아이피 표시
웹페이지 코드
//web page String const char HEADER[] PROGMEM = “
” “” ““; const char FOOTER[] PROGMEM = “\r
“; const char BACK[] PROGMEM = “
“; void ipPage() { Data += F(“
SSID: “); Data += ssid; Data += F(“
“); Data += F(“
IP Address: “); Data += ip; Data += F(“
“); Data += F(“
“); Data += F(“
“); page = true; } void buttonPage() { Data += F(“
Pin Control
“); Data += F(“
“); Data += F(“
“); Data += F(“
“); Data += (const __FlashStringHelper *)BACK; page = true; } void wifiPage() { Data += (const __FlashStringHelper *)BACK; Data += F(“
“); page = true; } void messagePage() { if (wifiRouter) { Data += F(“
SSID: “); Data += ssid; Data += F(“
“); Data += F(“
PASS: “); Data += pass; Data += F(“
“); Data += F(“
Credentials Saved.
“); Data += F(“
Trying to connect ESP01 to Router.
“); } else Data += F(“
disconnect from Router.
“); Data += (const __FlashStringHelper *)BACK; page = true; }
#include
#include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password bool wifiRouter = true; // 공유기 연결 유무 char ssid[21] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r “); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } #define ledPin 13 uint16_t sizeofHeader = 0; uint16_t sizeofFooter = 0; String Data = “”; bool page = false; #include “webPage.h” void setWifi() { sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘
‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“Set”)); break; } } if (wifiRouter) sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) else sendData(F(“CWMODE=2”)); if (wifiRouter) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 if (wifiRouter) { retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } } ipCheck(sendData(F(“CIFSR”))); // get ip address } void wifi_eeprom_read() { // 아이디 / 비밀번호 읽기 for (int i = 0; i < 20; i++) ssid[i] = EEPROM.read(981 + i); // sizeof(ssid)-1 for (int i = 0; i < 20; i++) pass[i] = EEPROM.read(1001 + i); // sizeof(pass)-1 } void wifi_eeprom_write() { // 아이디 / 비밀번호 쓰기 for (int i = 0; i < 20; i++) EEPROM.write(981 + i, ssid[i]); // sizeof(ssid)-1 for (int i = 0; i < 20; i++) EEPROM.write(1001 + i, pass[i]); // sizeof(pass)-1 } void setup() { pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); if(EEPROM.read(1023) != 1) { for (int i = 0 ; i < EEPROM.length() ; i++) EEPROM.write(i, 0); // EEPROM Clear EEPROM.write(1023, 1); // eeprom 저장 플래그 EEPROM.write(980, wifiRouter); wifi_eeprom_write(); // 최초 초기화시 아이디 / 비밀번호 쓰기 } else { wifiRouter = EEPROM.read(980); wifi_eeprom_read(); // 아두이노 리셋시 저장된 아이디 / 비밀번호 읽기 } Serial.begin(9600); esp01.begin(9600); // your esp's baud rate might be different setWifi(); sizeofHeader = sizeof(HEADER)-1; // -1: '\0' sizeofFooter = sizeof(FOOTER)-1; // -1: '\0' } uint8_t connectionId = 255; // 연결 id 저장 변수 void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; if (page) cip += Data.length()+19+sizeofHeader+sizeofFooter; else cip += Data.length()+19; cip += F("\r "); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r
\r
“)); // +19 if (page) { esp01.print((const __FlashStringHelper *)HEADER); esp01.print(Data); esp01.print((const __FlashStringHelper *)FOOTER); } else esp01.print(Data); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; page = false; disconnectID(); } String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘
‘); if (income_wifi.startsWith(F(“+IPD,”))) { income_wifi.remove(0,5); connectionId = income_wifi.charAt(0); int ed = income_wifi.lastIndexOf(F(“HTTP/1.1”))-1; income_wifi.remove(ed); int st = income_wifi.indexOf(F(“GET /”))+5; income_wifi.remove(0,st); Serial.println(income_wifi); if (!income_wifi.startsWith(F(“fav”))) { // favicon.ico 는 통과 bool wifiChanged = false; if(income_wifi == F(“on”)){ digitalWrite(ledPin, HIGH); Data += F(“
LED ON
“); } else if(income_wifi == F(“off”)){ digitalWrite(ledPin, LOW); Data += F(“
LED OFF
“); } else { if (income_wifi.indexOf(F(“ip”)) != -1) ipPage(); else if (income_wifi.indexOf(F(“Button”)) != -1) buttonPage(); else if (income_wifi.indexOf(F(“button”)) != -1) { String temp = income_wifi.substring(income_wifi.indexOf(‘?’)+4); uint8_t val = temp.toInt(); if (val == 10) digitalWrite(ledPin, LOW); else digitalWrite(ledPin, HIGH); buttonPage(); } else if (income_wifi.indexOf(F(“Wifi”)) != -1) wifiPage(); else if (income_wifi.indexOf(F(“wifi”)) != -1) { // ed = income_wifi.lastIndexOf(‘&’); String temp = income_wifi.substring(ed+3); String check = “”; if (temp.length() > 7) { // 비밀번호 길이가 8 이상인경우 check = pass; if (temp != check) { wifiChanged = true; for (int i = 0; i < temp.length(); i++) pass[i] = temp[i]; pass[temp.length()] = '\0'; } } income_wifi.remove(ed); ed = income_wifi.lastIndexOf(F("s=")); temp = income_wifi.substring(ed+2); Serial.println(temp); check = ssid; if (temp != check) { wifiChanged = true; for (int i = 0; i < temp.length(); i++) ssid[i] = temp[i]; ssid[temp.length()] = '\0'; } st = income_wifi.indexOf('?'); temp = income_wifi.substring(st+1, st+4); bool oldWifiRouter = wifiRouter; if (temp == F("use")) wifiRouter = true; else wifiRouter = false; if (oldWifiRouter != wifiRouter) { EEPROM.write(980, wifiRouter); wifiChanged = true; } if (wifiChanged) { wifi_eeprom_write(); messagePage(); } else wifiPage(); } else { if (income_wifi == "") ipPage(); else { income_wifi.replace("%20", " "); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F("
“); Data += income_wifi; Data += F(“
“); } } } http_response(); if (wifiChanged) setWifi(); } } income_wifi = “”; } if(Serial.available() > 0){ // 아두이노 모듈 작동 확인 String temp = Serial.readStringUntil(‘
‘); Serial.println(temp); if (temp.startsWith(F(“AT”))) { temp.remove(0,3); Serial.println(temp); sendData(temp); } else if (temp == F(“1”)) { EEPROM.write(1023, 0); } else if (temp == F(“2”)) { Serial.println(ssid); Serial.println(pass); } } }
웹페이지 로그인
와이파이를 통해 아두이노를 원격 제어할 때 Soft AP(192.168.4.1)를 사용할 경우에는 Soft AP의 비밀번호를 설정함으로써 보안이 설정되는데 (휴대폰의 와이파이 연결에서 AP연결 시 비밀번호 입력 필요), 아두이노가 와이파이 공유기에 연결되고 IP를 할당받은 경우에는 공유기 네트워크 내에 연결된 누구라도 아두이노가 연결된 IP주소만 알면 연결 및 제어가 가능하게 된다. 이를 방지하기 위해 Cookie를 사용하여 웹 로그인 기능을 구현하였다. 원격제어는 한 명만 제어가 가능해야 하며, 따라서 멀티 로그인은 배제한다.
1. 웹 로그인 사용 유무 설정
2. Soft AP(102.168.4.1)에 비밀번호가 설정되어 있는 경우에만 웹 로그인 활성화
* 비밀번호는 8 문자 이상 입력해야 설정됨
3. 웹 로그인 사용 시 Soft AP(102.168.4.1)를 통한 연결은 AP연결 시 비밀번호를 입력하므로 로그인 확인 안 함.
4. 공유기 네트워크에 로그인되어있더라도 Soft AP(102.168.4.1) 및 다른 브라우저 로그인을 통한 연결 시 밀어내기 기능 – Soft AP 접속 우선 제어 권한
5. 웹 로그인 비밀번호는 Soft AP 비밀번호를 사용한다.
웹로그인 페이지
웹로그인 비밀번호 입력
웹로그인 확인 후 페이지 표시
웹로그인 설정화면
웹로그인 시 시리얼모니터 표시
로그인 웹페이지 및 쿠기 생성 코드, 비밀번호 검증 코드
void loginPage() { if (connectedAP) { Data += F(“
occupied connection by AP
“); } else { Data += F(““); } page = true; } // login code String cooValue = “u7Dv0”; uint8_t cooLength = 5; bool newCoo = true; String makeCooValue() { cooValue = “”; uint8_t temp = 0; for (int i = 0; i < cooLength; i++) { temp = random(39, 123); //random(39, 123); // 39 ~ 122 pick if (temp == 47 || temp == 59 || temp == 60 || temp == 62 || temp == 92 || temp == 94 || temp == 96) temp = 41; cooValue += char(temp); } Serial.print(F("send coo: ")); Serial.println(cooValue); return cooValue; } bool checkLogin() { bool confirm = false; String tempId = ""; tempId = esp01.readStringUntil(' '); while(1) { tempId = esp01.readStringUntil(' '); if (tempId.startsWith(F("\r"))) { tempId = esp01.readStringUntil(' '); break; } } int index = tempId.lastIndexOf('&'); String tempPass = tempId.substring(index+3); tempId.remove(index); index = tempId.lastIndexOf('?'); tempId = tempId.substring(index+3); Serial.print("tempPass: "); Serial.println(tempPass); Serial.print("tempId: "); Serial.println(tempId); if (tempId == ssid_AP && tempPass == pass_AP) { confirm = true; login = true; newCoo = true;} return confirm; } #include
#include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password bool wifiRouter = true; // 공유기 연결 유무 char ssid[21] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; bool useLogin = true; bool connectedAP = false; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r “); esp01.print(command); // send the read character to the esp01 long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } #define ledPin 13 uint16_t sizeofHeader = 0; uint16_t sizeofFooter = 0; bool page = false; bool login = false; String Data = “”; #include “webPage.h” void setWifi() { sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘
‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“Set”)); break; } } if (wifiRouter) sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) else sendData(F(“CWMODE=2”)); if (wifiRouter) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 if (wifiRouter) { retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } } ipCheck(sendData(F(“CIFSR”))); // get ip address } void wifi_eeprom_read() { // 아이디 / 비밀번호 읽기 for (int i = 0; i < 20; i++) ssid[i] = EEPROM.read(981 + i); // sizeof(ssid)-1 for (int i = 0; i < 20; i++) pass[i] = EEPROM.read(1001 + i); // sizeof(pass)-1 } void wifi_eeprom_write() { // 아이디 / 비밀번호 쓰기 for (int i = 0; i < 20; i++) EEPROM.write(981 + i, ssid[i]); // sizeof(ssid)-1 for (int i = 0; i < 20; i++) EEPROM.write(1001 + i, pass[i]); // sizeof(pass)-1 } void setup() { pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); if(EEPROM.read(1023) != 1) { for (int i = 0 ; i < EEPROM.length() ; i++) EEPROM.write(i, 0); // EEPROM Clear EEPROM.write(1023, 1); // eeprom 저장 플래그 EEPROM.write(980, wifiRouter); EEPROM.write(979, useLogin); wifi_eeprom_write(); // 최초 초기화시 아이디 / 비밀번호 쓰기 } else { useLogin = EEPROM.read(979); wifiRouter = EEPROM.read(980); wifi_eeprom_read(); // 아두이노 리셋시 저장된 아이디 / 비밀번호 읽기 } if (pass_AP == "" || pass_AP.length() < 8) useLogin = false; // Soft AP의 비밀번호가 활성화되지않은 경우 Serial.begin(9600); esp01.begin(9600); // your esp's baud rate might be different setWifi(); sizeofHeader = sizeof(HEADER)-1; // -1: '\0' sizeofFooter = sizeof(FOOTER)-1; // -1: '\0' } uint8_t connectionId = 255; // 연결 id 저장 변수 void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; if (page) { uint8_t len = 50+4; if (!connectedAP && useLogin) { len += 4; if (login) { if (newCoo) len += cooLength; } } cip += Data.length()+len+sizeofHeader+sizeofFooter; } else cip += Data.length()+19; cip += F("\r "); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } if (page) { esp01.print(F(“HTTP/1.1 200 OK
Content-type:text/html
Set-Cookie:”)); // +52 -2 = 50 if (!connectedAP && useLogin) { esp01.print(F(“%%F5”)); // +4 if (login) { if (newCoo) esp01.print(makeCooValue()); // +cooLength } } esp01.print(F(“\r
\r
“)); // +8 -4 = 4 esp01.print((const __FlashStringHelper *)HEADER); esp01.print(Data); esp01.print((const __FlashStringHelper *)FOOTER); } else { esp01.print(F(“HTTP/1.1 200 OK\r
\r
“)); // 23 – 4 = +19 esp01.print(Data); } time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; page = false; disconnectID(); } String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘
‘); bool parsing = false; if (income_wifi.startsWith(F(“+”))) { if (income_wifi.startsWith(F(“+IPD”))) parsing = true; else if (income_wifi.startsWith(F(“+STA_CON”))) { connectedAP = true; Serial.println(F(“connectedAP”)); } else if (income_wifi.startsWith(F(“+STA_DIS”))) { connectedAP = false; Serial.println(F(“disconnectedAP”)); } } if (parsing) { income_wifi.remove(0,5); connectionId = income_wifi.charAt(0); int ed = income_wifi.lastIndexOf(F(“HTTP/1.1”))-1; income_wifi.remove(ed); int st = income_wifi.indexOf(F(“GET /”))+5; income_wifi.remove(0,st); Serial.println(income_wifi); if (!income_wifi.startsWith(F(“fav”))) { // favicon.ico 는 통과 bool OK = false, rootPage = false; bool wifiChanged = false; if (useLogin) { if (connectedAP) { OK = true; if (login) { login = false; makeCooValue(); } // 로그인 밀어내기 old Cookie terminate } else { if (!login) { // 현재 로그인 상태가 아닌 경우 if (income_wifi.indexOf(F(“Logi”)) != -1) { Serial.println(“enter”); rootPage = checkLogin(); // 비밀번호 검증 start sending Cookie Serial.println(rootPage); } } else { newCoo = false; if (income_wifi.indexOf(F(“Logi”)) != -1) { // 밀어내기 로그인 rootPage = checkLogin(); } else { uint16_t len = 0; String temp = “”; while(1) { temp = esp01.readStringUntil(‘
‘); len = temp.length(); if (temp.startsWith(F(“Coo”)) || len < 3) break; } if (len > 2) { ed = temp.indexOf(F(“%%F5”))+4; if (ed != -1) { temp = temp.substring(ed, ed+cooLength); if (temp == cooValue) { OK = true; newCoo = true; } } } if (OK) { // 웹페이지 출력 if (income_wifi.indexOf(F(“Logo”)) != -1) { // Logout login = false; OK = false; makeCooValue(); // cookie 값 변경 } } } } } } else { OK = true; } if (OK) { if(income_wifi == F(“on”)){ digitalWrite(ledPin, HIGH); Data += F(“
LED ON
“); } else if(income_wifi == F(“off”)){ digitalWrite(ledPin, LOW); Data += F(“
LED OFF
“); } else { if (income_wifi.indexOf(F(“ip”)) != -1) ipPage(); else if (income_wifi.indexOf(F(“Button”)) != -1) buttonPage(); else if (income_wifi.indexOf(F(“button”)) != -1) { String temp = income_wifi.substring(income_wifi.indexOf(‘?’)+4); uint8_t val = temp.toInt(); if (val == 10) digitalWrite(ledPin, LOW); else digitalWrite(ledPin, HIGH); buttonPage(); } else if (income_wifi.indexOf(F(“Wifi”)) != -1) wifiPage(); else if (income_wifi.indexOf(F(“wifi”)) != -1) { // ed = income_wifi.lastIndexOf(‘&’); String temp = income_wifi.substring(ed+3); if (temp == F(“G=on”)) { useLogin = true; EEPROM.write(979, useLogin); income_wifi.remove(ed); ed = income_wifi.lastIndexOf(‘&’); temp = income_wifi.substring(ed+3); } else { useLogin = false; EEPROM.write(979, useLogin); } String check = “”; if (temp.length() > 7) { // 비밀번호 길이가 8 이상인경우 check = pass; if (temp != check) { wifiChanged = true; for (int i = 0; i < temp.length(); i++) pass[i] = temp[i]; pass[temp.length()] = '\0'; } } income_wifi.remove(ed); ed = income_wifi.lastIndexOf(F("s=")); temp = income_wifi.substring(ed+2); Serial.println(temp); check = ssid; if (temp != check) { wifiChanged = true; for (int i = 0; i < temp.length(); i++) ssid[i] = temp[i]; ssid[temp.length()] = '\0'; } st = income_wifi.indexOf('?'); temp = income_wifi.substring(st+1, st+4); bool oldWifiRouter = wifiRouter; if (temp == F("ROU")) wifiRouter = true; else wifiRouter = false; if (oldWifiRouter != wifiRouter) { EEPROM.write(980, wifiRouter); wifiChanged = true; } if (wifiChanged) { wifi_eeprom_write(); messagePage(); } else wifiPage(); } else { if (income_wifi == "") ipPage(); else { income_wifi.replace(F("%20"), F(" ")); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F("
“); Data += income_wifi; Data += F(“
“); } } } } else { if (useLogin) { if (rootPage) ipPage(); else loginPage(); } else { if (income_wifi == “”) ipPage(); else { income_wifi.replace(F(“%20″), F(” “)); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F(“
“); Data += income_wifi; Data += F(“
“); } } } http_response(); if (wifiChanged) setWifi(); } } income_wifi = “”; } if(Serial.available() > 0){ // 아두이노 모듈 작동 확인 String temp = Serial.readStringUntil(‘
‘); Serial.println(temp); if (temp.startsWith(F(“AT”))) { temp.remove(0,3); Serial.println(temp); sendData(temp); } else if (temp == F(“1”)) { EEPROM.write(1023, 0); } } }
ESP01 펌웨어 업로드하기
웹 로그인 구현 코드상에 Soft AP로 연결된 상태를 확인하는 코드는 아래와 같다.
if (income_wifi.startsWith(F(“+”))) { if (income_wifi.startsWith(F(“+IPD”))) parsing = true; else if (income_wifi.startsWith(F(“+STA_CON”))) { connectedAP = true; Serial.println(F(“connectedAP”)); } else if (income_wifi.startsWith(F(“+STA_DIS”))) { connectedAP = false; Serial.println(F(“disconnectedAP”)); } }
상기 코드는 ESP01 펌웨어에서 Soft AP에 연결/종료 이벤트가 발생하면 시리얼 통신을 통해 아두이노로 보내주는 메시지 “+STA_CONNECTED / +STA_DISCONNECTED”를 확인하고 현재 Soft AP에서 연결된 상태인지 아닌지를 결정하는 코드이다. 따라서 ESP01의 펌웨어 프로그램에서 해당 메시지를 정상적으로 보내주지 않는다면 웹로그인 기능은 작동할 수 없게된다. 일부 펌웨어 버전이 탑제된 ESP01은 Soft AP 연결/종료 이벤트 발생시 해당 메세지를 전송하지 않는 오류가 있다고 한다. 만약 Soft AP로 연결을 했는데 시리얼 모니터에 “connectedAP”라는 메시지가 표시되지 않는다면 최신 펌웨어를 ESP01에 업로드해야 한다.
1. 아두이노에 EMPTY CODE 업로드
2. ESP01과 아두이노의 연결을 펌웨어 업로드용으로 변경
ESP01 TX -> 아두이노 TX
ESP01 RX -> 아두이노 RX
ESP01 VCC -> 아두이노 3.3V
ESP01 CH_PD -> 아두이노 3.3V
ESP01 GND -> 아두이노 GND
ESP01 GPIO0 -> 아두이노 GND
ESP01 RST -> 아두이노 GND 연결 대기
ESP01 핀맵
3. ESP01 펌웨어 / 펌웨어 업로드 프로그램 다운로드 및 압축 풀기
펌웨어 업로드 프로그램
펌웨어 V1.7.5_1
https://www.espressif.com/en/products/sdks/esp-at/resource
파일 경로상에 한글이 있으면 정상 작동하지 않으므로 다운로드한 펌웨어 / 업로드 프로그램은 C드라이브 또는 D드라이브에 복사하고 압축을 풀어준다.
펌웨어 업로드 프로그램 경로
펌웨어 경로
4. ESP01 설치되어있는 펨웨어 지우기
4-1. flash_download_tools_v3.6.5.exe를 실행하고 ESP8266 DownloadTool을 선택한다.
4-2. DownloadTool에서 아두이노가 연결된 COM PORT를 설정해준다. 만약 아두이노 IDE의 시리얼 모니터가 열려있다면 닫아준다.
아두이노 IDE의 COM 포트 확인
4-3. ESP01을 업로드 모드로 전환하고 지우기
ESP01의 RST핀에 연결해놓은 선을 아두이노 GND에 1초 정도 연결한 뒤 떼면 ESP01에 내장되어 있는 파란색 LED가 켜졌다 꺼지면서 업로드 모드로 전환된다. 파란색 LED가 켜졌다 꺼지지 않으면 업로드할 수 없다. ESP01과 아두이노의 연결이 잘못되었거나 아두이노에 EMPTY CODE가 업로드되지 않았을 수 있다. ERASE 버튼을 클릭한다.
정상적으로 펌웨어가 지워지면 아래와 같은 메시지와 함께 FINISH라고 표시된다.
만약 아래 사진처럼 점선이 표시된다면 정상적으로 진행되지 않고 있다는 것이다. 이때는 STOP을 누르고 COM PORT를 확인하거나 “업로드 모드”로 전환하기를 다시 한 뒤 해본다. 펌웨어 지우기를 할 수 없다면, 펌웨어 업로드도 할 수 없게 된다.
5. 펌웨어 설정 경로 확인하고 설정하기
D:\ESP8266_NonOS_AT_Bin_V1.7.5_1\ESP8266_NonOS_AT_Bin_V1.7.5\bin\at 경로의 README.md 파일을 메모장으로 열어보면 아래와 같은 경로 설정을 확인할 수 있다.
### Flash size 8Mbit: 512KB+512KB
boot_v1.2+.bin 0x00000
user1.1024.new.2.bin 0x01000
esp_init_data_default.bin 0xfc000
blank.bin 0x7e000 & 0xfe000
설정 방법에 따라 아래와 같이 순서대로 경로 창에 입력해 준다.
1.D:\ESP8266_NonOS_AT_Bin_V1.7.5_1\ESP8266_NonOS_AT_Bin_V1.7.5\bin\boot_v1.7.bin을 선택하고 우측에 “0x00000″을 입력.
2.D:\ESP8266_NonOS_AT_Bin_V1.7.5_1\ESP8266_NonOS_AT_Bin_V1.7.5\bin\at\512+512\user1.1024.new.2.bin을 선택하고 우측에 “0x01000″을 입력.
3.D:\ESP8266_NonOS_AT_Bin_V1.7.5_1\ESP8266_NonOS_AT_Bin_V1.7.5\bin\esp_init_data_default_v08.bin을 선택하고 우측에 “0xfc000″을 입력.
4.D:\ESP8266_NonOS_AT_Bin_V1.7.5_1\ESP8266_NonOS_AT_Bin_V1.7.5\bin\blank.bin을 선택하고 우측에 “0x7e000″을 입력. 그 아래 같은 파일을 한번 더 선택하고 우측에 “0xfe000″을 입력
입력한 다섯 개 항목의 체크박스에 체크를 해준다.
6. 설정이 완료됐으면 SPI SPEED: 40MHz, SPI MODE: QIO, FLASH SIZE: 8Mbit를 추가로 설정해주고
4-1 업로드 모드로 전환하기를 다시 실행한 뒤 “START” 버튼을 클릭
업로드 모드는 펌웨어 지우기 또는 펌웨어 업로드의 시도가 있은 후에는 그 성공 여부에 상관없이 초기화되므로 매번 업로드 모드로 전환한 후에 실행해야함.
펌웨어 업로드가 완료되면 ESP01 모듈의 보드 레이트는 초기값인 115200으로 변경된다. 아두이노에서 사용할 수 있도록 보드 레이트를 9600으로 변경해주어야 한다.
현재 아두이노에는 EMPTY CODE가 업로드 되어 있다. 이 상태에서 아두이노 IDE의 시리얼 모니터를 열고 보드 레이트는 115200, 전송옵션은 “Both NL & CR”로 설정한 뒤에 현재 아두이노 GND에 연결되어 있는 GPIO0핀의 연결을 해제한다. GPIO0핀이 연결해제된 상태에서 RST핀을 아두이노의 GND핀에 연결했다 해제하면 시리얼 모니터에 아래와 같이 “ready”라는 메시지가 출력된다.
시리얼 모니터 입력창에 “AT+UART_DEF=9600,8,1,0,0″를 입력하고 엔터를 치면 “OK”라는 메세지가 출력되고 ESP01의 보드레이트는 9600으로 변경된다.
보드 레이트가 9600으로 변경되었으므로 시리얼 모니터의 보드 레이트를 9600으로 변경한 뒤 시리얼 모니터 입력창에 “AT”를 입력하고 엔터를 치면 “OK”라는 메시지를 확인 할 수 있다.
이제 펌웨어 업로드와 보드 레이트 변경까지 완료 하였다. 아두이노와 ESP01의 연결을 이전으로(제어용) 변경해 준다.
기상청 및 오픈 웨더 맵에서 날씨 정보 받기
기상청
스케치는 프로그램 저장 공간 13142 바이트(40%)를 사용. 최대 32256 바이트.
전역 변수는 동적 메모리 437바이트(21%)를 사용, 1611바이트의 지역변수가 남음. 최대는 2048 바이트.
#include
#define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[21] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; String ap = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ap = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ap); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r “); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“CWQIF”)); // disconnect AP if connected sendData(F(“CWQAP”)); // disconnect wifi if connected sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address } // http://www.kma.go.kr/wid/queryDFSRSS.jsp?zone=1159068000 const char host[] PROGMEM = “www.kma.go.kr”; const char url[] PROGMEM = “/wid/queryDFSRSS.jsp?zone=1159068000”; bool OK200 = false; bool sentREQ = false; bool gotWeather = false; void get_weather() { if (!sentREQ) { Serial.println(F(“Starting connection to server…”)); bool connectOK = false; String cip = F(“AT+CIPSTART=3,”); // connection ID 3 (ID: 0 ~ 4) cip += ‘”‘; cip += F(“TCP”); cip += ‘”‘; cip += ‘,’; cip += ‘”‘; cip += (const __FlashStringHelper *)host; cip += ‘”‘; cip += ‘,’; cip += F(“80”); // port number cip += F(“\r
“); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { connectOK = true; Serial.println(F(“OK”)); break; } else if (cip.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } } if (connectOK) { Serial.println(F(“Connected to server”)); String temp = F(“GET “); temp += (const __FlashStringHelper *)url; temp += F(” HTTP/1.1\r
Host: “); temp += (const __FlashStringHelper *)host; temp += F(“\r
Connection: close\r
\r
“); cip = F(“AT+CIPSEND=”); cip += 3; // connection ID 3 (ID: 0 ~ 4) cip += ‘,’; cip += temp.length(); cip += F(“\r
“); esp01.print(cip); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“OK”)); break; } else if (cip.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } } esp01.print(temp); sentREQ = true; gotWeather = true; } } } // RSS 날씨 정보 저장 변수 // RSS 날씨 정보 저장 변수 String line0 = “”; String line1 = “”; uint8_t count = 0; // RSS 날씨 정보 분류 카운터 uint8_t tryCount = 0; // 온도 저장 변수 float temp0; float temp1; void parsing() { String announce_time; int tm_start= line0.indexOf(F(“
“)); // “ “문자가 시작되는 인덱스 값(‘<'의 인덱스)을 반환한다. int tm_end= line0.indexOf(F(" “)); announce_time = line0.substring(tm_start + 4, tm_end); // +4: ““스트링의 크기 4바이트, 4칸 이동 Serial.print(F(“announce_time: “)); Serial.println(announce_time); String hour; int hour_start= line0.indexOf(F(“ “)); int hour_end= line0.indexOf(F(“ “)); hour = line0.substring(hour_start + 6, hour_end); Serial.print(F(“hour: “)); Serial.println(hour); String temp; int temp_start= line0.indexOf(F(““)); int temp_end= line0.indexOf(F(“ “)); temp = line0.substring(temp_start + 6, temp_end); Serial.print(F(“temp: “)); Serial.println(temp); temp0 = temp.toFloat(); // 자료형 변경 String -> float Serial.print(F(“temp0: “)); Serial.println(temp0); String wfEn; int wfEn_start= line0.indexOf(F(““)); int wfEn_end= line0.indexOf(F(“ “)); wfEn = line0.substring(wfEn_start + 6, wfEn_end); Serial.print(F(“weather: “)); Serial.println(wfEn); line0 = “”; // 스트링 변수 line0 데이터 추출 완료 Serial.println(); hour_start= line1.indexOf(F(““)); hour_end= line1.indexOf(F(“ “)); hour = line1.substring(hour_start + 6, hour_end); Serial.print(F(“hour: “)); Serial.println(hour); temp_start= line1.indexOf(F(““)); temp_end= line1.indexOf(F(“ “)); temp = line1.substring(temp_start + 6, temp_end); Serial.print(F(“temp: “)); Serial.println(temp); temp1 = temp.toFloat(); // 자료형 변경 String -> float Serial.print(F(“temp1: “)); Serial.println(temp1); wfEn_start= line1.indexOf(F(““)); wfEn_end= line1.indexOf(F(“ “)); wfEn = line1.substring(wfEn_start + 6, wfEn_end); Serial.print(F(“weather: “)); Serial.println(wfEn); line1 = “”; // 스트링 변수 line1 데이터 추출 완료 } bool header = false; void loop() { if (!ip.startsWith(F(“0”))) { // 공유기로부터 IP주소를 할당받은 경우 if (!gotWeather) { if (tryCount < 3) { get_weather(); tryCount++; } } } if (sentREQ) { // 날씨 정보가 들어오는 동안 if (!OK200) { if (esp01.find('+')) { line0 = esp01.readStringUntil(' '); if (line0.indexOf(F("200")) != -1) OK200 = true; line0 = ""; } else { // gotWeather = true; -> 날씨 작업 종료 후 나머지 데이터 삭제 line0 = esp01.readStringUntil(‘‘); if (line0.endsWith(F(“D”))) { if (line0.endsWith(F(“CLOSED”))) sentREQ = false; // HTTP connection closed } } } else { if (!header) { line0 = esp01.readStringUntil(‘
‘); if (line0.indexOf(F(“
“)) != -1) { header = true; line0 = “”; } } else { bool finish = false; while (esp01.available()) { char c = esp01.read(); if (c == ‘<') count++; if (count <= 50) line0 += c; else if (count > 50 && count <= 90) line1 += c; else if (count > 90) { finish = true; break; } } if (finish) { Serial.println(F(“Finished Reading”)); Serial.println(line0); Serial.println(line1); parsing(); gotWeather = true; // 날씨 작업 종료 count = 0; header = false; OK200 = false; tryCount = 0; // 초기화 sentREQ = false; } } } } else { // 날씨 이외의 경우 if (esp01.available()) { line0 = esp01.readStringUntil(‘ ‘); Serial.println(line0); } } }
OPEN WEATER MAP
스케치는 프로그램 저장 공간 10142 바이트(31%)를 사용. 최대 32256 바이트.
전역 변수는 동적 메모리 407바이트(19%)를 사용, 1641바이트의 지역변수가 남음. 최대는 2048 바이트.
#include
#define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[21] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; String ap = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ap = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ap); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r “); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“CWQIF”)); // disconnect AP if connected sendData(F(“CWQAP”)); // disconnect wifi if connected sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address } String json_parser(String s, String a) { String val; if (s.indexOf(a) != -1) { int st_index = s.indexOf(a); int val_index = s.indexOf(‘:’, st_index); if (s.charAt(val_index + 1) == ‘”‘) { int ed_index = s.indexOf(‘”‘, val_index + 2); val = s.substring(val_index + 2, ed_index); } else { int ed_index = s.indexOf(‘,’, val_index + 1); val = s.substring(val_index + 1, ed_index); } } else { Serial.print(a); Serial.println(F(” is not available”)); } return val; } // OPEN WEATHER MAP // https://api.openweathermap.org/data/2.5/weather?q=Seoul,KR&APPID=YOUR_API_KEY const char host[] PROGMEM = “api.openweathermap.org”; const char url[] PROGMEM = “/data/2.5/weather?q=Seoul,KR&APPID=YOUR_API_KEY”; // YOUR_API_KEY 수정 bool OK200 = false; bool sentREQ = false; bool gotWeather = false; void get_weather() { Serial.println(F(“Starting connection to server…”)); bool connectOK = false; String cip = F(“AT+CIPSTART=3,”); // connection ID 3 (ID: 0 ~ 4) cip += ‘”‘; cip += F(“TCP”); cip += ‘”‘; cip += ‘,’; cip += ‘”‘; cip += (const __FlashStringHelper *)host; cip += ‘”‘; cip += ‘,’; cip += F(“80”); // port number cip += F(“\r
“); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { connectOK = true; Serial.println(F(“OK”)); break; } else if (cip.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } } if (connectOK) { Serial.println(F(“Connected to server”)); String temp = F(“GET “); temp += (const __FlashStringHelper *)url; temp += F(” HTTP/1.1\r
Host: “); temp += (const __FlashStringHelper *)host; temp += F(“\r
Connection: close\r
\r
“); cip = F(“AT+CIPSEND=”); cip += 3; // connection ID 3 (ID: 0 ~ 4) cip += ‘,’; cip += temp.length(); cip += F(“\r
“); esp01.print(cip); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘
‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“OK”)); break; } else if (cip.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } } esp01.print(temp); sentREQ = true; gotWeather = true; } } // RSS 날씨 정보 저장 변수 String line = “”; uint8_t tryCount = 0; void loop() { if (!ip.startsWith(F(“0”))) { // 공유기로부터 IP주소를 할당받은 경우 if (!gotWeather) { if (tryCount < 3) { get_weather(); tryCount++; } } } while (esp01.available()) { line = esp01.readStringUntil(' '); Serial.println(line); if (sentREQ) { if (!OK200) { if (line.startsWith(F("+"))) { if (line.indexOf(F("200")) != -1) OK200 = true; else { OK200 = false; gotWeather = false; } } } else { if (line.startsWith(F("{"))) { Serial.println(line); Serial.println(F("weather data for parsing")); String description = json_parser(line, F("description")); Serial.print(F("description: ")); Serial.println(description); String pressure = json_parser(line, F("pressure")); Serial.print(F("pressure: ")); Serial.println(pressure); String wind = json_parser(line, F("speed")); Serial.print(F("wind: ")); Serial.println(wind); String Temp = json_parser(line, F("temp")); Serial.print(F("Temp: ")); Serial.println(Temp); line = ""; gotWeather = true; // 날씨 작업 종료 tryCount = 0; OK200 = false; sentREQ = false; // 초기화 } } } else { Serial.println(line); } } } 날씨 코드 설명 : [arduino] - 아두이노 - ESP01 모듈, 기상청 RSS / 오픈 웨더 맵 API 날씨 정보 받기 참조사이트 http://allaboutee.com/2014/12/30/esp8266-and-arduino-webserver/ https://room-15.github.io/blog/2015/03/26/esp8266-at-command-reference/ 관련 글 [arduino] - 아두이노 - 안드로이드를 이용한 무선 원격제어 그리고 시리얼 통신 - 1편 [arduino] - 아두이노 - 안드로이드를 이용한 무선 원격제어 그리고 시리얼 통신 - 2편 [arduino] - 아두이노 - 안드로이드를 이용한 무선 원격제어 그리고 시리얼 통신 - 3편 [arduino] - 아두이노 - 안드로이드를 이용한 무선 원격제어 그리고 시리얼 통신 - 4편 [arduino] - 아두이노 - 안드로이드를 이용한 무선 원격제어 그리고 시리얼 통신 - 5편 [arduino] - 블루투스 4.0 BLE 이용 아두이노 및 ESP32 원격제어 [arduino] - 아두이노 - 시리얼통신 주요 함수와 예제, String class [arduino] - 아두이노 - ESP01 wifi 모듈 무선 원격제어 그리고 시리얼 통신 - 6편 [arduino] - ESP8266 - NodeMcu 1.0 와이파이 이용 원격제어(soft AP, wifi) [arduino] - ESP32 - Dev Module 와이파이 이용 원격제어(soft AP, wifi) [arduino] - 아두이노 - 와이파이 모듈 ESP01, WiFiEsp.h 라이브러리 이용 웹페이지에서 디지털핀 원격제어 arduino bluetooth controller PWM - 아두이노 원격제어 안드로이드 앱 버전 3.5 다운로드 arduino bluetooth controller PWM 매뉴얼
아두이노와 ESP8266으로 wifi에 연결해서 웹서버 만드고, 센서값 출력하기
<목표>
– 몇년 전부터 아두이노를 통한 IoT 개발이 정말 많이 이루어지고 있다.
자료가 많이 없어서 이렇게 글을 써보려 한다.
아두이노에 ESP8266 모듈을 장착하면 아두이노로 wifi연결을 통해 인터넷에 접속할 수 있다.
그리고 웹 서버도 만들 수 있는데, 이 웹서버를 통해서 센서값 등을 표현시킬 수도 있다.
그 방법을 한번 알아보자.
<준비물>
아두이노, ESP8266 모듈,
또는 아두이노 NodeMCU 같은 ESP8266이 포함된 개발보드,
CDS센서
LED
<회로도>
아날로그 0번에서 CDS 센서값을 읽어오고,
주변이 밝으면 LED를 끄고,
어두우면 LED를 키는 회로를 구성하였다.
필자는 NODE MCU를 이용해서 회로를 구성하였다.
아두이노에 ESP8266 wifi 모듈을 연결하면 똑같이 사용 가능하다.
<코드>
코드 작성에 앞서서
일단 아두이노(프로그램) 세팅을 해주어야 한다.
아두이노 환경설정에서
추가적인 보드 맨니저 URL 을 추가해주어야 한다.
http://arduino.esp8266.com/stable/package_esp8266com_index.json
위의 주소를 추가하면 된다.
그리고 툴>보드>보드매니저 에 들어가서
위의 최신 버전을 설치해주면 된다.
#include
const char* ssid = ” “; // 사용 중 인 와이파이 이름 const char* password = ” “; // 와이파이 패스워드 WiFiServer server(80); void setup() { pinMode(A0,INPUT); pinMode(LED_BUILTIN, OUTPUT); pinMode(12, OUTPUT); Serial.begin(115200); // 시리얼 통신, 속도 115200 delay(10); Serial.println(); // Connect to WiFi network WiFi.mode(WIFI_STA); Serial.println(); Serial.println(); Serial.print(“Connecting to “); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(100); Serial.print(“.”); } Serial.println(“”); Serial.println(“WiFi connected”); // Start the server server.begin(); Serial.println(“Server started”); // Print the IP address Serial.println(WiFi.localIP()); } void loop() { int val = analogRead(A0); // cds 센서값 저장 delay(50); Serial.println(val); WiFiClient client = server.available(); client.println(“HTTP/1.1 200 OK”); client.println(“Content-Type: text/html”); client.println(“Connection: close”); client.println(“Refresh: 1”); // 자동으로 웹페이지 새로고침 (1초 설정) client.println(); client.println(““); client.println(““); client.println(“ “); //client.println(““); //client.println(“
“); client.println(“
DIYver tistory blog test “); // 웹 서버 페이지 제목 설정 client.println(“ “); client.println(““); client.println(“ Node MCU Sensor Test
“); // 페이지 내용 설정 if (val < 250 ) { client.print("DARK !
“); client.println(“
“); client.println(“LED ON
“); client.println(“
“); client.println(“Sensor Value
“); client.println(val); digitalWrite(LED_BUILTIN, LOW); // LED ON digitalWrite(12, HIGH); // LED ON } else { client.print(“BRIGHT
“); client.println(“
“); client.print(“LED OFF
“); client.println(“
“); client.println(“Sensor Value
“); client.println(val); digitalWrite(LED_BUILTIN, HIGH); // LED OFF digitalWrite(12, LOW); // LED OFF } client.println(“
“); client.println(“
“); client.println(“블로그 주소 https://diyver.tistory.com
“); // 페이지 내용 설정 client.println(“"); client.print(""); }
제일 중요한 것은 윗 줄에 쓴
wifi ssid와 password 를 잘 적어주어야 하다는 것이다.
큰 따옴표 안에 직접 입력해두면 된다.
<실행 결과>
코드 실행은 위의 시연 영상을 확인하면 된다.
아두이노로 wifi에 접속해서 웹서버를 만들었고,
자신이 원하는 제목과 글을 출력할 수 있으며,
실시간으로 센서값을 출력할 수 있는 것을 확인할 수 있다.
참고로 만들어진 웹서버 주소는 공유기를 통해서 알아도 되지만,
코드를 업로드 할 때, 시리얼 모니터를 켜놓고 하면 만들어진 웹서버 주소가 뜨게 된다.
이처럼 아두이노와 ESP8266 모듈만 있더라도 간단한 웹서버를 만들어서 시제품 테스트를 진행할 수 있다.
또한 안드로이드와 IOS 어플을 개발하고,
웹서버에 올라와있는 데이터 값을 불러와서 사용할 수 있다.
웹서버 내용은 HTML 을 따른는데,
우리가 컴퓨터로 다루는 HTML에 비하면 사용할 수 있는 것이 제한적이다.
일단 이미지를 올리지 못한다는 것이 좀 단점이다.
다른 방법이 있겠지만, 쉽지가 않다는 뜻이다.
아두이노 코딩 다루기도 벅찬데 HTML 까지 알아야 하다니;;
아무튼 이정도만 알아도 어지간한 상황에서 구현하고 싶은 것들은 다 구현할 수 있다.
※ 궁금하시거나 질문사항이 있으시면 댓글로 작성해주시면 답변해 드릴 수 있는 부분에서 친절히 답변드리겠습니다!
25. 와이파이 연결하기
와이파이 모듈 ESP-01
모듈연결하기
보드레이트 변경하기
공유기 연결하기
1) 와이파이 모듈 ESP-01 ( ESP8266 )
와이파이 모듈을 사용해 인터넷에 접근하여 여러가지 센서의 값을 관리하거나 액추에이터를 작동시킬 수 있습니다.
2) 모듈연결하기
ESP-01 pin map
TX -> 아두이노 RX (2번핀) GND -> 아두이노 GND CH_PD -> 아두이노 3.3V VCC -> 아두이노 3.3V RX -> 아두이노 TX (3번핀)
3) 보드레이트 변경하기
시리얼 모니터를 사용하기 위해서는 보드레이트를 9600 으로 변경해야합니다.
보드레이트를 변경하기 위해선 시리얼 모니터 입력창에 AT+UART_DEF=9600,8,1,0,0 을 입력해야 합니다.
우선 위의 사진처럼 창 아래의 보드레이트가 115200인 보드레이트의 연결을 확인하기 위해
AT을 입력합니다.
OK 가 뜬다면 ESP-01과 연결이 잘 된것 입니다. 이제 보드레이트를 바꿔봅시다!!
시리얼 모니터 입력창에 AT+UART_DEF=9600,8,0,0 를 그대로 입력하면 보드레이트를 9600 으로 변경할 수 있습니다.
아래처럼 OK 응답이 표시 된다면 ESP-01의 보드레이트가 9600으로 변경된 것입니다.
ESP-01의 보드레이트가 9600 으로 변경되었으니 소스코드의 Serial.begin(115200) 을 Serial.begin(9600) 으로 바꾸고
다시 업로드해주어야 합니다.
시리얼 모니터 화면 가장 아래의 보드레이트를 9600 으로 변경한 뒤 AT를 입력하여 연결을 확인하면 통신준비가 완료된 것 입니다.
4) 공유기 연결하기
AT+RST // ESP-01 리셋
AT+CWMODE=2
// 1 = Station mode (client), 2 = AP mode (host), 3 = AP + Station mode
AT+CWSAP="esp01","1234test",5,3
// AT+CWSAP= softAP SSID, Password, channel id, ecn
// ecn(보안설정) : 0 = OPEN, 2 = WPA_PSK, 3 = WPA2_PSK, 4 = WPA_WPA2_PSK
접속속도 변경하기
AT+UART_DEF=9600,8,1,0,0
5) ESP-01 AT명령어
AT : "Attention"의 약어
AT+RST : 모듈 리셋
AT+GMR : 버전 확인
AT+CWMODE? : 모드 확인
AT+CWMODE=mode : mode는 1 : Station 모드, 2 : AP 모드, 3 : AP+Station 모드
AT+CWLAP : AP 리스트 확인
AT+CWJAP? : 접속 AP 확인
AT+CWJAP="ssid","password" : AP 접속 명령
AT+CWQAP : AP 접속 해제 명령
AT+CWSAP? : AP 정보 출력
AT+CWSAP="ssid","password","채널","보안방식" : 0 : OPEN, 2 : WPA_PSK, 3 : WPA2_PSK, 4 : WPA_WPA2_PSK
AT+CWDHCP : DHCP 설정(AP mode)
AT+CIPSTAMAC : MAC 설정(Station Mode)
AT+CIPAPMAC : MAC 설정(AP Mode)
AT+CIPSTA : IP 어드레스 설정(Station Mode)
AT+CIPAP : IP 어드레스 설정(AP Mode)
AT+CIPSTATUS : 접속정보
AT+CIPSTART : TCP 또는 UDP 포트 설정/연결
AT+CIPSEND : 데이터 전송
AT+CIPCLOSE : TCP 또는 UDP 접속 해제
AT+FSR : 로컬 IP 취득
AT+CIPMUX : 다중접속 설정
AT+CIPSERVER : 서버설정
AT+CIPMODE : 전송모드 설정
AT+CIPSTO : 서버 타임아웃 설정
AT+CIUPDATE : 네트워크를 통한 업데이트
AT+IPR : ESP 모듈의 Baud rate 설정
참조: https://postpop.tistory.com/23[postpop]
So you have finished reading the 아두 이노 와이파이 데이터 전송 topic article, if you find this article useful, please share it. Thank you very much. See more: 아두이노 데이터 전송, 아두이노 와이파이 통신 거리, 아두이노 esp8266, 아두이노 wifi 모듈, 아두이노 와이파이 연결, 와이파이 모듈이란, 아두이노 esp8266 웹서버