2016年7月30日 星期六

使用 NodeMCU API

本文參考 NodeMCU 官網  API : http://nodemcu.readthedocs.org/en/dev/,將 DHT22 的感測資料透過 http 呼叫傳送給SQL server,為了支援浮點運算,須使用韌體版本為支援浮點數運算之nodemcu_float_0.9.6-dev_20150704.bin,與先前使用的整數版本不同請先自行更新韌體


1. DHT模組 API 測試


DHT 模組 API 可以自行判斷 DHT11 (整數)與其他  DHT (浮點數之結果

函數
功能
讀取以下型號之DHT感測器 DHT11, 21, 22, 33, 44
讀取DHT11感測器
讀取DHT11以外之感測器

回應結果dht.OK (0)dht.ERROR_CHECKSUM (1)dht.ERROR_TIMEOUT (2)

Lua程式測試範例

pin = 2
status, temp, humi, temp_dec, humi_dec = dht.read(pin)
if status == dht.OK then
    -- Integer firmware using this example
    print(string.format("DHT Temperature:%d.%03d;Humidity:%d.%03d\r\n",
          math.floor(temp),
          temp_dec,
          math.floor(humi),
          humi_dec
    ))

    -- Float firmware using this example
    print("DHT Temperature:"..temp..";".."Humidity:"..humi)

elseif status == dht.ERROR_CHECKSUM then
    print( "DHT Checksum error." )
elseif status == dht.ERROR_TIMEOUT then
    print( "DHT timed out." )
end

  

2. 將 DHT 感測資料上傳至 MySQL 伺服器


這部分有 init.luauser.luadht22_report.lua  三個模組。 init.lua 於開機時會自動執行程式碼如下


local timerID=0   -- LED閃滅用的 timer編號
local pinLED=4
local lighton=0
--
-- flashLED()
--
function flashLED()
    if (wifi.sta.getip()==nil) then
        gpio.write(pinLED,gpio.LOW)     
    else
        if (lighton==1) then
            gpio.write(pinLED,gpio.HIGH)           
            lighton = 0
        else
            gpio.write(pinLED,gpio.LOW)                
            lighton = 1
        end   

    end
end

--
-- checkWifi()
--
function checkWifi()
    local ip = wifi.sta.getip()

    if(ip==nil) then
        print("Connecting...")
    else
        tmr.stop(timerID)
        print("Connected to AP!")
        print(ip)
        tmr.alarm(timerID, 500, tmr.ALARM_AUTO, flashLED)
    end
end

--
-- main()
--

-- init LED status
gpio.mode(pinLED, gpio.OUTPUT) 
gpio.write(pinLED,gpio.LOW)     

-- connect Wifi
wifi.setmode(wifi.STATION)
wifi.sta.config("SSID","PASSWORD")   -- 這裡要替換成自己 AP 的 SSID 與密碼
wifi.sta.autoconnect(1) 
tmr.stop(timerID)   -- stop previous timer
tmr.unregister(timerID)
tmr.register(timerID, 2000, tmr.ALARM_AUTO,checkWifi)
if not tmr.start(timerID) then
    print("tmr.start("..timerID..") failed!")
end

-- start user file
dofile("user.lua")


user.lua負責啟動所有服務程式碼如下


dofile("dht22_report.lua");


dht22_report.lua 每隔 10 秒讀取  DHT 的感測值並用  POST 方式上傳至  MySQL 伺服器

--
--  DHT22_report
--
--  Note: this module needs the float version firmware :
--        nodemcu_float_0.9.6-dev_20150704.bin
--
local timerID=1    -- 讀取 DHT22用的計時器編號
local pinDHT=2
local sqlServer="XXX.XXX.XXX.XXX"   --這裡要替換成伺服器的 IP
local Location="NodeMCU"

--
-- sendDHT(temp, humi)
--
function postDHT(temp, humi)
    local conn = nil

    -- receive()
    function receive(conn, payloadout)
        if (string.find(payloadout, "Status: 200 OK") ~= nil) then
            print("Posted OK");
        end
    end

    --connection()
    function connection(conn, payloadout)  
        local params = "loc="..Location.."&temp="..temp.."&hum="..humi   --post paramaters
        -- Post       
        local httpString =  "POST /SensorReport.php HTTP/1.1\n"
                        ..  "Host: "..sqlServer.."\n"
                        ..  "Content-Type: application/x-www-form-urlencoded\n"
                        ..  "Content-Length: "..string.len(params).."\n\n"
                        ..  params
        print("***postDHT:\n"..httpString.."\n")
        conn:send(httpString)
    end

    --disconnection()
    function disconnection(conn, payloadout)
        conn:close();
        collectgarbage();
    end
   
    -- create connection and register callback funciton
    conn = net.createConnection(net.TCP, 0)
    conn:on("receive", receive)
    conn:on("connection", connection)
    conn:on("disconnection", disconnection)
   
    -- connect to server
    conn:connect(80,sqlServer)
end

--
-- readDHT()
--
function readDHT()
    status, temp, humi, temp_dec, humi_dec = dht.read(pinDHT)
    if status == dht.OK then     
        local t = temp + temp_dec/1000
        local h = humi + humi_dec/1000       
        print(string.format("***DHT: Temperature : %.1f    Humidity : %.1f",t,h))  --debug
        if(wifi.sta.getip()==nil) then
            print("***DHT: Wifi is not connected")
        else
            postDHT(t,h)
        end
    elseif status == dht.ERROR_CHECKSUM then
        print( "***DHT: Checksum error." )
    elseif status == dht.ERROR_TIMEOUT then
        print( "***DHT: timed out." )
    end
end

--
-- main()
--
tmr.stop(timerID) -- stop previous timer
tmr.unregister(timerID)
tmr.register(timerID, 10000, tmr.ALARM_AUTO, readDHT)
if not tmr.start(timerID) then
     print("tmr.start("..timerID..") failed!")
end

--- start message
print("start DHT report service")



    

3. MySQL 伺服器的 http API



最後是  SensorReport.php,雖然是只用 POST 傳資料,但仍將 GET 放進來,網頁單獨測試時,可以直接在瀏覽器網址輸入測試資料 root 與 password 要替換成 mysql 的帳密

<?php
//The 'root' and 'password' is required to be setup according to your own mysql installation
$db = mysql_pconnect("localhost","root","password") or
   die('[{"Msg":"'.mysql_error().'"}]');
mysql_query("SET CHARACTER SET 'UTF8';");      
mysql_query('SET NAMES UTF8;');
mysql_query('SET CHARACTER_SET_CLIENT=UTF8;');
mysql_query('SET CHARACTER_SET_RESULTS=UTF8;');
mysql_select_db("HomeDB");
date_default_timezone_set('Asia/Taipei');
               
$loc="";
$temp=-999;
$hum=-999;

if (isset($_GET['loc'])) {
        $loc= $_GET['loc'];
}
if (isset($_GET['temp'])) {
        $temp = $_GET['temp'];
}
if (isset($_GET['hum'])) {
        $hum = $_GET['hum'];
}

if (isset($_POST['loc'])) {
        $loc = $_POST['loc'];
}
if (isset($_POST['temp'])) {
        $temp= $_POST['temp'];
}
if (isset($_POST['hum'])) {
        $hum= $_POST['hum'];
}

if ($loc=="") {  // invalid location
        die( '[{"Msg":"loc is null"}]'); //result code
}      

$query = 'INSERT INTO `HomeDB`.`sensor` '.
                 '(`Date`, `Time`, `Location`, `Temperature`, `Humidity`)'.
                 ' VALUES '.
                 '(CURDATE(), CURTIME(),"'.$loc. '","' .$temp. '","' .$hum.'");';

if(mysql_query($query)>0) {
        //create successfully
        print  '{"Msg":"OK"},';
} else {
        print  '{"Msg":"FAIL"},';
}
mysql_close();
?>




參考資料
[1]  “NodeMCU Documentation”, http://nodemcu.readthedocs.org/en/dev/


沒有留言:

張貼留言