本帖最后由 wetnt 于 2016-12-10 12:56 编辑
空气质量上报乐联网—攀藤G5(PM2.5)+NodeMcu(8266)+si7021+Lewei
乐为物联网的活动提供的套件,借机学习下NodeMcu(8266)的用法。之前开工贴在此:[url]http://www.geek-workshop.com/thread-26378-1-1.html[/url]
一、模块介绍
NodeMcu带一个扩展板,支持si7021传感器和攀藤G5传感器。
攀藤G5(PM2.5)传感器,采用串口输出数据模式,每秒钟输出一次数据,串口监听就好。
si7021采用了IIC总线,利用si7021库可以方便读取数据。
甲醛传感器,也是采用串口输出数据的方式,不过需要发送特定的字段请求数据。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[i].."","Value":"" ..arg[i+1].. ""}"
- 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, [url]http://opensource.org/licenses/MIT[/url]
- -- ***************************************************************************
- local moduleName = ...
- local M = {}
- _G[moduleName] = 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-bit two'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文件!!! |