ESP8266 NodeMCU - DHT22 sensor and ThingSpeak

ESP8266 NodeMCU - DHT22 sensor and ThingSpeak

I have previously written about pushing temperature and humidity readings from an ESP8266 to a MQTT server using a DHT22 sensor. Later I leveraged NodeMCU’s built-in DHT22 library by using an online service to create a streamlined NodeMCU firmware fit for my needs. However, a reader asked me about pushing data to ThingSpeak.com instead and here is the reply.

Hardware

Follow my post here on how to connect all the parts.

NodeMCU firmware

Follow my post here on how to built a custom NodeMCU firmware and remember to check the DHT library. If you need help flashing the firmware you can take a look at my guide here.

Nodemcu-build.com default values and DHT selected

Software

Instead of the test code described in my post here, use the one below. Configure the following variables before uploading to the ESP8266:

  • thingspeak_channel_api_write_key
  • thingspeak_temperature_field_name
  • thingspeak_humidity_field_name
  • wifi_SSID
  • wifi_password

And I recommend to use a static IP address for faster connection times, just set the client_* variables.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
-- Thingspeak connect script with deep sleep
-- Remember to connect GPIO16 and RST to enable deep sleep
-- TODO: Log error codes to server

--############
--# Settings #
--############

--- Thingspeak ---
thingspeak_channel_api_write_key = "LU1TXYV15GBVTDHU"
thingspeak_temperature_field_name = "field1"
thingspeak_humidity_field_name = "field2"

--- WIFI ---
wifi_SSID = "wifi-Name"
wifi_password = "wifi-Password"
-- 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_N
-- 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=""
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

--################
--# END settings #
--################

temperature = 0
humidity = 0

-- Connect to the wifi network
wifi.setmode(wifi.STATION)
wifi.setphymode(wifi_signal_mode)
wifi.sta.config(wifi_SSID, wifi_password)
wifi.sta.connect()
if client_ip ~= "" then
    wifi.sta.setip({ip=client_ip,netmask=client_netmask,gateway=client_gateway})
end

-- DHT22 sensor logic
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
    -- Release module
    dht=nil
    package.loaded["dht"]=nil
end

function loop()
    if wifi.sta.status() == 5 then
        -- Stop the loop
        tmr.stop(0)

        con = nil
        con = net.createConnection(net.TCP, 0)

        con:on("receive", function(con, payloadout)
            if (string.find(payloadout, "Status: 200 OK") ~= nil) then
                print("Posted OK to ThingSpeak");
            end
        end)

        con:on("connection", function(con, payloadout)

        -- Get sensor data
        get_sensor_Data()

        -- Post data to Thingspeak
        con:send(
            "POST /update?api_key=" .. thingspeak_channel_api_write_key ..
            "&field1=" .. temperature ..
            "&field2=" .. humidity ..
            " 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")
        end)

        con:on("disconnection", function(con, payloadout)
            con:close();
            collectgarbage();
            print("Going to deep sleep for "..(time_between_sensor_readings/1000).." seconds")
            node.dsleep(time_between_sensor_readings*1000)
        end)

        -- Connect to Thingspeak
        con:connect(80,'api.thingspeak.com')
    else
        print("Connecting...")
    end
end

tmr.alarm(0, 100, 1, function() loop() end)

-- Watchdog loop, will force deep sleep the operation somehow takes too long
tmr.alarm(1,4000,1,function() node.dsleep(time_between_sensor_readings*1000) end)

Result

If everything went well you should see the following repeated every 60 seconds on your ESP8266:

0�~?�4�R���OCMa��_6E������

NodeMCU custom build by frightanic.com
	branch: dev
	commit: 093a895980fbd4ab8b3ebedcd6efe36e26419887
	SSL: true
	modules: node,file,gpio,wifi,net,tmr,adc,dht
 	built on: 2015-10-13 18:26
  powered by Lua 5.1.4
