Overview

Skill Level: Any Skill Level

Makers and Developers who have basic knowledge of microcontroller.

Ingredients

Step-by-step

  1. Introduction

    This is follow-on of my earlier recipe on how to connect ESP8266 to Watson IoT. Instead of using emulated data, here you use real temperature and humidity data from DHT11 sensor. Beside its wifi and mqtt built-in functions, the recipe demonstrates that NodeMCU based ESP8266 still has processing power to handle an external sensor. The most common solution for the use cases such as in home automation, weather sensor, etc is by using arduino with its ethernet or wifi shield. This recipe shows alternative solution that is more compact, cheaper and uses less power.

    The recipe also shows how an IoT application can be build in less than 15 minutes with Bluemix IoT Platform starter application by using Node-RED flow. The application is a temperature alarm which will send out a ‘tweet’ if the temperature from the DHT11 sensor exceeds a certain threshold.

  2. Prepare

    If you are a first time user of ESP8266, familiarize yourself with flashing the NodeMCU firmware, loading and running the lua scripts. There are many tutorials in the net that serve the purpose, this is one of them. Complete links and API documentation to write your own lua scripts are available in the NodeMCU wiki.

    1. Wire ESP8266 to the FTDI USB to Serial adapter. Connect the USB to Serial adapter to the PC using USB cable. PC USB port also supplies enough power to the ESP8266 and the FTDI USB to Serial adapter.
    2. Download
    3. Flash the NodeMCU firmware to the ESP8266. Make sure you connect GPIO0 pin to ground during flashing.
    4. Create init.lua and mainIoTF.lua scripts provided below.
      • Modify macID, SSID and wifiPWD accordingly
    5. Using LuaLoader, load init.lua and mainIoTF.lua scripts.
    6. Unwired ESP8266 from the FTDI USB to Serial adapter.
    7. Connect DHT11 to the ESP8266.
      • Data pin of DHT11 is wired to GPIO2 pin of ESP8266
    8. Power on the ESP8266 by connecting it to a 3.3V power supply e.g: 2x AAA batteries.
    9. Verify that real temperature and humidity data are indeed published periodically by visiting Quickstart.

  3. init.lua

    -- Executed everytime it restarts or power on
    --
    tmr.alarm(0, 10000, 0, function() dofile(mainIoTF.lua) end)

  4. mainIoTF.lua

     -- I've added code to send command (2 ways communication) but currently still being comment out. Pls read comment in line 61 below. 
    -- If you want to be able to send command then uncomment those lines. However you will no longer be able use 'quickstart' as org ID. You must use registered org ID with its auth password.
    --
    orgID = "quickstart" -- IoT Foundation organization ID <========== Modify this!
    broker = orgID..".messaging.internetofthings.ibmcloud.com" -- IP or hostname of IoTF service
    mqttPort = 1883 -- MQTT port (default 1883: non-secure)
    userID = "use-token-auth" -- blank for quickstart
    userPWD = "<your auth password>" -- blank for quickstart <========== Modify this!
    --macID = "18fe349e543f" -- unique Device ID or Ethernet Mac Address <=== Modify this!
    macID = wifi.sta.getmac():gsub(':','') -- set this manually if needed. Just hex digits, no collons/spaces/dashes/etc.
    clientID = "d:"..orgID..":esp8266:"..macID -- Client ID
    count = 0 -- Test number of mqtt_do cycles
    mqttState = 0 -- State control

    topicpb = "iot-2/evt/status/fmt/json"
    topicmd = "iot-2/cmd/+/fmt/json" -- Topic for subscribing commands

    pin = 4 -- GPIO2

    -- Wifi credentials
    SSID = <your wifi SSID> -- <========== Modify this!
    wifiPWD = <your wifi password> -- <========== Modify this!

    function wifi_connect()
    wifi.setmode(wifi.STATION)
    wifi.sta.config(SSID,wifiPWD)
    wifi.sta.connect()
    print("MAC address is " .. macID);
    end


    function mqtt_do()
    count = count + 1 -- tmr.alarm counter

    if mqttState < 5 then
    mqttState = wifi.sta.status() --State: Waiting for wifi
    wifi_connect()

    elseif mqttState == 5 then
    print("Starting to connect...")
    m = mqtt.Client(clientID, 120, userID, userPWD)

    m:on("offline", function(conn)
    print ("Checking IoTF server...")
    mqttState = 0 -- Starting all over again
    end)

    m:on("message",
    function(conn, topic, data)
    print(topic .. ":" ) -- receive the commands
    if data ~= nil then
    print(data)
    end
    end)

    m:connect(broker , mqttPort, 0,
    function(conn)
    print("Connected to " .. broker .. ":" .. mqttPort)
    mqttState = 20 -- Go to publish state

    -- To be able to send command, uncomment the next 4 lines of code.
    -- m:subscribe(topicmd,0,
    -- function(conn)
    -- print("Successfully subscribe to commands...")
    -- end)
    --
    end)

    elseif mqttState == 20 then
    mqttState = 25 -- Publishing...
    status,temp,humi,temp_decimal,humi_decimal = dht.read11(pin) --read temperatur & humdity
    if( status == dht.OK ) then
    m:publish(topicpb ,'{"d": {"Temperature":'..temp..',"Humidity":'..humi..'}}', 0, 0,
    function(conn)
    -- Print confirmation of data published
    print("Sent message #"..count.." DHT Temperature:"..temp.."; ".."Humidity:"..humi)
    mqttState = 20 -- Finished publishing - go back to publish state.
    end)
    elseif( status == dht.ERROR_CHECKSUM ) then
    print( "DHT Checksum error." );
    elseif( status == dht.ERROR_TIMEOUT ) then
    print( "DHT Time out." );
    end

    else print("Waiting..."..mqttState)
    mqttState = mqttState - 1 -- takes us gradually back to publish state to retry
    end

    end

    tmr.alarm(2, 10000, 1, function() mqtt_do() end) -- send data every 10s
  5. Temperature Alarm Application

    The application is modified version of the sample Node-RED flow from the Internet of Things Platform Starter boilerplate. Instead of using simulated device, you will use real temperature data from DHT11 sensor. In addition, you also will add twitter out node in the flow so that critical condition i.e: temperature exceeds threshold will be tweeted.

    1. Go to IBM Bluemix. If you are an existing Bluemix user log in as usual. If you are new to Bluemix you can sign up for the free 30 day trial.
    2. Create the application by taking the following steps:
      • Select the Internet of Things Platform Starter from the boilerplates section of the catalog, and click View More.
      • Provide the application name, modify your host (yourhostname), if required, and click Create.
    3. Wait until your application completes staging and starts.
    4. When your application is running, click the Routes URL or enter this URL in a browser:
       http://<yourhostname>.mybluemix.net
    5. You arrive at the Node-RED for Internet of Things landing page.
    6. Click Go to your Node-RED flow editor.
    7. You see a ready-made flow that can process temperature readings from a simulated device.
    8. Modify the provided sample flow:
      1. Open ‘IBM IoT App In’ node and fill in the Device Id with macID of mainIoTF.lua
      2. Open ‘temp’ node and modify the function into: return {payload:msg.payload.d.Temperature};
      3. Modify the temperature threshold in the ‘temp thresh’ if required
      4. Add twitter out node and supply the credentials
      5. Deploy the application

  6. Conclusion

    That’s it if the temperature exceeds the threshold, a tweet will be generated.

    I hope this recipe demonstrates in the Internet of Things that:

    1. The client device including its wifi networking capability can be built inexpensively and compactly with Espressif ESP8266.
    2. Lua based NodeMCU firmware for ESP8266 enables ‘high level’ language script to be developed quickly and easily. Perfect for prototyping.
    3. On the cloud end, IBM Internet of Things Platform Starter application in Bluemix enables quick and simple IoT application development and deployment. It also makes available more advanced functions such as Analytics, AlchemyAPI, Watson Nodes etc.

