使用snprintf()函式轉換動態字串、輸出ESP8266溫濕度網頁

本文旨在補充《超圖解物聯網IoT實作入門》第十二章「使用ESP8266WebServer程式庫建立HTTP伺服器」,示範運用C語言的snprint()函式,將動態字串轉換成字元陣列,在ESP8266控制板(如:NodeMCU或Wemos D1 mini)輸出HTML網頁。

底下是本文的靜態HTML網頁內容,它將在瀏覽器上顯示虛構的溫度和濕度值:

HTML碼

HTML裡的溫度和濕度數字,實際將由程式動態填入DHT11感測器的感測值。程式首先設置一個空白的字元陣列,預備填入HTML內容,提供給ESP8266WebServer的send()方法傳給用戶端。

筆者假設網頁內容約佔700字元(含字串結尾的’\0’):

char htmlStr[700]; 

snprintf()函式語法

假設DHT11感測的溫度和濕度值,分別存在temp與humid變數。那麼,整合上面的HTML網頁文字和temp, humid變數,並轉存成字元陣列的snprintf()函式語法格式,以及程式片段如下:

snprintf()函式格式

snprintf()函式的「字元數」參數,請設定成和「字元陣列」的元素數量相同;「字串」參數內容若要分成數行,則每一行的結尾都要加上「行結尾符號」。

「字串」參數值相當於「樣板」,其中要被替換動態內容,必需用「格式字元」標示。格式字元用%符號開頭,後面加上資料類型代碼,例如,%d代表「此處將填入整數資料」。

下表列舉幾個常見的格式字元,受限於微控板的記憶體容量,Arduino版的snprintf()函式無法實現個人電腦版本的所有功能,像Arduino版並不支援%f浮點數字格式字元。

格式字元 說明
d或i 帶正負號的整數
u 無正負號的整數
c 字元
s 字串
f 浮點數字

若需要把浮點數字轉換成字串,請使用dtostr()函式(參閱《超圖解Arduino 互動設計入門》16-15頁)。

ESP8266控制板設置AP模式、顯示溫濕度網頁

本文的ESP8266完整程式碼如下,DHT11感測器的數位輸出接第5腳(D1):

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <dht11.h>

#define DHT11PIN 5  // DHT11輸出接第5腳

ESP8266WebServer server(80); // HTTP伺服器物件
dht11 DHT11;                 // DHT11感測器物件

IPAddress apIP(192, 168, 4, 3);  // 設定AP模式的IP位址;預設是192.168.4.1。
const char *ssid = "ESP8266";      // AP模式的Wi-Fi熱點名稱
const char *password = "12345678"; // Wi-Fi密碼
int humid = 0;  // 溫度整數
int temp = 0;   // 濕度整數

void rootRouter() {
  server.send(200, "text/html", "<p>Hello from <b>ESP8266</b>!</p>");
}

void setup() {
  WiFi.mode(WIFI_AP);   // 啟用AP模式
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));  // 設定微控器的IP位址
  WiFi.softAP(ssid, password);  // 設定Wi-Fi的識別名稱和密碼

  Serial.begin(9600);
  Serial.println();

  pinMode(DHT11PIN, INPUT);
  
   server.on("/temp", []() {   // 設定 '/temp' 路徑的路由
   int chk = DHT11.read(DHT11PIN);
   
   if (chk == 0) {
     char htmlStr[700];
     humid = DHT11.humidity;
     temp = DHT11.temperature;
     
     snprintf ( htmlStr, 700,
      "<html>\
       <head>\
         <meta charset='utf-8'/>\
         <meta http-equiv='refresh' content='5'/>\
         <meta name='viewport' content='width=device-width;\
             initial-scale=1.0;\
             maximum-scale=1.0;\
             user-scalable=0;'/>\
         <title>溫溼度感測器</title>\
         <style>\
                    body { font-family: '微軟正黑體', '黑體-繁', Sans-Serif;}\
         </style>\
         </head>\
         <body>\
          <h1>ESP8266溫溼度</h1>\
          <p>溫度:%d </p>\
          <p>濕度:%d </p>\
        </body>\
        </html>",
          temp, humid
        );
  
      server.send(200, "text/html", htmlStr);
     } else {
      server.send(200, "text/html", "Sensor Error");
     }
  });
  
  server.on("/index.html", rootRouter);
  server.on("/", rootRouter);
  server.onNotFound ( []() {
    server.send ( 404, "text/plain", "File Not Found" );
  } );
  
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
    server.handleClient();
}

編譯並上傳程式碼到ESP8266控制板之後,在電腦或手機連接到ESP8266控制板的Wi-Fi熱點(名稱是ESP8266、密碼是12345678),再開啟瀏覽器連線到192.168.4.3/temp,即可看到動態的溫濕度頁面。

Posts created 483

9 thoughts on “使用snprintf()函式轉換動態字串、輸出ESP8266溫濕度網頁

  1. 老師百忙之中打擾一下
    請問一下 如果是在外出
    透過4G訊號連到家中路由器
    再從路由器連到ESP8266
    ESP8266在連到UNO上 讀取A0的訊號
    請問這樣的方式
    要朝什麼方向去做
    謝謝

    1. IP分享器可以設定「虛擬伺服器」,讓你指定可從網際網路連入的裝置(如ESP8266)的IP位址,每一家IP分享器的設定方式都不太一樣,請查閱廠商說明書。

      thanks,
      jeffrey

    2. 你必須要先做兩件事:
      1.先知道你家的網路IP,如果你用的是固定ip問題就比較簡單,去問你的網路供應商就好了,如果你家是動態ip也沒關係,如果你在台灣,就用瀏覽器”連到https://myip.com.tw/”這個網站就可以看到你家網路的ip了!
      2.如果你是想用一般的瀏覽器功能去讀取的話,會使用到port:80,這時就必須用WiFi路由器中的”Port forward”設定功能,把Port:80對應到你路由器內部的IP位址,例如192.168.0.100,然後把你的ESP8266以固定IP的方式連接到路由器的這個內部IP,再來就是把ESP8266設定成伺服器的角色就可以了!
      不過不是每一款的WIFI路由器都有”Port Forward”功能,要先去查清楚你手上的路由器是否有?如果沒有就必須買過了!

  2. 好像不能哦,您现在仅用AP模式是不可以的从外网接入的,只有采用WiFi.mode(WIFI_AP_STA),将模块同时作为station接入路由才可以:)

  3. 老師您好 :
      我給了mosquitto一個固定ip,也開啟port:1883,但是仍然無法由外網連入
    Broker安裝在CentOS 7環境下

  4. 我有幾個疑問
    1. server.on() 這函數的意義是?和他括號填的值是要甚麼?
    2. 溫度:%d \
    濕度:%d \
    所以說濕度跟溫度的值是填到那兒?這一段只有提到%d是整數,那temp這個變數值用到那兒了?

    1. server.on()相當於事件處理程式,在此偵測用戶端的請求:temp和humid會被填入%d的位置,這些在書本裡面都有寫。

      thanks,
      jeffrey

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top