> Connecting...
Temperature: 23.2 deg C
Humidity: 39.1%
Posted OK to ThingSpeak
Going to deep sleep for 60 seconds

The results should now show up right away at your ThingSpeak channel.

Thingspeak with temperature and humidity data from and ESP8266 using a DHT22 sensor

Enjoyed this Content?

Help keep it free by sending a donation or purchase something using my affiliate links. You can also subscribe to various site feeds to get notified of new posts, follow me on social media, and more.

21 Comments

Alan

I have used your code as a basis for a monitor I built for my Polytunnel which posts over MQTT to a self-hosted mosquito broker. Thanks for the code - it helped me a lot!

I recently discovered a bug though - if the temperature falls below 0, using the Integer build of NodeMCU means that your temperature string ends up reading something like 0.-2 or, even worse, -1.-2.

I tried a few things to sort it but, frankly, it was giving me a headache so I replaced the image with the floating point build so I didn’t need to parse the temp string at all.

Hope this is helpful and thanks again for publishing your code

Poul Serek

Hi Alan

Glad you could use the code! Nice catch on the bug, weird that everybody uses a similar code. Anyway, I updated the code and tested the DHT sensor readings using my freezer and it works now on the integer version. It is not the prettiest code, but it works (replaced the original line 56-57 with these 4 lines):

-- 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

The code in the post is fully updated.

Example output:

Temperature: 1.1 deg C
Humidity: 10.1%

Temperature: 0.8 deg C
Humidity: 10.3%

Temperature: 0.5 deg C
Humidity: 10.6%

Temperature: 0.2 deg C
Humidity: 10.8%

Temperature: -0.1 deg C
Humidity: 11.0%

Temperature: -0.4 deg C
Humidity: 11.1%

Temperature: -0.7 deg C
Humidity: 11.4%

Temperature: -0.9 deg C
Humidity: 11.6%

Temperature: -1.2 deg C
Humidity: 11.7%

/Poul

Raz

Hi Poul,

I have a Lolin nodeMCU V3 board and I have custom flashed the board and have included all your mentioned modules. The only thing connected is a DHT22 sensor module on D2 and have connected D0 to RST.
I have uploaded your code to init.lua, but I’m not seeing any data on my thingspeak channel.
I’ve run init.lua while connected to ESPlorer and I’m getting the following error:

> dofile("init.lua")
init.lua:54: 'end' expected (to close 'function' at line 52) near ''

Could you help me fix this?

Raz

hmm… I think I may not have the dht module loaded.. I thought I had it flashed correctly.

Poul Serek

Hi Raz

That could be the issue since the code breaks the first time it tries to use the DHT22 library. If you have something connected to RST while trying the flash it will fail, I had to disconnect anything connected to the RST pin while flashing.

/Poul

ildar

