# 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](https://www.amazon.se/gp/product/B08LL7ZH2W/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&psc=1) |  | 160kr |
| Dht11 (Sensor pack) | Temperature and humidity sensor | [Amazon.se](https://www.amazon.se/gp/product/B071GV6L41/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&psc=1) |  | 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](https://www.amazon.se/gp/product/B01NBHYAR0/ref=ppx_yo_dt_b_asin_title_o06_s01?ie=UTF8&psc=1) |  | 130kr |
| Breadboard and jumper wires | To wire things together | [Amazon.se](https://www.amazon.se/gp/product/B078JGQKWP/ref=ppx_yo_dt_b_asin_image_o06_s00?ie=UTF8&psc=1) |  | 138kr |
| Oled display | To show the latest readings | [Amazon.se](https://www.amazon.se/gp/product/B01L9GC470/ref=ppx_yo_dt_b_asin_title_o01_s01?ie=UTF8&psc=1) |  | 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](https://nodejs.org/en/).
2. Download [Python](https://www.python.org/downloads/).
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. <br>*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](https://micropython.org/download/esp32/).
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.

*fig. 1.*
## Platform
This project uses [Node-RED](https://nodered.org/) 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](https://www.influxdata.com/) 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.

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

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

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

*fig. 5.*
Fig. 6 shows the display.

*fig. 6.*