This article documents a first project with the Espressif ESP8266.
The objective is a module that will take periodic temperature and humidity measurements and publish them to an MQTT message broker.
This inital implementation is very basic, it is largely configured in code, though it does use DHCP. Later extensions might include a web interface for configuration of WLAN parameters etc, but for the moment the emphasis is assessment of reliability given some reports on the ‘net.
Hardware
A module was purchased with on board CP210x USB to serial chip. The only other component needed was the DHT22 digital temperature and humidity sensor.
NodeMCU was chosen for the ESP2866 firmware because of the inbuilt support for ‘interesting things’, including the DHT22.
Above is a breadboard of the system for development.
Lots of online schematics show a pullup resistor on the DHT22 data wire.
Above is a scope capture of the DHT22 data wire, pulses are quite square and a pullup resistor is not needed, at least for short connections.
See also NodeMCU devkit V1 deep sleep.
Firmware
The firmware was downloaded from https://nodemcu-build.com/ , modules included were adc, dht, file, gpio, mqtt, net, node, ow, tmr, uart, wifi. (Some were not required for this project.)
Code
The lua code was derived from several published articles, and none worked straight off, probably a result of changes to nodeMCU over time.
nodeMCU depends heavily on the use of callbacks. The preferred scheme is to schedule elements asynchronously… which seems a good idea but using the event for “GOT_IP” to initiate MQTT connection resulted in no connection (DHCP negotation has not been completed at this point).
An alternate method of trying to monitor the GOT_IP event did work successfully, reducing operating time and saving some battery.
Here is the first pass of working code.
-- Remember to connect GPIO16 (D0) and RST for deep sleep function --# Settings # --- MQTT --- mqtt_broker_ip = "192.168.0.10" mqtt_broker_port = 1883 mqtt_username = "" mqtt_password = "" mqtt_client_id = "" nodeid="30" --- WIFI --- wifi_SSID = "hakea" wifi_password = "04584858937105" -- wifi.PHYMODE_B 802.11b, More range, Low Transfer rate, More current draw -- wifi.PHYMODE_G 802.11g, Medium range, Medium transfer rate, Medium current draw -- wifi.PHYMODE_N 802.11n, Least range, Fast transfer rate, Least current draw wifi_signal_mode = wifi.PHYMODE_G -- If the settings below are filled out then the module connects -- using a static ip address which is faster than DHCP and -- better for battery life. Blank "" will use DHCP. -- My own tests show around 1-2 seconds with static ip -- and 4+ seconds for DHCP --client_ip="192.168.0.17" --client_netmask="255.255.255.0" --client_gateway="192.168.0.20" client_ip="" client_netmask="" client_gateway="" --- INTERVAL --- -- In milliseconds. Remember that the sensor reading, -- reboot and wifi reconnect takes a few seconds --time_between_sensor_readings = 60000-6000 time_between_sensor_readings = 60000 --# END settings # temperature = 0 humidity = 0 -- DHT22 sensor function get_sensor_Data() dht=require("dht") status,temp,humi,temp_decimial,humi_decimial = dht.read(2) if( status == dht.OK ) then -- Prevent "0.-2 deg C" or "-2.-6" temperature = temp.."."..(math.abs(temp_decimial)/100) humidity = humi.."."..(math.abs(humi_decimial)/100) -- If temp is zero and temp_decimal is negative, then add "-" to the temperature string if(temp == 0 and temp_decimial<0) then temperature = "-"..temperature end print("Temperature: "..temperature.." deg C") print("Humidity: "..humidity.."%") elseif( status == dht.ERROR_CHECKSUM ) then print( "DHT Checksum error" ) temperature=-1 --TEST elseif( status == dht.ERROR_TIMEOUT ) then print( "DHT Time out" ) temperature=-2 --TEST end dht=nil package.loaded["dht"]=nil end function swf() wifi.setmode(wifi.STATION) wifi.setphymode(wifi_signal_mode) wifi.sta.config(wifi_SSID, wifi_password) wifi.sta.eventMonReg(wifi.STA_GOTIP,smq) wifi.sta.eventMonStart() wifi.sta.connect() if client_ip ~= "" then wifi.sta.setip({ip=client_ip,netmask=client_netmask,gateway=client_gateway}) end print("swf done...") end function smq() print(tmr.now()) print("wifi.sta.status()",wifi.sta.status()) if wifi.sta.status() ~= 5 then print("No Wifi connection...") else get_sensor_Data() m=mqtt.Client(client_id,120,username,password) print(" IP: ".. mqtt_broker_ip) print(" Port: ".. mqtt_broker_port) print("WiFi connected...") m:on("offline",slp) m:connect(mqtt_broker_ip,mqtt_broker_port,0,0, function(conn) print("Connected to MQTT") print(" IP: ".. mqtt_broker_ip) print(" Port: ".. mqtt_broker_port) print(" Client ID: ".. mqtt_client_id) print(" Username: ".. mqtt_username) print("emonhub/tx/"..nodeid.."/values"..":".. temperature .. "," .. humidity) m:publish("emonhub/tx/"..nodeid.."/values",temperature .. "," .. humidity, 0, 0, function(conn) print("Published.") m:close() tmr.alarm(0,1000,tmr.ALARM_SINGLE,slp) -- tmr.alarm(0,2000,tmr.ALARM_SINGLE,function() slp() end) end) end, function(conn,reason) print("MQTT connect failed",reason) end) end print("smq done...") end function slp() print(tmr.now()) node.dsleep(time_between_sensor_readings*1000-tmr.now()+8100,2) end print("Starting...") swf() -- Watchdog loop, will force deep sleep the operation somehow takes to long tmr.alarm(1,30000,1,function() node.dsleep(time_between_sensor_readings*1000) end)
The code as it evolves is available online https://github.com/owenduffy/dht22iotm .
Problems
For whatever reason, I could not write new firmware on Windows 10 (32), It either didn’t work, or resulted in BSOD. I eventually wrote the firmware on Linux using esptool.py which has been reliable (though it did not work in Windows 10.
Similarly, Esplorer cause BSOD on the same machine communicating with the module. It did work reliably on my laptop with Windows 10 (64).
The WEMOS MiniPro D1 does not work with security enabled on a DLINK router where the other module pictured earlier works fine.
Test results
The system is running under test and small changes being explored to improve operation. With recent changes to get some event handling working, average current drawn from 5V is 5mA.
Follow on implementations
WEMOS D1 Mini Pro
Above, the WEMOS D1 Mini Pro with DHT shield with AM2302 fitted.
Above, the WEMOS module with a Ge diode added for the deep sleep reset circuit (NodeMCU devkit V1 deep sleep).