Try   HackMD

Tutorial on how to build a temperature and humidity sensor with a display

by Sebastian Gustavsson (sg222yu)

Overview

This tutorial contains information on how you create a temperature and humidity sensor. The devices also use an oled display and tree led lights. The microcontroller used for this work is an ESP32 from ZHITING. To handle all the data and events this tutorial uses Node-RED (low-code programming tool for event-driven applications) and InfluxDb (time series database).

The device uses the home network (Wi-Fi) to connect to the internet.

The programming language used to program the EPS32 is micropython and some basic javascript was used in Node-red.

Everything was created on a Window 10 PC.

Approximate time:

This project was created over 5 weeks (full time), most of this time was used for lectures. I've created things like this before, which made it possible to create this device in a couple of days. When following this tutorial you should also be able to achieve this.

Objective

This project was chosen mostly because I already had most of the hardware to create the device. To gain new knowledge I chose to get an old display that was used to display the latest collected data. I also chose to use Node-red since this isn't something I've used before.

The device collects the temperature and humidity data from my house and displays in on Node-red's dashboard. The dashboard provides a detailed view of the humidity and temperature in both celsius and fahrenheit. You will be able to see the current and average values, also the lowest and highest reached temperatures and lastly three charts showing the last 24 hour readings.

This tutorial will give the insights of how you can easily create a weather station with node-red. The user can on your own expanded the weather station with addition devices, by giving the devices a unique location.

Material

Parts Used for Store Picture Price
Zhiting ESP32 (2pcs) The main device Amazon.se
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
160kr
Dht11 (Sensor pack) Temperature and humidity sensor Amazon.se
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
260kr
Led stop light (Sensor pack) Used to flash to indicate when things happen
USB cable To connect the microcontroller to the PC Amazon.se
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
130kr
Breadboard and jumper wires To wire things together Amazon.se
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
138kr
Oled display To show the latest readings Amazon.se
Oled display
85kr
773kr

Computer setup

This program uses Thonny as IDE and is used to both write and upload the code to the microcontroller.

