ESP8266 IoT DHT22 temperature and humidity

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://bitbucket.org/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).