this code works ones - post data to thingpeak, going to deepsleep and never comes back from deepsleep. and I cant stop or erase this script from nodemcu :(

Poul Serek

Hi Ildar

Did you connect the D0 to the RST pin? It will not wake up if you didn’t. Take a look at my post here.

You can always reflash the ESP8266 to bring it back, just remember to disconnect the D0 to RST wire and follow my guide here.

I am still using this script so it should just work fine.

/Poul

Marc

Hi and thanks for this post.
I have a problem with the DHT22.
When coming back from deepsleep it gives a timeout status and never comes back to an other status. Some an idea on this topic?

Best regards,
Marc

Poul Serek

Hi Marc

Could you post the output you get from the console? You could try changing this line:

tmr.alarm(0, 100, 1, function() loop() end)

to

tmr.alarm(0, 2000, 1, function() loop() end)

It might help if the DHT is initialised too fast after waking up.

/Poul

Simon

Great stuff and love your Oled tutorial.

Rather than post to MQTT, how can I get the temp reading to be shown on an Oled display? Can’t find how to do this in Lua only Arduino.

Keep up the great work!

Simon

Got this up and running tonight as per above but get 0 readings.

Have changed the last line to 2000 as suggested before but still no luck.

The sensor works as I can get a reading from the DHT module in the consol.

Assuming the code shown has the data line from the sensor going to pin D2 on the nodemcu?

How do I change the code so the unit doesn’t go to sleep to test it works?

Many thanks!

Poul Serek

Hi Simon

Try changing the line

tmr.alarm(0, 100, 1, function() loop() end)

to

tmr.alarm(0, 2000, 1, function() loop() end)

as you already did and

tmr.alarm(1,4000,1,function() node.dsleep(time_between_sensor_readings*1000) end)

to

tmr.alarm(1,100000,1,function() node.dsleep(time_between_sensor_readings*1000) end)

You can also delete the following lines to prevent it from going to deep sleep:

  • node.dsleep(time_between_sensor_readings*1000)
  • tmr.alarm(1,4000,1,function() node.dsleep(time_between_sensor_readings*1000) end)

/Poul

simon

Thanks Poul,

In fact I deleted the last line tmr.alarm(1,4000,1,function() node.dsleep(time_between_sensor_readings*1000) end) but did modify did tmr.alarm(0, 100, 1, function() loop() end) to tmr.alarm(0, 2000, 1, function() loop() end) as you suggested as this allows a smoother connection of the wifi (with the last line it stopped connecting or took too long.)

Also, got the values reading properly by changing the lines in the Thingspeak connection section to the following:

“&field1=” .. temp ..

“&field2=” .. humi ..

I am using the current v1.5 master firmware which could be why these tweaks were needed.

Hope this helps others :)

Simon

simon

Hi Poul,

Have tried and just cannot get the Thingspeak and oled code combined. Think its to do with the order of the calls and if they are in the loop() or not.

Working oled code is:

temperature = 0
humidity = 0

dht=require("dht")
pin = 2
status,temp,humi,temp_decimial,humi_decimial = dht.read(pin)
if( status == dht.OK ) then
  -- Float firmware using this example
  print("DHT Temperature:"..temp..";".."Humidity:"..humi)
elseif( status == dht.ERROR_CHECKSUM ) then
  print("DHT Checksum error.");
elseif( status == dht.ERROR_TIMEOUT ) then
  print("DHT Time out.");
end

myStr1 = "Temp is "..temp.." degC"
myStr2 = "Hum is "..humi.." %"

function init_spi_display()
  -- Hardware SPI CLK  = GPIO14
  -- Hardware SPI MOSI = GPIO13
  -- Hardware SPI MISO = GPIO12 (not used)
  -- CS, D/C, and RES can be assigned freely to available GPIOs
  local cs  = 8 -- GPIO15, pull-down 10k to GND
  local dc  = 4 -- GPIO2
  local res = 1 -- GPIO5
  spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
  disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
end

function draw()
  disp:setFont(u8g.font_6x10)
  disp:drawStr(10,30,myStr1)
  disp:drawStr(10,50,myStr2)

end

function display()
  disp:firstPage()
repeat
draw()
until disp:nextPage() == false
display();
end

init_spi_display()
display()

Any thoughts? This has been driving me crazy!

Many thanks,

Simon

Brendan

Is anyone able to help, i’m receiving this error;

PANIC: unprotected error in call to Lua API (`user.lua:110: not connected`)

Not that greatest at this stuff but I’m giving it a go.
Love the tutorial by the way.

Brendan

Hey all, I am receiving this error;

> Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Connecting...  
Temperature: 17.8 deg C  
Humidity: 67.2%  
Posted OK to ThingSpeak  
PANIC: unprotected error in call to Lua API (init.lua:110: not connected)

Is anyone able to help? I’m not great at this but giving it a go.
Thanks.

Poul Serek

Hi Brendan

It looks like it cannot connect to your wifi. Did you correctly fill out:

wifi_SSID = "wifi-Name"
wifi_password = "wifi-Password"

And maybe the following settings if you don’t automatically get assigned an IP address

client_ip=""
client_netmask=""
client_gateway=""

/Poul

Leave a reply