NTP 時鐘 – browser 網頁控制 LED board

由於覺得上次沒有交代清楚,所以這篇一開始先來補充上次遇到 WiFi 和 interrupt 打架,我所使用的 functions 的部分程式碼:

#include <SoftwareSerial.h>
.
.
.
.
void disable(void);
void enable(void);
.
.
.
void disable(void)
{
ETS_GPIO_INTR_DISABLE();
}
void enable(void)
{
ETS_GPIO_INTR_ENABLE();
}

至於原理以及所代表的意義可以詳見:NTP 時鐘 – interrupt 中斷程式 & WiFi 的殺手

browser 網頁控制 LED board

在解決了 WiFi 和 interrupt 打架的問題後,我開始在 void loop () 裡面寫了一個簡單的網頁,這個網頁只有一個 textbox 和 一個 button (用來執行我要的動作),我想要的是 user 可以在 textbox 裡面輸入想要顯示的數字 (0-9),然後按下 button 後 LED board 有反應且可以確實完成任務。對一個之前常常有事沒事就開始刻網頁的我來說應該不是難事,況且只是一個 textbox 和一個 button 沒什麼了不起的吧,這一做下去以為三分鐘解決,沒想到又出事……。

在講出事為何之前先來分享一下,這個 browser 的網頁是如何和 ESP8266 的 web server 做溝通的:

首先是連上 WiFi。我用我的 Mac 連到公司其中一個 AP (以下簡稱 A),而在 Arduino IDE 裡面先設定固定參數,將 ESP8266 WiFi chip 也連線到 A,連上後,A 會回傳一個 IP 位置在 console,而這個 IP 位置就是 ESP8266 web server 的 IP 位置 (所以基本上我在 browser 上輸入這個顯示在 console 裡面的 IP,應該可以很順利的從 ESP8266 web server 裡掏出個什麼),這背後講得更白話更細一點的話就是,我拿到 IP 位置後在 browser 上輸入 IP,按下 enter,等同於透過網路走訪送出了一個 request 到這個 IP 位置 (ESP8266 web server),而 ESP8266 web server 就會赤裸裸的還 user 一個 response (即 web server 裡有什麼就吐什麼出來到我 browser 的頁面上)。

講到這裡提個外話,之前在第一篇分享的 NTP 時鐘 – WiFimanager & AP 中有提到 wifimanager 這個神奇的功能,而當我做到這裡的時候我產生了個小疑問,我們在 console 看到的 IP 到底是什麼東西的 IP?透過 wifimanager 連線得到的 IP 所代表的東西以及是誰給的和直接用 ESP8266 WiFi chip 連線所取得的 IP 是一樣的東西嗎?

我們把這兩種情況分開看:
1. Mac 直接連線上 A 這個 AP,也在 Arduino IDE 裡面設定 ESP8266 直接連上 A

我在 console 獲得的 IP 回傳值是 ESP8266 web server 的 IP (是 A 這個 AP 給的)。AP 在這還有 DHCP 的角色,這個 AP 是個 gateway 本身有自己的 IP (192.19.16.254),這個 AP 的網域是 192.19.16.0-200,也就是說當我連上 A (WiFi) 的時候,我會獲得一個來自 A 給我的 IP 位址 (192.19.16.0-200 其中一個),Mac 是 ESP8266 當然也是。

2. ESP8266 wifimanager 開啟 AP 功能

我用我的 Mac 去連這個 AP (不是 A),這個 AP 也會給我一個 IP 回傳值,而這個 IP 就是 ESP8266 的 web server 的 IP 位址,所以我連線這個 AP 後輸入拿到的 IP 看到的東西就是 ESP8266 裡面本身 web server 的東西,也就是說這個狀況 ESP8266 是 AP 也是 DHCP 也有 web server 的功能。

言歸正傳,看起來上面所說 browser 的網頁和 ESP8266 web server 做溝通是件很合理的事情,只不過我要做的事情不是單純的連線而已,我要做的東西是在連線後 (真的已經看到我在 Arduino IDE 編寫的網頁 code 真真實實的顯示在 browser 上),我要 input 數字到 textbox,按下 submit button 讓他起化學變化,顯示在 LED board 上頭,而這背後的邏輯也跟連線是一樣的東西。假設我 input 數字 5 在 textbox 裡面,按下 button,等同於透過網路走訪送出了一個 request (我想要顯示數字 5) 到 ESp8266 web server,這時候就要看這個 web server 到底會不會理我,會不會給我一個正確的 response,顯示數字 5 在 LED board 上面,很不幸的答案是不會,這就真的出事了……。

