1. 程式人生 > >NODEMCU除錯心得7

NODEMCU除錯心得7

關於網路協議 HTTP 2

上一節,我們用nodemcu伺服器向客戶端傳送nodemcu的記憶體資訊。這一節反過來,我們介紹如何用客戶端控制nodemcu。

先介紹一個簡單的例子,用客戶端控制nodemcu的GPIO4,實現nodemcu的藍色LED遠端開關。

Step 3

這裡仍然參考了 ckuehnel程式碼gpio.lua

  • 下面是我的程式碼,取名叫My_gpio.lua

   -- SSID = " "
   -- password = " "
   pin = 4

   -- wifi.setmode(wifi.STATION)
   -- wifi.sta.config(SSID,password)
print(wifi.sta.getip()) gpio.mode(pin, gpio.OUTPUT) srv=net.createServer(net.TCP) srv:listen(80,function(conn) conn:on("receive", function(conn,payload) print(payload) local _, _, method, path, vars = string.find(payload, "([A-Z]+) (.+)?(.+) HTTP"); if
(method == nil)then _, _, method, path = string.find(payload, "([A-Z]+) (.+) HTTP"); end local _GET = {} if (vars ~= nil)then for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do _GET[k] = v end end
-- HTML local buf = ""; buf = buf.."<h1> Web Server</h1>"; buf = buf.."<p>LIGHT 1 " buf = buf.."<a href=\"?pin=ON4\"><button>LED OFF</button></a>&nbsp;" buf = buf.."<a href=\"?pin=OFF4\"><button>LED ON</button></a></p>"; if(_GET.pin == "ON4")then gpio.write(pin, gpio.HIGH); elseif(_GET.pin == "OFF4")then gpio.write(pin, gpio.LOW); end conn:send(buf); conn:close(); collectgarbage(); end) end)

逐段來看程式碼

  • 前兩行,定義路由器的賬號與密碼,因為我的nodemcu已經預設連上路由,所有這裡就遮蔽了。
    • 注意,當你連上路由,獲得IP地址後,這個資訊就儲存在flash裡了。所以就算掉電重啟,還會自動連線
  • 第三行,pin = 4定義GPIO,4號對應的是nodemcu上控制LED的管腳,注意高電平時LED關,低電平開。
  • 第四行和第五行,設定esp8266為station模式,連線路由器。同樣之前連線過,資訊就儲存了,所以就遮蔽了。
  • print()列印IP地址資訊,這個是客戶端瀏覽器要訪問nodemcu,就要輸它的IP地址。
    • 每次上電時的IP有可能不一樣
  • gpio.mode()設定gpio為輸出模式,也就是控制模式

  • srv=..建立TCP伺服器

  • srv.listen()監聽80埠的資訊,80也就是http協議對應的埠
  • conn.on("recieve"..)這個與上一節的例程一樣,也是接收客戶端發出的資訊payload。不同之處在於:
    • 上節的例程只接收客戶端連線到伺服器的資訊。
    • 本節的例程除了接收連線資訊之外,還接收客戶端傳送的gpio控制指令
  • print()列印客戶端發來的payload資訊,會有四五行,具體內容可以見上一節關於網路協議 HTTP,最重要的是第一行,裡面包含的資訊需要提取出來,一般是這樣

      GET / HTTP/1.1
    

    或者這樣

      GET /?pin=ON4 HTTP/1.1
    
  • string.find()函式用來提取控制指令,它會返回符合規則的字串,這裡的目標資訊是客戶端傳送的控制指令,一般為如下形式:

    GET /?pin=ON4 HTTP/1.1
    

    這裡定義了3個字串method,path,vars.

    • method代表客戶端的方法,有GETPOST等等。GET用來向伺服器傳送請求的資訊,POST用來向伺服器提交網頁上輸入的資訊。
    • path 代表路徑,這裡只得到一個/
    • vars 代表控制按鈕button返回的控制資訊

    • 前面的兩個_,_是模糊變數,這兩個變數是返回find函式找到字串的第一個和最後一個的index(沒什麼用)

    find()的第一個變數是要檢索的字串,第二個變數是檢索的規則

    • method,path,vars對應的檢索規則分別是([A-Z]+),(.+), (.+)
    • ([A-Z]+),[A-Z]代表檢索的是從A到Z的大寫字母,+代表不是單個字母,而是多個字元構成的字串
    • (.+).代表檢索所有字元,+同樣代表是字串
    • HTTP是格式,代表pathvars之間有?隔開,vars後以HTTP結束,相當於pathvar的讀取終止符

    假如是客戶端剛連線時傳送的資訊,paylaod第一行是這樣

    GET / HTTP/1.1
    

    不符合剛才帶?的格式,methodpath,vars 都得到空值nil

  • if..用來判斷method是否為nil,如果是,說明是客戶端的連線資訊,

  • find()的檢索模式改為([A-Z]+) (.+) HTTP,只接收兩個字串methodpath

  • 定義局域變數_GET,接收vars中的gpio控制資訊

  • 如果vars不為空,其代表了控制資訊
  • 用for迴圈提取pin=ON4裡的資訊
  • string.gmatch()是專用在迭代forx迴圈中的字串函式,
    • (%w+)=(%w+)&*,%w代表字母和數字,+代表是多個字元。
    • &應該是和=一樣,是格式,
    • *的作用和+類似,區別是* 代表該字元可以不出現。&*的意思是vars字串的提取格式最後可以沒有&,也可以有一個或者多個&
