ESP8266 & NodeMCU 開發入門 (Part 3) - GPIO over REST API

本文將實作「使用 WiFi 來控制電源開關」,實作過程需要以下的背景知識:

  • 認識 REST API
  • 能使用 Lua 撰寫 HTTP Server
  • 能使用 Lua 控制 GPIO 腳位(High/Low)

需要的硬體設備如下:

  • NodeMCU 開發板
  • 麵包板
  • 杜邦線 3 條(公)
  • 繼電器模組

網路開關電器原理

透過 WiFi 來控制繼電器開關的原理非常簡單:

  • 使用 NodeMCU 的 GPIO 做為繼電器的開關訊號
  • GPIO 為 High 時繼電器開啟、Low 繼電器關閉
  • NodeMCU 實作控制 GPIO 的 REST API
  • 透過網路(WiFi)呼叫 NodeMCU 的 REST API

只能要透過網路呼叫 NodeMCU 的 REST API,就能經由繼電器來開關電器產品,達到網路開關電器的功能。

電路設計

將 D3 做為繼電器的控制 Signal,如圖 3.1。

圖 3.1:NodeMCU 與繼電器完成圖 圖 3.1:NodeMCU 與繼電器完成圖

WiFi Power Switch 實作

根據以下步驟撰寫 Lua 程式。

Step 1:設定 GPIO

使用 NodeMCU 的 D3 來控制繼電器,必須將 D3 設定為輸出,並且初始化輸出值為 Low:

-- Select IO - GPIO0 
outpin=3  
gpio.mode(outpin,gpio.OUTPUT)  
gpio.write(outpin,gpio.LOW)  

D3 輸出 Low 時,繼電器的開關會切換至 Off 狀態,表示不通電。NodeMCU 的接腳,可參考圖 3.2。

圖 3.2:使用到的 NodeMCU 腳位 圖 3.2:使用到的 NodeMCU 腳位

Step 2:實作控制函數

實作一個控制繼電器開關的函數,範例如下:

-- Power Switch
function power(stat)  
  if stat=="ON"  then gpio.write(outpin,gpio.HIGH) 
    return end
  if stat=="OFF" then gpio.write(outpin,gpio.LOW) 
    return end
end  

Lua 的函數,語法以 end 述敘做為結尾。

執行 power("ON") 即可打開繼電器開關,執行 power("OFF") 關閉繼電器開關。

本文使用的繼電器模組上,有一個 Signal 接腳,可用來控制繼電器開關。請參考圖 3.3。

圖 3.3:本文使用的繼電器模組 圖 3.3:本文使用的繼電器模組

Step 3:連接 Wifi

參考 ESP8266 & NodeMCU 開發入門 (Part 2) - 實作 HTTP Server 教學,將 NodeMCU 連上網路。

範例如下:

-- Configure the ESP as a station (client)
wifi.setmode(wifi.STATION)  
wifi.sta.config("jollenchen", "qqqqqqqq")  
wifi.sta.autoconnect(1)  

Step 4:建立 Socket Server

參考 ESP8266 & NodeMCU 開發入門 (Part 2) - 實作 HTTP Server 教學,建立 Socket Server。

範例如下:

-- Create a server
-- and set 30s time out for a inactive client
sv = net.createServer(net.TCP, 30)  

Step 5:定義 REST API

定義 Power Switch On 的 REST API 如下:

POST /power/on  

以及 Power Switch Off 的 REST API:

POST /power/off  

假設 NodeMCU 的 IP 位址為 192.168.1.100,可使用 curl 呼叫 Power Switch On 的 API 進行測試:

$ curl -X POST http://192.168.1.100/power/on

Step 6:實作 REST API

完成 REST API 定義後,開始進行 API 實作。實作原理如下:

  • receive 事件裡解析 HTTP request headers
  • 如上,判斷是否有 POST request method
  • 如上,若是 POST request method,進行 URI path 解析
  • 如上,若 URI path 為 /power/on,則呼叫 power("ON")
  • 如上,若 URI path 為 /power/off,則呼叫 power("OFF")

這裡需要了解 Lua 解析字串的做法。string 是 Lua 的字串處理模組,string.find() 函數可用來尋找子字串(substring);因此,可簡單撰寫程式如下:

if (string.find(payload, "POST /power/on") ~= nil) then  
  power("ON")
end  

比對 HTTP request headers 裡是否有 POST /power/on 字串。若找不到子字串,string.find() 則回傳 nil(即 NULL)。

範例:

-- Server listen on 80
-- Print HTTP headers to console
sv:listen(80,function(c)  
    c:on("receive", function(conn, payload)
        print(payload)

        if (string.find(payload, "POST /power/on") ~= nil) then
            power("ON")
        elseif (string.find(payload, "POST /power/off") ~= nil) then
            power("OFF")
        end

        conn:send("HTTP/1.1 200 OK\n\n")
        conn:close()
    end)
end)  

完整 WiFi Power Switch 範例

根據上述步驟,實作一個 HTTP Server,提供控制繼電器開關的 REST APIs。完整程式碼列表如下:

-- Select IO - GPIO0 
outpin=3  
gpio.mode(outpin,gpio.OUTPUT)  
gpio.write(outpin,gpio.LOW)

function power(stat)  
  if stat=="ON"  then gpio.write(outpin,gpio.HIGH) 
    return end
  if stat=="OFF" then gpio.write(outpin,gpio.LOW) 
    return end
end

-- Print IP address
ip = wifi.sta.getip()  
print(ip)

-- Configure the ESP as a station (client)
wifi.setmode(wifi.STATION)  
wifi.sta.config("jollenchen", "qqqqqqqq")  
wifi.sta.autoconnect(1)

-- Create a server
-- and set 30s time out for a inactive client
sv = net.createServer(net.TCP, 30)

-- Server listen on 80
-- Print HTTP headers to console
sv:listen(80,function(c)  
    c:on("receive", function(conn, payload)
        print(payload)

        if (string.find(payload, "POST /power/on") ~= nil) then
            power("ON")
        elseif (string.find(payload, "POST /power/off") ~= nil) then
            power("OFF")
        end

        conn:send("HTTP/1.1 200 OK\n\n")
        conn:close()
    end)
end)  

展示影片:

課堂練習

將電器(例如:電風扇)接到繼電器,並使用 Bootstrap 製作控制電器的 Web Frontend。

小結

在 NodeMCU 裡設計並實作 REST API,來製作具 Remote Control 能力的物聯網裝置。

其原理是經由 WiFi 對 NodeMCU 裡的 HTTP Server 發出請求,NodeMCU 收到請求後,根據 API 名稱(URI Path)來控制相對應的 GPIO 腳位。

這就是 GPIO over REST API 的觀念。

其它