攀藤G5空气质量上报乐联网教程,PM2.5 HCHO NodeMcu(8266) si7021
本帖最后由 wetnt 于 2016-12-10 12:56 编辑空气质量上报乐联网—攀藤G5(PM2.5)+NodeMcu(8266)+si7021+Lewei
乐为物联网的活动提供的套件,借机学习下NodeMcu(8266)的用法。之前开工贴在此:http://www.geek-workshop.com/thread-26378-1-1.html
一、模块介绍
NodeMcu带一个扩展板,支持si7021传感器和攀藤G5传感器。
http://image.geek-workshop.com/forum/201603/24/204333xdlgzjllspg6grrd.jpg
攀藤G5(PM2.5)传感器,采用串口输出数据模式,每秒钟输出一次数据,串口监听就好。
http://image.geek-workshop.com/forum/201603/24/204333dsm2nylqnnttnv0g.jpg
si7021采用了IIC总线,利用si7021库可以方便读取数据。
http://image.geek-workshop.com/forum/201603/24/204334hfwizho0u5funpit.jpg
甲醛传感器,也是采用串口输出数据的方式,不过需要发送特定的字段请求数据。NodeMcu只有一个串口,这次实验暂时没有把它的数据集成进去。(另外一个帖子里有介绍:甲醛测试仪+ESP8266+LeWei)
在另外一个帖子里,将采用Arduino MEGA上传所有传感器数据。
二、制作过程
制作过程很简单了,配套的扩展板很完善,直接将模块、传感器插在上面就ok了。
不过需要注意的是,NodeMcu是和Arduino完全不同的一款设备,Arduino像是个电脑,而NodeMcu则像是一个操作系统,Arduino直接烧录软件,而NodeMcu是对上传到Flash的文件进行解释运行;使用习惯上有非常的不同。真正使用过程中遇到很多问题,纠结了很久才都解决。回头从新开贴说下“NodeMcu的使用心得”。
步骤如下:
1、NodeMcu连上手机USB线,插入电脑USB口,就等系统识别硬件,自动安装驱动程序好了。如果安装不成功,需要手动安装。
2、烧录bin文件。需要下载烧录软件、bin文件。
其中bin文件下载地址:http://bbs.nodemcu.com/t/nodemcu-firmware-download-build-20150318-new-location/27,也可以在GitHUB上下载:https://github.com/nodemcu/nodemcu-firmware/releases/tag/0.9.6-dev_20150704,不过国家防火墙问题,经常访问不到。
其中有两个版本:nodemcu_float_0.9.6-dev_20150704.bin、nodemcu_integer_0.9.6-dev_20150704.bin,一个是具备浮点功能,另外一个只是整数功能。差别呢就是“integer”版本不能处理小数,精度要求高的地方的用“float”版本,但我的NodeMcu板子float版本老刷入不成功。建议两个版本都下载,后面有用处。
烧录软件下载,之前在网络上搜索了很多版本,这些版本都可以刷入bin,但板子却没反应,建议大家下载最新的 “ESP8266Flasher.exe”版本。界面如图:
刷入波特率是:230400,而连接波特率是:9600,有些模块需要RST按键才能响应串口连接
如果烧录成功之后板子没有回显响应,应该是有init.lua文件嵌入,你换刚才提到的另外一个bin刷下就ok,不然板子永远不受你控制!这个地方浪费了我大量的时间和精力!
3、下载IDE。NodeMcu官网IDE是垃圾建议不要用,问询了群里许多朋友,推荐用“ESPlorer”,JAVA软件写的需要java环境。
三、软件代码
init.lua
-- init.lua
--=============================================================
print("\nBBK_Lewei_Started_si7021_pm2.5_init.lua")
require("bbk_log")
require("bbk_ip_info")
lg("require_ok")
--=============================================================
function Do_Next_File()
lg("Do_Next_File")
dofile("bbk_si7021_pm25_lewei_ok.lua")
end
--=============================================================
wifi.setmode(wifi.STATION)
wifi.sta.disconnect()
Connect2AP("ssid","pass")
--=============================================================
bbk_log.lua
--bbk_log
--=============================================================
function GetRunTime()
local t = tmr.now()/1000000 --print(t)
local h = t/3600 t = t - h * 3600--print(h,t)
local f = t/60 --print(f,t)
local s = t%60 --print(s,t)
local u = tmr.now()/1000%1000 --print(s,t)
return string.format("%02d:%02d:%02d.%03d",h,f,s,u)
end
--=============================================================
function lg(s)
if s==nil then
print("-------- "..GetRunTime().." --------")
else
print("-------- "..GetRunTime().." = "..s)
end
end
--=============================================================
bbk_ip_info.lua
-- Connect2AP
function Connect2AP(ssid,pass)
---------------------------------------------------------
lg("Connect2AP("..ssid..","..pass..")")
---------------------------------------------------------
tmr.alarm(0, 3000, 1, function()
----------------------------------------------------
wifi.sta.config(ssid,pass)
wifi.sta.connect()
wifi.sta.autoconnect(1)
----------------------------------------------------
if wifi.sta.getip() == nil then
print("Connecting to AP...\n")
else
local ip, nm, gw = wifi.sta.getip() print(ip) --IP_Info_Show()
tmr.stop(0)
Do_Next_File()
end
----------------------------------------------------
end)
---------------------------------------------------------
end
function IP_Info_Show()
---------------------------------------------------------
ip, nm, gw = wifi.sta.getip()
if wifi.sta.getip() == nil then
print("IP Info:",ip,nm,gw,'\n')
else
print("IP Info:")
print("IP Address: ",ip)
print("Netmask : ",nm)
print("Gateway Ad: ",gw,'\n')
end
---------------------------------------------------------
end
function Do_Next_File()
lg("Do_Next_File")
end
---------------------------------------------------------
--wifi.setmode(wifi.STATION)
--wifi.sta.disconnect()
--Connect2AP("acDev","AbroadCar2015()")
---------------------------------------------------------
bbk_si7021_pm25_lewei_ok.lua
--=============================================================
print("\nBBK_Lewei_Started_si7021_pm2.5")
--=============================================================
require("bbk_log")
require("bbk_ip_info")
---------------------------------
require("bbk_http_get_post")
require("bbk_lewei")
require("bbk_string")
---------------------------------
require("si7021")
require("bbk_si7021")
--=============================================================
lg("require_ok")
--=============================================================
function httpResponse(s)
----------------------------------------------------------
conn=nil
local n = string.len(s)
if(n<10) then return end
----------------------------------------------------------
local z = StringGetAB(s,"{","}") s = nil n = nil
print("{"..z.."}","\r\n")
----------------------------------------------------------
end
--=============================================================
--=============================================================
pm25 = 0
upkey = 0
----------------------------------------------------------
si7021_Init()
uart.setup( 0, 9600, 8, 0, 1, 0 )
----------------------------------------------------------
uart.on("data", 0,
function(data)
if((string.len(data)==32) and (string.byte(data,1)==0x42) and (string.byte(data,2)==0x4d))then
----------------------------------------------------------
pm25 = (string.byte(data,13)*256+string.byte(data,14))
print("pm25 = "..pm25)
----------------------------------------------------------
upkey = upkey + 1
if upkey>15 then upkey=0 updateLoop() end
----------------------------------------------------------
end
end, 0)
--=============================================================
function updateLoop()
lg("updateLoop")
si7021_Loop() si7021_Integer_Show()
local d,l = buildValueJson("WD",si7021_T,"SD",si7021_H,"PM",pm25)
lewei_httpPOST("02",d) d=nil l=nil
collectgarbage()
end
--=============================================================
bbk_http_get_post.lua
--=============================================================
conn=nil
--=============================================================
function httpResponse(s)
conn=nil
print("back==")
print(s)
end
function httpPOST(h,p,u,o,d)
----------------------------------------------------------
local l=string.len(d)
----------------------------------------------------------
local s="POST "..u.." HTTP/1.1\r\n"
.."Host:"..h.."\r\n"
..o
.."Connection:close\r\n"
.."Content-Length: " ..l.. "\r\n"
.."\r\n"..d.."\r\n"
.."\r\n"
--print(str)
----------------------------------------------------------
httpCONNECT(h,p,s)
----------------------------------------------------------
end
function httpGET(h,p,u)
local s="GET "..u.." HTTP/1.1\r\n"
.."Host:"..h.."\r\n"
.."Connection:close\r\n"
.."Accept: */*\r\n\r\n"
--print(s)
httpCONNECT(h,p,s)
end
function httpCONNECT(h,p,s)
conn=net.createConnection(net.TCP, false)
conn:on("connection",function(conn,r) conn:send(s) end)
conn:on("receive", function(conn,r) httpResponse(r) end)
conn:connect(p,h)
end
--=============================================================
bbk_lewei.lua
--=============================================================
port = 80
host = "www.lewei50.com"
urls = "/api/V1/gateway/UpdateSensors/"
usek = "userkey:xxxxxxx\r\n"
--=============================================================
function buildValueJson(...)
local arg={...} local s=""
local n = table.getn(arg)
for i=1,n,2 do
s = s.."{\"Name\":\""..arg.."\",\"Value\":\"" ..arg.. "\"}"
if(i~=n-1)then s = s.."," end
end
s="["..s.."]"
return s,string.len(s)
end
function lewei_httpPOST(g,d)
httpPOST(host,port,urls..g,usek,d)
end
--=============================================================
bbk_string.lua
function StringGetAB(s,a,b)
local ln = string.len(s)
local ai,an=string.find(s,a) --print(ai.."="..an)
local bi,bn=string.find(s,b) --print(bi.."="..bn)
local ax=0 local bx=0
if(ai~=nil) then ax=ai end
if(an~=nil) then ax=an end
if(bn~=nil) then bx=bn end
if(bi~=nil) then bx=bi end
if(ax+1>bx-1) then return "" end
return string.sub(s,ax+1,bx-1),string.sub(s,bx+1,ln)
end
bbk_si7021.lua
----------------------------------------------------------
si7021_H = 0
si7021_T = 0
si7021 = require("si7021")
----------------------------------------------------------
function si7021_Init()
local SDA_PIN = 5 -- sda pin, GPIO12
local SCL_PIN = 6 -- scl pin, GPIO14
si7021.init(SDA_PIN, SCL_PIN)
end
function si7021_Loop()
si7021.read()
si7021_H = si7021.getHumidity()
si7021_T = si7021.getTemperature()
end
function si7021_Integer_Show()
print("si7021: ",si7021_T.."C ",si7021_H.."%")
end
function si7021_Float_Show()
local t = string.format("%.1f",si7021_T)
local h = string.format("%.1f",si7021_H)
print("si7021: ",t.."C ",h.."%")
end
----------------------------------------------------------
--si7021_Init()
--si7021_Loop()
--si7021_Show()
----------------------------------------------------------
si7021.lua
-- ***************************************************************************
-- SI7021 module for ESP8266 with nodeMCU
-- Si7021 compatible tested 2015-1-22
--
-- Written by VIP6
--
-- MIT license, http://opensource.org/licenses/MIT
-- ***************************************************************************
local moduleName = ...
local M = {}
_G = M
--I2C slave address of Si70xx
local Si7021_ADDR = 0x40
--Commands
local CMD_MEASURE_HUMIDITY_HOLD = 0xE5
local CMD_MEASURE_HUMIDITY_NO_HOLD = 0xF5
local CMD_MEASURE_TEMPERATURE_HOLD = 0xE3
local CMD_MEASURE_TEMPERATURE_NO_HOLD = 0xF3
-- temperature and humidity
local t,h
local init = false
-- i2c interface ID
local id = 0
-- 16-bittwo's complement
-- value: 16-bit integer
local function twoCompl(value)
if value > 32767 then value = -(65535 - value + 1)
end
return value
end
-- read data from si7021
-- ADDR: slave address
-- commands: Commands of si7021
-- lenght: bytes to read
local function read_data(ADDR, commands, length)
i2c.start(id)
i2c.address(id, ADDR, i2c.TRANSMITTER)
i2c.write(id, commands)
i2c.stop(id)
i2c.start(id)
i2c.address(id, ADDR,i2c.RECEIVER)
tmr.delay(20000)
c = i2c.read(id, length)
i2c.stop(id)
return c
end
-- initialize module
-- sda: SDA pin
-- scl SCL pin
function M.init(sda, scl)
i2c.setup(id, sda, scl, i2c.SLOW)
--print("i2c ok..")
init = true
end
-- read humidity from si7021
local function read_humi()
dataH = read_data(Si7021_ADDR, CMD_MEASURE_HUMIDITY_HOLD, 2)
UH = string.byte(dataH, 1) * 256 + string.byte(dataH, 2)
h = ((UH*12500+65536/2)/65536 - 600)
UH = nil
dataH = nil
return(h)
end
-- read temperature from si7021
local function read_temp()
dataT = read_data(Si7021_ADDR, CMD_MEASURE_TEMPERATURE_HOLD, 2)
UT = string.byte(dataT, 1) * 256 + string.byte(dataT, 2)
t = ((UT*17572+65536/2)/65536 - 4685)
UT = nil
dataT = nil
return(t)
end
-- read temperature and humidity from si7021
function M.read()
if (not init) then
print("init() must be called before read.")
else
read_humi()
read_temp()
end
end;
-- get humidity
function M.getHumidity()
return string.sub(h, 1, 4)/100
end
-- get temperature
function M.getTemperature()
return string.sub(t, 1, 4)/100
end
return M
(待补充)
将这些文件都传入NodeMcu,就可以开始你的“空气质量上传乐联网”之旅了!
四、网页展示
空气质量地图
五、注意事项
1、NodeMcu的悖论
NodeMcu的悖论: 刷入了一个uart监控串口的程序,一启动就运行。但接下来重启操作、刷bin都不能停止这个监控串口的程序,这块NodeMcu就不能操作,也不能再写入程序了。
悖论解决办法: nodemcu_integer_0.9.6-dev_20150704.bin、nodemcu_float_0.9.6-dev_20150704.bin 两个版本互相刷能够冲掉内嵌lua文件。
核心关键 —— NodeMcu 只能支持一个UART,而且上传文件、程序都是使用这个串口,因此遇到串口传感器,特别是发送数据特别密的传感器,NodeMcu立马就不受控制了!
NodeMcu看到有朋友写了软件串口的库,回头试试能否用软件虚拟串口来解决!
2、调试时候先不要使用init.lua文件,如果init.lua文件中使用了串口监听,那么基本上板子就不能再调试了,必须得重新刷bin才能用,非常浪费时间!只有确定代码完全没问题了,再写入init.lua文件!!! 学习了。谢谢,连代码都放出来了,真不错 自己顶贴!自己顶贴! 我是来顶贴的 :lol超级赞!!!! 楼主好厉害,膜拜:loveliness::loveliness::loveliness::loveliness: 我也来顶啊 不错,山寨之,哈哈 学习学习支持支持 NodeMcu看到有朋友写了软件串口的库,回头试试能否用软件虚拟串口来解决!
大神,求库共同研究
[email protected]
非常感谢 软件虚拟串口 http://nodemcu.readthedocs.io/en/master/en/modules/uart/ 程序运行起来不能再写入程序这样解决: 在代码uart.on("data"加段逻辑,如果遇到+++退出回调函数,大概这样: if data==“+++" then uart.on("data") 。。。 点亮板子上的蓝牙灯
wifi.setmode(wifi.STATION)
wifi.sta.config("xxxx","xxxx")
print(wifi.sta.getip())
led1 = 3
led2 = 4
gpio.mode(led1, gpio.OUTPUT)
gpio.mode(led2, gpio.OUTPUT)
srv=net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive", function(client,request)
local buf = "";
local _, _, method, path, vars = string.find(request, "(+) (.+)?(.+) HTTP");
if(method == nil)then
_, _, method, path = string.find(request, "(+) (.+) HTTP");
end
local _GET = {}
if (vars ~= nil)then
for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
_GET = v
end
end
buf = buf.."<h1> ESP8266 Web Server</h1>";
buf = buf.."<p>GPIO0 <a href=\"?pin=ON1\"><button>ON</button></a> <a href=\"?pin=OFF1\"><button>OFF</button></a></p>";
buf = buf.."<p>GPIO2 <a href=\"?pin=ON2\"><button>ON</button></a> <a href=\"?pin=OFF2\"><button>OFF</button></a></p>";
local _on,_off = "",""
if(_GET.pin == "ON1")then
gpio.write(led1, gpio.HIGH);
elseif(_GET.pin == "OFF1")then
gpio.write(led1, gpio.LOW);
elseif(_GET.pin == "ON2")then
gpio.write(led2, gpio.LOW);
elseif(_GET.pin == "OFF2")then
gpio.write(led2, gpio.HIGH);
end
client:send(buf);
client:close();
collectgarbage();
end)
end) 先收藏在学习 本帖最后由 lipper 于 2017-3-26 18:36 编辑
这个代码有几个BUG。
1.;P表示“;P”
2.:o表示“:0”
嗯,是的,是网页的问题,
页:
[1]