土壤湿度计Project综述
这节介绍如何用NodeMCU来检测花盆里土壤的湿度,效果如下:
本Project中,仍然是利用NodeMCU收集传感器的环境数据,并传送到ThingSpeak的Channel上存储,和上一个收集温度信息的Project相比,这里NodeMCU脱离了USB供电,使用了四节AA的电池盒加上一个3.3V的Step Down Regulator,还增加了一个LED显示工作状态。在程序中我们规定每隔10分钟向ThingSpeak发送一次测量结果(HTTP POST),4节电池一共维持了三天,这大约相当于400-500次使用ESP8266。
在电池基础上,今后可以尝试的改进方向是:
- 利用USB的插头转换电压,再通过Step Down Regular供电。
- 寻找是否有更节能的维持NodeMCU的工作方式,比如定时唤醒硬件,类似Amazon的Dash。
NodeMCU Analog Input
NodeMCU只有一个模拟输入,即A0。LUA读A0的输入很简单
function getHumidity() hum = adc.read(0); return hum; end
使用LED提示WIFI连接状态
在Deploy的工作模式下,有时ESP8266和Router的连接可能出现问题,通常不希望需要通过检查ThingSpeak的Channel才能发现其实NodeMCUM没有正常工作,所以这里还使用了LED指示灯在表示连接状态,正常的LED状态是在发送POST并且完成,LED会短暂闪烁一次,表示开始准备发送,发送完毕。如果有连接问题,LED将一直停留红灯状态,如果发现,只需重新启动电源,一般NodeMCU会重新成功连接到Router上。
function postToThingspeak(hum) gpio.write(8, gpio.HIGH); --开始POST,置LED HIGH .... 发送HTTP POST ... conn:on("receive", function(conn, payload) gpio.write(8, gpio.LOW); --发送成功,置LED LOW conn:close() end)
NodeMCU和湿度器的连线方式
这里使用的土壤湿度传感器如下所示
插入土壤中的叫的装置做soil probe. 工作电压3.3-5V,它的读数范围在0-1023之间,读数越大土壤越干燥. NodeMCUM直接给传感器其供3.3V电压。Probel的PCB板上的有三个PIN,分别是Vin,GND,AO,和NodeMCU的连接方式很简单
YL-69 | NodeMCU |
---|---|
A0 | Analog A0 |
3.3V | VCC |
GND | GND |
土壤湿度计的读数范围
Reading | Interpretation |
---|---|
1000<=s | Disconnected,or not in soil |
600<=s<1000 | Dry |
370<=s<600 | Humid |
s<370 | In Water |
土壤的Humidity随时间变化
整体上Humidity随时间变化比较缓慢,部分原因可能是因为植物放在室内,光合作用不明显。数值越大,土壤越干燥,在5月26日时,土壤的湿度的一下子增加是因为给植物浇了水,可以看出浇水之后,湿度立即变大之后(干燥度变小),然后迅速回到350以上,这说明浇的部分的水分很快被植物吸收一部分,然后湿度就一直维持在350以上。
一种可靠的Deploy的途径
Deploy物联网开发板有两个重要的问题需要解决:
- 电池的寿命问题
- WIFI连接的可靠程度
目前我采用的方式是:
通过USB直接供电
如果deploy的环境中有110/220V交流电源,则可以通过一个USB转接口+USB cable通过microusb直接给NodeMCU供电,这极大的简化的程序的复杂程度和日后对Deploy开发版的电池维护(更换,重启等等)。
经常重启node.restart()
如果供电不是问题,那么每次调用node.restart(),之后再连接WIFI,几乎可以确保每次的Request能够成功的发送。 需要斟酌的是要在合适的地方调用restart. 因为NodeMCU的net library的工作方式都是异步的,restart可能会造成之前的connection 对象销毁。目前看来,如下的工作方式较可靠(前提是对能耗没有限制)
setupWifi() -- 第一次启动需要连接一次WIFI tmr.alarm(1,30000,1,function() postToThingspeak() end)
function postToThingspeak() ... conn:on("receive", function(conn, payload) print("received") gpio.write(2,gpio.LOW) conn:close() node.restart() --在receive的回调函数中重启node setupWifi() --重启之后还需要重新连接wifi end) t = tmr.now() conn:connect(80,'api.thingspeak.com') end
经常重启wifi
如果NodeMCU仅仅用来收集环境的信息,重启NodeMCU不会对其收集的信息造成任何的影响,那么restart是一个可靠,简单的手段。如果NodeMCU还用来控制外界的电路,比如Relay,那么短暂的重启可能会影响Relay的状态,这个时候我们只需要重启WiFi就可以了,事实上,重启WIFI要比重启NodeMCU要更简单可靠,因为重启本身的原因就是WIFI的连接问题
---------------------------- ---- post to thingspeak --- ---------------------------- function postToThingspeak() conn=net.createConnection(net.TCP, 0) conn:on("connection",function(conn, payload) cmd ="POST /update.json?api_key=TheToken&field1=".."1" .. " HTTP/1.1\r\n" .. "Host: api.thingspeak.com\r\n" .. "Connection: close\r\n" .. "Accept: */*\r\n" .. "User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n" .. "\r\n"; print(cmd); conn:send(cmd); gpio.write(6,gpio.HIGH) end) conn:on("receive", function(conn, payload) print("received") gpio.write(6,gpio.LOW) conn:close() -- 示例用 -- 这段内容保证每次Post完成之后都重启一次WIFI -- 尽管这不是很必要 wifi.sta.disconnect() wifi.sta.connect() end) t = tmr.now() conn:connect(80,'api.thingspeak.com') end
更多情况下,如果我们发现NodeMCU的WIFI工作的结果,不在我们的预计之内,可以通过一个If Statement重启WIFI连接
if (result =='0') then elseif (result=='1') then else -- restart will disturb the relay -- ideally repull should not affect -- replay's status -- print("need repull"); -- node.restart(); wifi.sta.disconnect() wifi.sta.connect() do_some_work_again() end