HTTP get v.s HTTP post

要跟 web server 做互動,第一個想到的就是 AJAX,看可不可以不要 reload 頁面的情況下又可以 update webpage 的資料,答案是不行。在這裡我們必須先忘掉 AJAX (以及任何 javascript 的魔法)。為什麼不行,答案很簡單,因為 webpage 在跟 ESP8266 web server 做互動的時候,所傳遞 request 的形式是以 HTTP 網址的形式傳送!所以如果用 AJAX 我不改變網址的情況下就等於沒辦法去 ESP8266 web server 核對資料而進而能顯示我的要求 (即 respond user),知道這個道理後,只好跟 AJAX 說掰掰,然而 HTTP 傳址的方式有兩種,Bird 要我先去了解這兩個 HTTP get 和 HTTP post 的差別後在做使用。

在經過我的解讀後我把這兩者的差異做了比較:

前提:論是 method 是 get 還是 post,這兩者都是要將 browser 改變的網址傳給 web server (即發送 request),(web server 會再 parse 傳進來的東西看有沒有符合的資料再 respond 給 browser)

HTTP get: 網址"會"因為 webpage 上的動作而改變,將改變後的網址發出 request 給 web server

HTTP post: 網址"不會"因為 webpage 上的動作而改變,仍然傳 request 給 web server

參考資料:淺談 HTTP Method:表單中的 GET 與 POST 有什麼差別?
由此可知,在這裡我選擇使用 HTTP get (因為我想在 browser 上看到網址的變化)。

所以現在整個 browser webpage 和 ESP8266 web server 的溝通變成,我在 textbox 輸入了一個數字,按下 button 後會改變網址,而這個改變的網址會透過 HTTP get 的方式傳遞給 ESP8266 web server 去 parse 看看 server 裡面到底有沒有東西符合這個 request,如果有就執行 (執行某件事,我這裡是要顯示數字在 LED board 上頭),沒有當然就不會理我,同時在 browser 上的網址也會跟著產生變化,解決了這個問題後,當然,數字就如我所願的顯示在 LED board 上面了。

以下程式碼是部分在 void setup() 裡面使用 HTTP get 的核心程式碼:

server.begin();
server.on("/",[]()
{
server.send(200, "text/html", page);
});
server.on("/LED", []()
{
num = server.arg("msg").toInt();
if (num == 0 || num == 1 || num == 2 || num == 3 || num == 4 || num == 5 || num == 6 || num == 7 || num == 8 || num == 9)
{
int i, k;
for (i = 0; i < COL; i++)
{
for (k = 0; k < ROW; k++)
{
pixel[num][i][k] = number[num][i][k];// let pixel work on the the number which depends "changeNumber"
}
}
}
else
{
int i, k;
for (i = 0; i < COL; i++)
{
for (k = 0; k < ROW; k++)
{
pixel[10][i][k] = number[10][i][k];// let pixel work on the the number which depends "changeNumber"
}
}
}
server.send(200, "text/html", page);
});
view raw web_server.c hosted with ❤ by GitHub

User Story Scenario

在文章的最後想要分享一個 Bird 跟我說的一個很重要的觀念,在做任何產品之前都一定要做 user story scenario。

user story scenario 是要清楚描述即將要做的產品 (要非常 detail,比如說我要幾個 button,而這個 button 可以做什麼事情,產品組件,組件規格…),站在使用者的角度思考,如果不夠清楚,就無法製作產品。

做到目前為止,看似我的手邊已經有很多大積木可以讓我去組裝了 (其實還沒完,還有至少兩個東西還沒分享到) (做到現在才在講 user story scenario 其實已經太晚,不過也是學到一次經驗),我終究還是要把這些積木拼起來才是一個完整 LED 時鐘,那我想要這個時鐘長什麼樣子呢?會在這系列文章的結束篇跟著成品一起以圖文的方式分享出來。

發表留言