# Tutorial on how to build a temperature and humidity sensor
*Overview and objective*
In this tutorial we will build a mini weather station, aiming to push weather data using a Pycom lopy4 over The Things Network and get phone notifications with the temperature. The things network uses LoRa (Long Range) that is a low-power wide-area network (LPWAN) protocol.
The project is carried out as a part project in controlling the environment in a greenhouse. The project might also gain future insights in what temperature and humidity environment specific plants thrive. The project took me (as an absolute beginner in IoT, Programming and electronics) about two three weeks to complete including the research time to gain a deeper understanding of the subject, the project will however take less time if there is experience in the relevant fields.
The tutorial is created by Filip Renström with the student id fr222jc.
*Materials*
* Pycom lopy4 [330SEK]
* This is the main controller in the project and will work as a mini processor.
https://www.mouser.se/ProductDetail/Pycom/LoPy-40?qs=MLItCLRbWsz2Ys%252BwjFa7JA==
* Pycom expansion board 3.0 [170 SEK]
* This board is used for easy connection to a computer, a fast way of connecting sensor cables and a quick way of connecting a battery.
https://www.mouser.se/ProductDetail/Pycom/Expansion-Board-V3?qs=MLItCLRbWswyAU64Xj3CwQ%3D%3D
* Sigfox and LoRa antenn (868MHz/915MHz for EU) [125SEK]
* This needs to be used if the device is using LoRa.
https://pycom.io/product/lora-868mhz-915mhz-sigfox-antenna-kit/
* 3,7V battery (500mha) [100SEK]
* This battery is used for the weather station to operate without being connected to a USB device.
https://www.kjell.com/se/produkter/el-verktyg/arduino/tillbehor/luxorparts-li-po-batteri-37-v-med-kontakt-500-mah-p87923
* Cables [75SEK]
* Cables are needed to connect the sensors to the processor.
https://www.kjell.com/se/produkter/el-verktyg/elektronik/elektroniklabb/delbar-kopplingskabel-40-pol-15-cm-hane-hona-p87076
* Temperature and humidity sensor (dht-11) [100SEK]
* This is the sensor responsible for capturing the data, other sensors can be used to capture other data.
https://www.kjell.com/se/produkter/el-verktyg/arduino/moduler/temperatur-och-luftfuktighetssensor-for-arduino-p87086
* (optional) 3D-printed case from Thingiverse
https://www.thingiverse.com/thing:1635315
Total cost: around 900 SEK (The materials bought at Kjell can be found cheaper online)
*Computer setup*
The device is programmed with MicroPython in the Atoms editor. This editor makes it easy to get a overview of the documents, import custom libraries and push code to the device. You can also quickly test a line of code by typing it directly into a command prompt.
First you need to upgrade the firmware of the device, this is done by following the link below and downloading the firmware updater for your system. When installing the new firmware select legacy firmware, the rest of the installation setting does not need to be tampered with.
https://pycom.io/downloads/
After the device is updated you can open atom.
From here you will first need to install the Pycom library (called pymakr), this is done by selecting settings -> package and searching for the pymakr package.
It's now time to connect your device, use a standard USB cable to do this. Be aware that some USB cables cannot transfer data and can’t be used. If your device does not connect try changing the cable. If everything is correct atom will find your device via a COM link, this is another name for USB connection. Ones Atom has found your device you can run code on it directly by typing it into the terminal on the bottom of the interface. Try typing:
```
import pycom
pycom.heartbeat(False)
pycom.rgbled(0xff00)
```
This should make the LED on the Pycom light up.
If this works then cofngratulations, you have just sent your first command to your device!
You can also try to type code into the main.py file in atom. After saving the document you can select "upload to device" to upload to code. This will make the code inside main.py run when the device starts.
*Connecting the sensor*
The sensor needs to be connected. There are 3 pins on the DHT-11 sensor. Connect the sensor as shown in the figure below. If the sensor has 4 there is not a board with the sensor and a different setup as well as a resistor is needed.
)
*uploading the code*
In the Atmos framework we need 3 files. boot.py main.py and dht.py. Boot.py is run on start-up of the device before main.py and does not need to be considered. main.py contains most of the code, including connecting to a network and sending the data to the server. dht.py is a driver for the sensor that needs to be used for us to read the data that the sensor read, this driver was created by Fredrik Ahlgren. The code can be found below, copy this to the file named dht.py:
```
import time
import pycom
from machine import enable_irq, disable_irq, Pin
class DHTResult:
'DHT sensor result returned by DHT.read() method'
ERR_NO_ERROR = 0
ERR_MISSING_DATA = 1
ERR_CRC = 2
error_code = ERR_NO_ERROR
temperature = -1
humidity = -1
def __init__(self, error_code, temperature, humidity):
self.error_code = error_code
self.temperature = temperature
self.humidity = humidity
def is_valid(self):
return self.error_code == DHTResult.ERR_NO_ERROR
class DHT:
'DHT sensor (dht11, dht21,dht22) reader class for Pycom'
#__pin = Pin('P3', mode=Pin.OPEN_DRAIN)
__dhttype = 0
def __init__(self, pin, sensor=0):
self.__pin = Pin(pin, mode=Pin.OPEN_DRAIN)
self.__dhttype = sensor
self.__pin(1)
time.sleep(1.0)
def read(self):
# pull down to low
self.__send_and_sleep(0, 0.019)
data = pycom.pulses_get(self.__pin,100)
self.__pin.init(Pin.OPEN_DRAIN)
self.__pin(1)
#print(data)
bits = []
for a,b in data:
if a ==1 and 18 <= b <= 28:
bits.append(0)
if a ==1 and 65 <= b <= 75:
bits.append(1)
#print("longueur bits : %d " % len(bits))
if len(bits) != 40:
return DHTResult(DHTResult.ERR_MISSING_DATA, 0, 0)
#print(bits)
# we have the bits, calculate bytes
the_bytes = self.__bits_to_bytes(bits)
# calculate checksum and check
checksum = self.__calculate_checksum(the_bytes)
if the_bytes[4] != checksum:
return DHTResult(DHTResult.ERR_CRC, 0, 0)
# ok, we have valid data, return it
[int_rh, dec_rh, int_t, dec_t, csum] = the_bytes
if self.__dhttype==0: #dht11
rh = int_rh #dht11 20% ~ 90%
t = int_t #dht11 0..50°C
else: #dht21,dht22
rh = ((int_rh * 256) + dec_rh)/10
t = (((int_t & 0x7F) * 256) + dec_t)/10
if (int_t & 0x80) > 0:
t *= -1
return DHTResult(DHTResult.ERR_NO_ERROR, t, rh)
def __send_and_sleep(self, output, mysleep):
self.__pin(output)
time.sleep(mysleep)
def __bits_to_bytes(self, bits):
the_bytes = []
byte = 0
for i in range(0, len(bits)):
byte = byte << 1
if (bits[i]):
byte = byte | 1
else:
byte = byte | 0
if ((i + 1) % 8 == 0):
the_bytes.append(byte)
byte = 0
#print(the_bytes)
return the_bytes
def __calculate_checksum(self, the_bytes):
return the_bytes[0] + the_bytes[1] + the_bytes[2] + the_bytes[3] & 255
```
The code of the main.py is split into two parts, the first part connects to the things network. For this to work you need to be in range of a gateway, in my experience this distance is about 3km but can be greater or smaller depending on things such as buildings or trees in the way, indoor or outdoor placement of the gateway as well as outdoor or indoor placement of the device you can’t to connect. The device will turn red when searching for a network and green for a few seconds ones it has found a gateway to the things network. The second part reads the data from the sensor and sends it over the things network. with this code new data is sent every two seconds. Copy the code below to the file main.py.
Remember to fill in your own information on the app_eui and app_key, these are personial for your device and can be found on the Things networks ones you logg on.
```
import time
from machine import Pin
from dht import DHT # can be found at https://github.com/JurassicPork/DHT_PyCom
import socket
from network import LoRa
import time
import ubinascii
import struct
import pycom
#connecting to the things netowrk
lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
pycom.heartbeat(False)
pycom.rgbled(0x7f7f00) # yellow
time.sleep(1.5)
app_eui = ubinascii.unhexlify('INPUT YOUR OWN APP EUI')
app_key = ubinascii.unhexlify('INPUT YOUR OWN APP KEY')
lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0)
while not lora.has_joined():
print('Not yet joined...')
pycom.rgbled(0x7f0000) # red
time.sleep(3)
print("Joined network")
pycom.rgbled(0xff00) #green
s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
s.setsockopt(socket.SOL_LORA, socket.SO_DR, 0)
s.setblocking(True)
s.bind(2)
#s.send(bytes([0x01,0x02]))
s.setblocking(False)
# get any data received...
#data = s.recv(64)
#print(data)
time.sleep(3)
pycom.heartbeat(True)
time.sleep(2)
#code to read the sensor data and send it over The things network
while True:
pycom.heartbeat(False)
th = DHT(Pin('P23', mode=Pin.OPEN_DRAIN), 0)
result = th.read()
temp = result.temperature
RH = result.humidity
print("Temp:", temp)
print("RH:", RH)
time.sleep(1)
package = struct.pack('>h',int(temp)) + struct.pack('>h',int(RH))
s.send(package)
pycom.rgbled(0xff00)
time.sleep(2)
pycom.heartbeat(True)
time.sleep(1)
#co2, voc = ccs_read.value()
#print('co2: ', co2)
#print('voc: ', voc)
```
*Setting up the things network and collecting the data*
the things network can be found in the link:
https://www.thethingsnetwork.org/
you can also find a map where all the gateways are located here:
https://www.thethingsnetwork.org/map
Create an account on the things network, then go to console and create a application followed by adding a device. The device EUI can be found in ATOM under device info or by running the code:
```
print("DevEUI: " + ubinascii.hexlify(lora.mac()).decode('utf-8').upper())
```
The app eui and app key for the code above can both be found in the console in the things network website.
Lastely we need to decode and tag all the data sent by the device. This is done under application -> payload functions. here we need to make a Javascript that will interpret the data and give different data different names. this is done in java. The code can be found below. This code will recode the data and label it temp and RH for temperature and room humidity respectively. Do not forget to click save after you have copied your code.
```
function Decoder(bytes, port) {
// first and second bytes are for temp
var temp = (bytes[0] << 8) | bytes[1];
// third and fourth bytes are for RH
var RH = (bytes[2] << 8) | bytes[3];
return {
temp: temp,
RH: RH
}
}
```
*Fetching the data and visualising it*
This is done with the help of Ubidots, a cloud service. This service is free for a limited number of devices and can therefore be used for prototyping and testing purposes, for more devices you need to pay a subscription. To setup a integration go to applications -> integrations on the things network website. Here you can create a new integration and find Ubidots. Create this integration.
Go to the Ubidots website and create an account. You can find the Token that is needed on the things network by clicking on your account in the top right corner and finding my credentials. Here the API key can be found as well. One’s everything is setup the things network will automatically send the data ones it's received. The device cannot be found on the ubidots website before the first sets of data is sent. The data til be presented in a graph on the Ubidots website. More integrations with the data such as giving you SMS alerts or E-mail alerts are possible.
*Final result*
Below graphs that present the data can be found. The top picture shows room humidity and the bottom room temperature.


Below the final weather station can be found.