更多字串函式和模式的語法,請點選這裡這裡

接下來是HTML程式碼

  • 首先定義一個空字串
  • 接下來直接寫HTML的body部分,前面沒有head,也沒有<html>,<head>,<body>關鍵字,直接寫標題1:<h1>..</h1>
  • 然後寫第一端的文字部分,<p1>..
  • 接下來的程式碼定義button和它的返回值。關鍵字<a>通常是連結的關鍵字,href=後是連結的地址。但是這裡,用來建立一個button物件,

    • href = \"?pin=ON4\"\是轉義符,當按鈕被按下,客戶端就返回?pin=ON4這一資訊,
    • <button>LED OFF</button>LED OFF是button物件上的文字標籤
    • </a>:結束<a>開頭的程式碼,&nbsp代表一個空格
    • 這行程式碼的含義是點選LED ON開啟LED,gpio4處於低電位
  • 下一段程式碼的含義是:點選LED OFF關閉LED。點選後,返回?pin=OFF4
    • 文字,按鈕on和按鈕off都屬於段落p1,處在同一行上

接下來,對vars代表的字串pin=ON4進行判斷,

  • pin作為關鍵字,ON4或者OFF4是關鍵字對應的元素。
  • 如果_GET.pin對應的元素是ON4,拉高GPIO電平,反之,則拉低

最後傳送buf包,並關閉conn連線,清理記憶體垃圾

  • 注意,這裡並沒有像Step 1的例程,沒有加入HTTP的頭部資訊,可能是傳送buff量比較小的原因,而傳送的HTML文件本身就是一個很簡略的版本。

    如果傳送buff比較長,或者對傳送正確率要求比較高,還是採用標準的HTML格式和HTML協議頭部資訊。

  • 這裡直接用conn:close()關閉連線,沒有像上一個例程,採用conn:on("sent"..)事件發生函式。

Step 4

程式碼解釋完後,我們上傳到nodemcu。如果你的nodemcu沒有連上路由,或者剛刷了韌體,就取消My_gpio.lua的註釋,輸入你的wifi賬號和密碼
- Save to ESP後,會列印你的IP資訊,像這樣

  172.21.100.79 255.255.255.0   172.21.100.254

第一個就是nodemcu的IP,後面分別是子網掩碼,和路由器的的IP

  • 在瀏覽器裡輸入nodemcu的IP,出現介面,可以選擇關閉和開啟nodemcu的LED,像這樣

這裡寫圖片描述
fig1

  • 因為HTML沒有Head資訊,所以標籤上顯示的和位址列資訊是一樣的
  • 點選LED OFF,原先的IP地址就會附加資訊:/?pin=ON4,作為客戶端的GET資訊

本來還打算講一個提交表單的例程,不過已經寫得很長了,就放到下一節好了。順帶會講一講CSS,讓沒有圖片的伺服器也能exciting。