6 Comments on "Cloud-ready temperature & humidity sensor for IBM Watson IoT Platform"

  1. CezarSacomani October 08, 2015

    Hendro Hello, I used your code in a DHT22 sensor and did not work! I made a small change in mainIoTF.lua the code and got success !!!! Just below this code:

    orgID = “quickstart” — IoT Foundation organization ID
    broker = orgID..”.messaging.internetofthings.ibmcloud.com” — IP or hostname of IoTF service
    mqttPort = 1883 — MQTT port (default 1883: non-secure)
    userID = “” — blank for quickstart
    userPWD = “” — blank for quickstart
    macID = “18FE34F20FC0” — unique Device ID or Ethernet Mac Address <==== Modify this!
    clientID = "d:"..orgID..":esp8266:"..macID — Client ID
    count = 0 — Test number of mqtt_do cycles
    mqttState = 0 — State control

    topicpb = "iot-2/evt/status/fmt/json"
    topicmd = "iot-2/cmd/+/fmt/json" — Topic for subscribing commands

    pin = 4 — GPIO2

    — Wifi credentials
    SSID = "HOME_CEZAR" — <========== Modify this!
    wifiPWD = "xuxa102030" — <========== Modify this!

    function wifi_connect()
    wifi.setmode(wifi.STATION)
    wifi.sta.config(SSID,wifiPWD)
    wifi.sta.connect()
    print("MAC address is " .. macID);
    end

    function mqtt_do()
    count = count + 1 — tmr.alarm counter

    if mqttState < 5 then
    mqttState = wifi.sta.status() –State: Waiting for wifi
    wifi_connect()

    elseif mqttState == 5 then
    print("Starting to connect…")
    m = mqtt.Client(clientID, 120, userID, userPWD)

    m:on("offline", function(conn)
    print ("Checking IoTF server…")
    mqttState = 0 — Starting all over again
    end)

    m:connect(broker , mqttPort, 0,
    function(conn)
    print("Connected to " .. broker .. ":" .. mqttPort)
    mqttState = 20 — Go to publish state
    end)

    elseif mqttState == 20 then
    mqttState = 25 — Publishing…
    status,temp,humi,temp_decimial,humi_decimial = dht.read(pin)
    if( status == dht.OK ) then
    m:publish(topicpb ,'{"d": {"Temperature":'..temp..',"Humidity":'..humi..'}}', 0, 0,
    function(conn)
    — Print confirmation of data published
    print("Sent message #"..count.." DHT Temperature:"..temp.."; ".."Humidity:"..humi)
    mqttState = 20 — Finished publishing – go back to publish state.
    end)
    elseif( status == dht.ERROR_CHECKSUM ) then
    print( "DHT Checksum error." );
    elseif( status == dht.ERROR_TIMEOUT ) then
    print( "DHT Time out." );
    end

    else print("Waiting…"..mqttState)
    mqttState = mqttState – 1 — takes us gradually back to publish state to retry
    end

    end

    tmr.alarm(2, 10000, 1, function() mqtt_do() end) — send data every 10s

    • Yes, dht.read11(pin) is only for dht11 whereas dht.read(pin) is for dht11, 22, 33, 44 so it is more general purpose….great.

    • Ops, it didn’t work not only because dht11 vs dht22 but also because orgID ‘quickstart’ vs registered orgID. My original code was using orgID=’quickstart’ but later I added capability to send command. In IoT Foundation, you can’t use ‘quickstart’ to send command, you must use registered orgID but somehow I still put ‘quickstart’ in the above published code.
      So yes, you did the right thing. If you want to continue to use ‘quickstart’ then you remove the added command code like what you did. Or using my code with the sending command capability (2 ways communication) but have to use registered orgID (including userID & userPWD).
      Thanks for brought this up and sorry for the confusion.

  2. CezarSacomani October 08, 2015

    Hendro Hello, I used your code in a DHT22 sensor and did not work! I made a small change in mainIoTF.lua the code and got success !!!! Just below this code:

    orgID = “quickstart” — IoT Foundation organization ID
    broker = orgID..”.messaging.internetofthings.ibmcloud.com” — IP or hostname of IoTF service
    mqttPort = 1883 — MQTT port (default 1883: non-secure)
    userID = “” — blank for quickstart
    userPWD = “” — blank for quickstart
    macID = “18FE34F20FC0” — unique Device ID or Ethernet Mac Address <==== Modify this!
    clientID = "d:"..orgID..":esp8266:"..macID — Client ID
    count = 0 — Test number of mqtt_do cycles
    mqttState = 0 — State control

    topicpb = "iot-2/evt/status/fmt/json"
    topicmd = "iot-2/cmd/+/fmt/json" — Topic for subscribing commands

    pin = 4 — GPIO2

    — Wifi credentials
    SSID = "HOME_CEZAR" — <========== Modify this!
    wifiPWD = "xuxa102030" — <========== Modify this!

    function wifi_connect()
    wifi.setmode(wifi.STATION)
    wifi.sta.config(SSID,wifiPWD)
    wifi.sta.connect()
    print("MAC address is " .. macID);
    end

    function mqtt_do()
    count = count + 1 — tmr.alarm counter

    if mqttState < 5 then
    mqttState = wifi.sta.status() –State: Waiting for wifi
    wifi_connect()

    elseif mqttState == 5 then
    print("Starting to connect…")
    m = mqtt.Client(clientID, 120, userID, userPWD)

    m:on("offline", function(conn)
    print ("Checking IoTF server…")
    mqttState = 0 — Starting all over again
    end)

    m:connect(broker , mqttPort, 0,
    function(conn)
    print("Connected to " .. broker .. ":" .. mqttPort)
    mqttState = 20 — Go to publish state
    end)

    elseif mqttState == 20 then
    mqttState = 25 — Publishing…
    status,temp,humi,temp_decimial,humi_decimial = dht.read(pin)
    if( status == dht.OK ) then
    m:publish(topicpb ,'{"d": {"Temperature":'..temp..',"Humidity":'..humi..'}}', 0, 0,
    function(conn)
    — Print confirmation of data published
    print("Sent message #"..count.." DHT Temperature:"..temp.."; ".."Humidity:"..humi)
    mqttState = 20 — Finished publishing – go back to publish state.
    end)
    elseif( status == dht.ERROR_CHECKSUM ) then
    print( "DHT Checksum error." );
    elseif( status == dht.ERROR_TIMEOUT ) then
    print( "DHT Time out." );
    end

    else print("Waiting…"..mqttState)
    mqttState = mqttState – 1 — takes us gradually back to publish state to retry
    end

    end

    tmr.alarm(2, 10000, 1, function() mqtt_do() end) — send data every 10s

    • Yes, dht.read11(pin) is only for dht11 whereas dht.read(pin) is for dht11, 22, 33, 44 so it is more general purpose….great.

    • Ops, it didn’t work not only because dht11 vs dht22 but also because orgID ‘quickstart’ vs registered orgID. My original code was using orgID=’quickstart’ but later I added capability to send command. In IoT Foundation, you can’t use ‘quickstart’ to send command, you must use registered orgID but somehow I still put ‘quickstart’ in the above published code.
      So yes, you did the right thing. If you want to continue to use ‘quickstart’ then you remove the added command code like what you did. Or using my code with the sending command capability (2 ways communication) but have to use registered orgID (including userID & userPWD).
      Thanks for brought this up and sorry for the confusion.

Join The Discussion