Steps:
ESP32
  1. Download and install the LTS version of Node.js.
  2. Download Python.
  3. Install Python, choose Add Python to PATH (this makes it possible to use python in your command prompt.
  4. Connect your ESP32 to the computer using the USB cable.
  5. Open Thonny.
  6. In the top menu find the Run tab, open it and choose the top choice, "Select interpreter".
  7. Select your device in the first drop down menu by pressing the menu and choosing MicroPython (ESP32).
  8. To find out what port your ESP32 is using, open the start menu, type "device manager" and open it.
  9. Find Ports(COM & LPT) and open the tab. Here you will see your device followed by a COM port.
    If you are unsure what device that is your ESP32 you could disconnect and reconnect it while watching this menu.
  10. Go back to Thonny and select the port that your EPS32 is using.
  11. Press Install or update firmware.
  12. In the first drop down choose the COM port that your device is using.
  13. Download the latest firmware.
  14. In the second drop down browse the firmware you downloaded.
  15. Make sure that the Erase flash before installing is checked.
  16. Press Install. This will take a while.
  17. When you get a message that says "Done!" you can close the window, and press "OK" on the next window.
  18. Your device is now ready.
Node-RED
  1. Open the command prompt by opening the start menu and type run, in the window type cmd and press run.
  2. Type "npm install -g unsafe-perm node-red" and press enter.
  3. Done!

Putting everything together

All of the components used in this tutorial got built in resistors, so there is no need to add any additional resistors. If any other components are used than the one linked in the table above, there could be a need to add resistors.

The inputs used in Fig. 1 could have a different placement on your device.

Circuit diagram
fig. 1.

Platform

This project uses Node-RED and this choice was made because I wanted to learn how to use this tool and I've knowledge about programming since earlier, the tool is free and at the moment it's set up locally.

InfluxDB is used to store all the data and the a free account is used, since I had some troubles getting the networking to work locally. This database was chosen since I used it before and Node-RED has built in support for this database.

The code

import network

def network_connect():
    wifi = network.WLAN(network.STA_IF)
    if not wifi.isconnected():
        print('Connecting to network...')        
        wifi.active(True)
        wifi.connect(config.WIFI_SSID, config.WIFI_PASSWORD)
        while not wifi.isconnected():
            pass

    if wifi.isconnected():
        print('Network config:', wifi.ifconfig())
        
# This is how the ESP32 is connected to the Wi-Fi.
# It establishes a new connection if there is none.
def network_disconnect():
    wifi = network.WLAN(network.STA_IF)
    if wifi.isconnected():
        wifi.disconnect()
        wifi.active(False)
        while wifi.isconnected():
            pass
        print("\nDisconnected from WIFI")
        
# This disconnects the ESP32 from the Wi-Fi. 
# This code isn't really needed since this should happen automatically 
# when the device goes into deep sleep.
import usocket as socket

def upload_data(celsius, humidity):
    network_connect()
    
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    addr = socket.getaddrinfo(config.IP_ADDRESS, 4445)[0][-1]

    data = "%s %s" % (celsius, humidity)

    message = str(data)
    s.sendto(message, addr)
    
    network_disconnect()

# This code uploads the data to Node-RED on port 4445. 
from time import sleep

class Lamp:    
    def __init__(self, green, yellow, red):
        self.green = green
        self.yellow = yellow
        self.red = red
    
    
    def blink_red(self, times, length):
        while times > 0:
            self.red.value(1)
            sleep(length)
            self.red.value(0)
            sleep(length)
            times -= 1

    
    def blink_green(self, times, length):
        while times > 0:
            self.green.value(1)
            sleep(length)
            self.green.value(0)
            sleep(length)
            times -= 1
    

    def blink_yellow(self, times, length):
        while times > 0:
            self.yellow.value(1)
            sleep(length)
            self.yellow.value(0)
            sleep(length)
            times -= 1

# This is the class for the lamp.
import ssd1306
from machine import Pin, SoftI2C

class Oled:
  def __init__(self, width, height, scl, sda):   
    self.display = ssd1306.SSD1306_I2C(
        width, height, SoftI2C(scl=Pin(scl), sda=Pin(sda)))


  def display_values(self, celcius, fahrenheit, humidity):
    self.display.fill(0)
    self.display.text("Temp/humidity:", 0, 0)
    self.display.text("Celcius:    %s C" % str(celcius), 0, 20)
    self.display.text("Fahrenheit: %s F" % str(fahrenheit), 0, 30)
    self.display.text("Humidity:   %s %s" % (str(humidity), "%"), 0, 40)
    self.display.show()

# And this is the class used for the display.
# The ssd1306 is an external library that can be downloaded here: 
# https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py
from machine import Pin
from machine import deepsleep
import dht
sensor = dht.DHT11(Pin(27))

print("\nReading sensor data.")
        
celsius = None
fahrenheit = None
humidity = None

tries = 5
sensor_read = False
while celsius is None or tries > 0 and not sensor_read:
    try:
        sensor.measure()
        celsius = sensor.temperature()
        fahrenheit = round(sensor.temperature() * (9 / 5) + 32)
        humidity = sensor.humidity()
        sensor_read = True

    except:
        print("Failed to read sensor.")
        tries -= 1
        sleep(1)

if not sensor_read:
    print("Skipping reading sensor.")
    lamp.blink_red(5, 0.25)
else:
    print("Successful read.")
    oled.display_values(celsius, fahrenheit, humidity)

    tries = 5
    data_uploaded = False
    while tries > 0 and not data_uploaded:        
        try:
            network_connect()

            lamp.blink_yellow(3, 0.25)  
            upload_data(celsius, humidity)
            lamp.blink_green(1, 1)
            data_uploaded = True

            network_disconnect()
        except:
           print("Failed to connect to the network.")
           tries -= 1
           sleep(1)

    if not data_uploaded:
        print("Skipping uploading data.")
        lamp.blink_red(2, 1)
    else:
        print("Data uploaded.")

print("Deep sleep in 5 seconds.")
sleep(5)
deepsleep(config.DEEP_SLEEP_TIMER)
    
# Here is the main function.
# It will try to read the sensor 5 times,
# if it fails it will skip the rest of the code and go into deep sleep.
# If it reads the sensor successfully it will try to upload the data 5 times,
# before it goes into deep sleep.

Transmitting the data / connectivity

The data is sent once every hour by Wi-Fi over UDP (User Datagram Protocol).

The Wi-Fi connection uses a lot of battery and that is why its only used for short periods before disconnected.
The range of the Wi-Fi is quite short, even with a good router. Sadly I couldn't use anything else where I live.

Presenting the data

Fig. 2 shows the flow set up in Node-RED.

Node-RED flow
fig. 2.

The data is saved to the database (InfluxDB) on every reading made by the ESP32 and is stored for 30 days.
The choice of using InfluxDB was made because I had prior knowledge about this database from earlier, Node-RED has support for it and it's a great database for time series data.

Node-RED fetches data 5 times each update, something that most likely could be improved upon, but for simplicity I will leave it like it is.

As seen in Fig. 2 there is some automation, the "Automatic update" and "Initial load" nodes.
The Automatic update node is run on every upload from the ESP32, which updates the dashboard after 15 seconds.
The Initial load node is run on the first page load which updates all the values on the dashboard.

Fig. 3 shows the dashboard from Node-RED's. Where you can see the humidity and temperature in both celsius and fahrenheit. All of these values are displayed in current, average, lowest reached and highest reached form. They also have a chart providing a 24 hour overview of the readings.

Dashboard
fig. 3.

Fig 4. shows the data stored in InfluxDB. At the moment there is just one location added, since there is just one device, but a new device could be added with another location.

InfluxDB
fig. 4.

Finalizing the design

I'm very happy how the project turned out, and it would be cool to create more devices and place them around the house. Sadly I don't own a 3D printer else it would be nice to create a case as well.

Fig. 5 shows the device.

Device

fig. 5.

Fig. 6 shows the display.

Device display

fig. 6.