延續前一個案例「以ESP8266的AT命令建立HTTP服務」中, 我們很容易透過ESP-01模組的AT命令來建立HTTP伺服器, 也知道web browser與ESP-01模組背後是如何溝通運作的. 本案例電路部份以「與 ESP8266 的第一次接觸」為基礎, 在所有接線都不變的前提下再追加一個「溫濕度感測器」來展示以ESP-01模組為IoT控制中心的方法, 概念如下圖.
溫濕度感測器測試
Maker喜歡用「溫濕度感測器」來展示以IoT控制的應用, 因為它非常簡單又適合達到展示物聯網的效果. 筆者的溫濕度感測器型號是DHT11, 只有三隻腳分別為Data、Vdd與Gnd, 如下圖所示.
依照規格Vdd可接受3V~5V的電壓輸入, 而本例直接引用前例Arduino的3.3V輸出(紅色線). 圖中黑色為Gnd, 而白色為Data. 整個系統看起來如下圖, 在ESP-01模組後面多了另一位主角(DHT11).
細部接線
整個系統接法相當簡單, Vcc(3.3V)與Gnd直接share之前給ESP-01模組的麵包板排線, 而Data我們任意指定一根Arduino上還未使用的數位腳即可, 例如本例為Pin5(下圖藍色接線).
DHT11模組測試
我們需要先測試一下DHT11模組是否能正常工作, 測試程式相當簡單. 本例我們使用現成的DHT11模組函式庫, 可以至https://github.com/adafruit/DHT-sensor-library下載原始檔並將其複製到Arduino IDE路徑下的libraries目錄即可. 例如, $IDE_ROOT\arduino-1.8.2 \libraries\DHT-sensor-library-master
(其中DHT_U.*我們用不到, 請將其刪除). 下面範例程式每隔10秒透過DHT11讀取溫濕度並透過串列埠監控窗顯示.
#include "DHT.h"
// package required
from https://github.com/adafruit/DHT-sensor-library
DHT dht(5, DHT11); // digital pin5
connected to the DHT11
void setup() {
Serial.begin(115200);
Serial.println("DHT11 start
...");
dht.begin();
}
void loop() {
delay(10000); // measure humidity and
temperature per 10 seconds
float h = dht.readHumidity(); // Reading temperature or humidity
takes about 250 milliseconds
float t = dht.readTemperature(); // Read temperature
as Celsius (the default)
Serial.print("Humidity: ");
Serial.print(h);
Serial.println(" %\t");
Serial.print("Temperature: ");
Serial.print(t);
Serial.println(" *C");
}
|
Arduino程式
筆者的Arduino IDE開發環境是1.8.2 ZIP免安裝版. 程式部份我們以前一個案例「以ESP8266的AT命令建立HTTP服務」為基礎, 並將上述DHT11的程式碼整合在一起. 在啟動ESP-01為AP模式前, 我們先啟動DHT11模組並等待約1~2秒. 我們主要修改了sendHTML函式, 於讀取溫度與濕度內容之後將兩筆值打包成HTML格式並回傳給clien(由ESP-01), 其它大部分程式內容不變. HTML部份我們透過<meta http-equiv="refresh"
content="10">標籤讓client端每隔10秒對我們的HTTP伺服器重新提出更新需求, 因此也同時更新了溫度與濕度的內容.
#include <SoftwareSerial.h>
#include "DHT.h" // package required from
https://github.com/adafruit/DHT-sensor-library
DHT dht(5, DHT11); // digital pin5 connected to the DHT11
SoftwareSerial
ESP(3, 2); // ESP8266 ESP-01: Tx, Rx
void setup() {
Serial.begin(115200);
dht.begin();
delay(2000); // Sensor readings may be up to 2 seconds
Serial.println("DHT11 start ...");
ESP.begin(115200);
Serial.println("\nInitialize ESP-01 ...");
sendATcmd("AT+RST\r\n",3000); // reset
ESP-01
sendATcmd("AT+CWMODE=2\r\n",2000); // config ESP-01
as AP mode
//sendATcmd("AT+CWMODE?\r\n",1000); // check
AP mode
//sendATcmd("AT+GMR\r\n",1000); // check firmware version
sendATcmd("AT+CIFSR\r\n",2000); // check IP
sendATcmd("AT+CIPMUX=1\r\n",2000); // allow multiple
access
sendATcmd("AT+CIPSERVER=1,80\r\n",2000); // start server at port:80
Serial.println("\nServer started at
port 80 ...");
}
void setDelay(unsigned int delay) {
unsigned long timeout = delay+millis();
while( millis()<timeout ) {} // NOP
}
void sendATcmd(char* cmd, unsigned int
delay) {
ESP.print( cmd ); // send AT command to
ESP-01
setDelay(delay);
}
void sendHTML(byte connID,char* msg) {
extern int connCount;
String html;
char cipSend[128];
char cipClose[128];
float h = dht.readHumidity(); // Reading
temperature or humidity takes about 250 milliseconds
float t = dht.readTemperature(); // Read temperature as Celsius (the default)
html += "<html><head>";
html += "<meta http-equiv=\"refresh\"
content=\"10\">";
html +="<title>From
ESP-01</title></head><body>\n\r";
html += "<p>ClientMsg: ";
html += msg;
html += "</p>\n\r";
html += "<p>Humidity:";
html += h;
html += "%</p>\n\r";
html +=
"<p>Temperature:";
html += t;
html += "*C</p>\n\r";
html +=
"</body></html>";
Serial.println(html);
sprintf(cipSend,"AT+CIPSEND=%d,%d\r\n",connID,html.length());
sprintf(cipClose,"AT+CIPCLOSE=%d\r\n",connID);
sendATcmd(cipSend,1000);
sendATcmd(html.c_str(),1000);
sendATcmd(cipClose,1000);
}
void loop() {
// send AT command to ESP-01 form console
(serial)
if ( Serial.available() ) {
ESP.write( Serial.read() );
}
if ( ESP.available() ) { // receive message
from ESP-01
if ( ESP.find("+IPD,") ) { //
detect the client's request
String msg="";
byte connID = ESP.read()-48; // client's connection ID
while( ESP.available() ) { // collect client's request from the web browser
msg += (char)ESP.read();
delay(20); // the delay will let the message become more stable
}
sendHTML(connID,msg.c_str()); // send HTML message to client
Serial.flush();
}
}
}
|
同場加映LED燈控制
我們於前面的例子中已經知道, 客戶端(client)的web browser可以透過GET方式順便傳送簡單的指令到ESP-01模組所扮演的HTTP server.
因此上面的程式只要稍作修改, 我們就能看到透過客戶端的web browser做遠程控制LED燈的效果. 概念上如下圖所示, 透過電腦或手機的web browser下指令給ESP-01並點亮/熄滅LED燈.
為了不增加任何硬體線路, 我們選擇Arduino內建的LED燈做示範. 在setup步驟, 我們將built-in LED燈腳重新規劃為output. 追加的程式碼以橙色文字表示, 主要是透過sendHTML呼叫時, 在將原本客戶端傳送進來的訊息打包成HTML之前判斷是否有「GET /led=?」開頭的字串. 若有則判斷下一個字元為0或1的值(字元減去48), 並將該值寫到built-in LED的腳位(1為點亮, 0為熄滅).
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // to demonstrate the argument passed in GET method
Serial.begin(115200);
dht.begin();
delay(2000); // Sensor readings may be up to
2 seconds
Serial.println("DHT11 start ...");
ESP.begin(115200);
Serial.println("\nInitialize ESP-01 ...");
sendATcmd("AT+RST\r\n",3000); // reset
ESP-01
sendATcmd("AT+CWMODE=2\r\n",2000); // config ESP-01
as AP mode
//sendATcmd("AT+CWMODE?\r\n",1000); // check
AP mode
//sendATcmd("AT+GMR\r\n",1000); // check firmware version
sendATcmd("AT+CIFSR\r\n",2000); // check IP
sendATcmd("AT+CIPMUX=1\r\n",2000); // allow multiple
access
sendATcmd("AT+CIPSERVER=1,80\r\n",2000); // start server at port:80
Serial.println("\nServer started at
port 80 ...");
}
void sendHTML(byte connID,char* msg) {
extern int connCount;
String html;
char cipSend[128];
char cipClose[128];
float h = dht.readHumidity(); // Reading temperature or humidity takes about 250
milliseconds
float t = dht.readTemperature(); // Read
temperature as Celsius (the default)
char* p;
int led = 0; // built-in LED value
if ( (p=strstr(msg,"GET
/led="))!=NULL ) { // receive LED
control form client with GET method
*(p+10) = '\0'; // remove the rest message
led = (int)p[9]-48; // get LED value
digitalWrite(LED_BUILTIN, led);
delay(1000);
}
html += "<html><head>";
html += "<meta
http-equiv=\"refresh\" content=\"10\">";
html +="<title>From
ESP-01</title></head><body>\n\r";
html += "<p>
html += (++connCount);
html +=
"</p>\n\r";
html += "<p>ClientMsg: ";
html += msg;
html += "</p>\n\r";
html += "<p>Humidity:";
html += h;
html += "%</p>\n\r";
html +=
"<p>Temperature:";
html += t;
html += "*C</p>\n\r";
html +=
"<p>LED: ";
html += led;
html += "</p>\n\r";
html += "</body></html>";
Serial.println(html);
sprintf(cipSend,"AT+CIPSEND=%d,%d\r\n",connID,html.length());
sprintf(cipClose,"AT+CIPCLOSE=%d\r\n",connID);
sendATcmd(cipSend,1000);
sendATcmd(html.c_str(),1000);
sendATcmd(cipClose,1000);
}
|