---
# System prepended metadata

title: '[](#Tutorial "Tutorial")Tutorial - Check temperature year round'

---

[](#Tutorial "Tutorial")Tutorial - Check temperature year round
================================


[](#Tutorial-on-how-to-build-a-temperature-and-humidity-sensor "Tutorial-on-how-to-build-a-temperature-and-humidity-sensor")Tutorial on monitoring of temperature and humidity for a semi-remote location
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

This tutorial aims to setup a monitoring system for temperature and humidity in order to safeguard a remote location such as summer house. 

The tutorial has been created by Johannes Höier (credentials: jh224us) for an IoT-course (1DT305) at Linnéuniversitetet.

To complete the tutorial exactly as it is layed out would take roughly 2-3 hours (excluding delivery time of the hardware), but to also learn about all the concepts and adapt it to your own ideas migth take everything from 5-40 hours. 


### [](#Objective "Objective")Objective

In order to know if a window or if the ceiling of a semi-remote location, such as this tutorial writers summer house, is damaged a monitoring setup would help in letting the owner know that an incident has happened. This can enable the owner to handle the incident before it has become a major issue. Since the location is semi-remote, the monitoring needs to work year long and the data needs to be accessible online. But semi-remote also means that it is assumed there is mobile network coverage available, to enable the setup to rely on using WiFi. 


### [](#Material "Material")Material

The hardware was bought at https://www.electrokit.com and some was reused from spare parts.


| IoT Thing       | For this          |  Price in SEK |
| ------------- |:-------------:| :---:|
| Breadboard      | An intermediary plastic platform to connect wires from sensor to the LoPy4. (White plastic to the left in the picture) | 949 kr*|
| LoPy4      | Development platform for connecting pins to expansion board (The smaller rectangular chip on top of the larger chip, in the middle just where the usb-cable is connected to the larger chip)     | 949 kr* |
| Expansion board | Board for power, input and output (The larger rectangular chip with cables attached to it)       | 949 kr* |
| DHT11 sensor | A sensor the measures temperature and air humidity (Blue piece of plastic attached to the white bread board)       | 49 kr |
| Red, blue and green cable | Small cables that connect the sensor to the development boards       | 949 kr* |
| Power | An old iPhone-charger block and a usb-cable (White plastic in the top of the picture)       | ~100 kr |

\* part of a bundle totalling 949 kr


Here is the complete setup:
![](https://i.imgur.com/i2IFpRx.jpg)




### [](#Computer-setup "Computer-setup")Computer setup

I opted to use Atom as my IDE with the Pymakr-plugin, mainly because I've used Atom in the past. The Pymakr-plugin makes the upload of code (or "flashing") simple, as it only requires the push of a button to upload and reboot the pycome device. A caveat being that you need to save the files first, which is slightly different compared to standard cycle of code-test-code-test using a single keyboard shortcut to run a unit test suite.

My computer is an M1 Mac and that came with some issues such as:
 - Error running Atom and pymakr "gyp: No Xcode or CLT version detected!" and I believe I solved it with: "sudo xcode-select --reset"
 - Error using the Pycom Firmware update program which gave me the error "Failed to connect to ESP32: Invalid head of packet (\x08)" (solved through using the iOS app for activation instead)
 - Error using the activation one-liner for Pybytes which gave me the error "'nable to provision Sigfox! Please try again. Activation failed!" (seems like an error on the backend of PyBytes since I definitely didn't select SigFox in the setup) (solved through using the iOS app for activation instead)

### [](#Putting-everything-together "Putting-everything-together")Putting everything together

The wiring used:
![](https://i.imgur.com/Pv2JE70.png)

The setup is devolpment based in nature as it is using development components, but the idea is to use this year round. For real production it should be properly designed, ordered and CE-certified. However, one good next step for this setup would probably be to solder the sensor directly to a dedicated chip. 


#### Current lifecycle
- Sleeping 10 seconds
- Waking, checking DHT sensor and sending data over WiFi

The setup will draw 37mAh, or 0,185Wh. Calculations below:
```
from __future__ import division

sleep_draw = 30/60 # We never go to deep sleep, only idle. Converting from second to per minute
awake_draw = 107/60 # When we are active we use WiFi as client

sleepseconds = 10
awakeseconds = 1
awake_percentage = awakeseconds/(sleepseconds + awakeseconds) #insert how much time you're awake of the total time, for example if you sleep 100 seconds and awake 20, do 20/(100+20).

awake_minutes = awake_percentage * 60 #how many minutes of an hour you're awake
sleep_minutes = 60 - awake_minutes

active_cost = awake_draw * awake_minutes
sleep_cost = sleep_draw * sleep_minutes

total_cost = active_cost + sleep_cost #total mA per hour

print(total_cost)
```

Source of power draw: https://docs.pycom.io/gitbook/assets/specsheets/Pycom_002_Specsheets_LoPy4_v2.pdf

mAh × V / 1000 = Wh
37 * 5 / 1000 = 0,185


### [](#Platform "Platform")Platform
I've chosen to use a setup where I host a database, collector and visualiser on a VPS. This setup is called a TIG-stack. One attempt was made to use PyComs PyBytes, but it was deemed inferior due to the limitations in visualisations and the possibility that the free tier would not contain enough history. 

#### The VPS
The VPS is vultr which offers a european VPS for 5$ per month, but sadly I could not use the 2,5$ per month VPS because it required IPv6 only which Github and Docker doesn't support. I've chosen to use a VPS in order to be in control of the data and to make sure I, in the future, can use a selfhosted setup based on a Raspberry Pi. The amount of data stored determines the scaling options, but since this setup is only based on one device and since the idea is to identify if an incident has happened, no history is really needed and thus not much disk space is required.

### [](#The-code "The-code")The code
Here is main.py, the imported libraries are either standard or re-used from https://github.com/iot-lnu/applied-iot
    
    
```import json
import time
import read_dht
import pycom
import _thread
from mqtt_client import MQTTClient
import ubinascii
import hashlib
import machine

pycom.heartbeat(False)

# Load configuration parametersfor the MQTT connection
with open('config.json') as f:
    config = json.load(f)

# Helper method to connect to WiFi and reconnect! if connection is missing
def connect_wifi():
    from network import WLAN
    import machine
    import keys
    wlan = WLAN()
    if not wlan.isconnected():
        wlan = WLAN(mode=WLAN.STA)
        # Keys are placed in separate file in order to make it easier to get help without exposing private keys
        wlan.connect(ssid=keys.wifi_ssid, auth=(WLAN.WPA2, keys.wifi_password))
        print("Trying to connect...")
        # We use delays to allow WiFi to be down up to 90 seconds before giving up
        x = 0
        for x in range(0, 9):
            try:
                if not wlan.isconnected():
                    machine.idle()
                    x += 1
                    print("No wifi found, waiting 10s")
                    time.sleep(10)
                else:
                    x = 9
                    print("WiFi connected succesfully")
                    return True
            except (Exception) as err:
                print("error: {0}".format(err))
                import machine
                machine.reset()

# Enables pycom board to set LEDs according to info from server (messages from server not used right now though)
def sub_cb(topic, msg):
    if msg == b'{"Command":"Red"}': pycom.rgbled(0xff0000)
    if msg == b'{"Command":"Blue"}': pycom.rgbled(0x0004ff)
    if msg == b'{"Command":"Green"}': pycom.rgbled(0x00ff04)
    if msg == b'{"Command":"Yellow"}': pycom.rgbled(0xe5ff00)
    if msg == b'{"Command":"White"}': pycom.rgbled(0xe5ff00)
    if msg == b'{"Command":"Off"}': pycom.rgbled(0x000000)
    print((topic, msg))

# Helper method for threading to work
def interval_send(t_):
    while True:
        send_value()
        print("Sleeping " + str(t_) + " seconds")
        time.sleep(t_)

# Test method used during devolpment
def blink_led():
    for n in range(3):
        pycom.rgbled(0x100000)
        time.sleep(0.1)
        pycom.rgbled(0x000010)
        time.sleep(0.1)
        pycom.rgbled(0x100000)
        time.sleep(0.1)
        pycom.rgbled(0x000000)

# Method for sending DHT11 information (temperature and humidity).
# Attempts to reconnect to WiFi if no network is available.
# If any issues is reported the LED will be set to red to inform people in its vicinity that there is a problem
def send_value():
    try:
        dht_T, dht_RH = read_dht.value()
        c.publish(topic_pub,'{"living_room_sensor": {"dht11 temp":' + str(dht_T) +
                  ',"dht11 RH":' + str(dht_RH) +
                  '}}')
        print('Sensor data sent ..')
    except (NameError, ValueError, TypeError, OSError) as err:
        print('Failed to send! OS error: {0}'.format(err))
        import machine
        machine.reset()

# here follows main code, using helper methods from above

# We start with connecting to WiFi, not using boot.py setup due to issues with reconnection and troubleshooting
while (not connect_wifi()):
    time.sleep(120)

topic_pub = 'devices/raspberry-height/'
topic_sub = 'devices/raspberry-height/control'
client_name = ubinascii.hexlify(hashlib.md5(machine.unique_id()).digest()) # create a md5 hash of the pycom WLAN mac

c = MQTTClient(client_name,server=config['broker_url'],user=config['user_mqtt'],password=config['pass_mqtt'])
c.set_callback(sub_cb)
c.connect()
c.subscribe(topic_sub)

def listen_command(i_):
    while True:
        c.check_msg()
        time.sleep(i_)

_thread.start_new_thread(interval_send,[10])
_thread.start_new_thread(listen_command,[0.1])

```
    

### [](#Transmitting-the-data--connectivity "Transmitting-the-data--connectivity")Transmitting the data / connectivity

The project is setup to use WiFi as this was readily available. SigFox is an option as well, according to the coverage map. 

For SigFox data could only have been sent every 11 minutes, but with WiFi the periodicity can be much shorter. Also, the project is setup to use a wall socket power, running through an old iPhone-power brick which means battery consumption is not an issue. This project settled on data being sent every 10 seconds. Main reason being that development is easier that way, with fast feedback. However, humidity and temperature will likely not change that fast enough to warrant once per minute updates.

As we are using the TIG Stack, we are using MQTT as a broker and relying on a LNU-supplied server for the initial setup, the idea is to move also this to be self hosted. 


### [](#Presenting-the-data "Presenting-the-data")Presenting the data

The setup uses telegraph for getting data from a MQTT service, which the PyCom board publishes to, and InfluxDB which stores the data and lastly Grafana which visualises the data. This is what the visualisation looks like:

![](https://i.imgur.com/iRJoKNj.png)

The data is sent every 10 seconds.

I've chose to use InfluxDB as it was easy to get up and running, but also it fits the bill as it is used for time series data which we will be storing. 

There is currently no triggers connected to the data, but in the future this will be good to add as the idea is to protect the summer house from incidents.

The automation in place, besides the services provided by Telegraph, InfluxDB and Grafana is that three services are glued together by Docker which in turn automatically starts up if the server is rebooted.


### [](#Finalizing-the-design "Finalizing-the-design")Finalizing the design

The pictures above show the hardware and the resulting visualization, which completes the setup. 

There is still some work to be done in making sure the setup is working no matter what, so additional code to handle error cases needs to be added. 

The results are all right, it has been a warm summer! And the times where I've been away from the house I could monitor it. It was very clear that closing the doors made the indoor temperature go higher for example.

