# Climate logger and motion detection with email alert, using LoPy4 and Raspberry Pi
### Adrian Höglund
#### Student ID: ah225bq
---
This project is about monitoring the temperature, humidity and sending out email alerts when motion is detected from a PIR sensor. Using Telegraf we will get data and save it to an InfluxDB and display it using Grafana, each running inside their own docker container on the raspberry pi.
**Approximate time: 5-10 hours**
---
### Objective
I personally built this device to be able to monitor the temperature and humidity but also to provide security by my door. I want to log the temperature so that I can test different solutions to lower the temperature in the room and look back at the results over time to determine the best option. It should also function as a burglar alarm and alert me by email when motion is detected.
### Materials
List of materials:
| Item |Link |Specifications|Price |
|--------------------------|-----------------------------------------------------|--------------|------------|
|Pycom Expansion Board 3.1 |[www.m.nu](https://www.m.nu/pycom/expansion-board-31) |USB and LiPo battery powered. LiPo battery charger. Reverse voltage protection. Size: 65 x 50 x 8mm. |199kr |
|Pycom LoPy4 |[www.pycom.io](https://pycom.io/product/lopy4/) |Espressif ESP32 chipset. LoRa, Sigfox, WiFi, Bluetooth. Programmable with MicroPython. Input: 3.3V 5.5V. RAM: 4MB. External flash: 8MB. GPIO: Up to 24.|365kr |
|Digital DHT11|[www.electrokit.com](https://www.electrokit.com/produkt/digital-temperatur-och-fuktsensor-dht11/) |Power supply: Min: 3V Typical: 5V Max: 5.5V. Current supply: Min: 0.5mA Max: 2.5mA. | 49kr |
|PIR mini SR602|[www.electrokit.com](https://www.electrokit.com/produkt/rorelsedetektor-pir-mini-sr602/) |Detection range: 3-5m. Current supply: 3.3 - 15V. | 59kr|
|Breadboard* |[www.electrokit.com](https://www.electrokit.com/produkt/kopplingsdack-400-anslutningar/) |Bus connections: 4. Connections: 400. Size: 82 x 55mm. |59kr|
Wire 1-pin |[www.electrokit.com](https://www.electrokit.com/produkt/labsladd-1-pin-hane-hane-150mm-10-pack/) |Wire male-male |29kr|
|Wire 1-pin |[www.electrokit.com](https://www.electrokit.com/produkt/labsladd-1-pin-hane-hona-150mm-10-pack/) | Wire male-female | 29kr
|Raspberry Pi 3/4 * | [www.kjell.com](https://www.kjell.com/se/produkter/dator/raspberry-pi/raspberry-pi-4-model-b-enkortsdator-4-gb-ram-p88181) |[Raspberry Pi specifications](https://www.raspberrypi.org/products/) | 690kr
|Total| | |1479kr|
*Optional
---
### Computer setup
#### Flash LoPy4 firmware
Download the firmware updater for your operating system from [[Pycom Updating-Firmware]](https://docs.pycom.io/gettingstarted/installation/firmwaretool/)
**Make sure your IDE is closed before opening the firmware updater so you can connect to the device.**
##### Step 1

##### Step 2

#### Computer
I am using Atom IDE with the pymakr plugin to connect to the device with USB and upload code. You can install Atom from [**here**](https://atom.io/) and [**this**](https://atom.io/packages/pymakr) is the plugin.
Node.js is also required for the pymakr plugin to work, depending on your operating system you can download it from [**here**](https://nodejs.org/en/download/)
#### Raspberry Pi
I chose to run the docker containers on the raspberry pi, so if you want to run it somewhere else you can skip this part.
Start by updating and upgrading your Raspberry Pi OS:
```bash
sudo apt update
sudo apt full-upgrade
```
Then we need [**docker engine**](https://docs.docker.com/engine/install/debian/), we will install it using the convenience script.
1. Download it:
```bash
curl -fsSL https://get.docker.com -o get-docker.sh
```
2. Run the installer:
````bash
sudo sh get-docker.sh
````
3. To use docker as non-root user without having to type sudo. Add your user to the docker group as follows(Log out and back in after):
````bash
sudo usermod -aG docker ${USER}
````
Next we need to install [**Docker Compose**](https://docs.docker.com/compose/install/), using python3 and pip3.
1. If you dont have python3 and pip3 installed, run these commands first:
````bash
sudo apt-get install libffi-dev libssl-dev
sudo apt install python3-dev
sudo apt-get install -y python3 python3-pip
````
2. Then install docker-compose using pip3:
````bash
sudo pip3 install docker-compose
````
Now our raspberry pi is ready to use docker-compose!
---
### Putting everything together
#### Circuit diagram

This is only a development setup. If you want to use it in production I recommend soldering wires to the sensors and buying/3D-printing a case for it.
When using the dht11 sensor with a module it has a built in pull-up resistor, but if you only have the bare sensor you need to add a 4k7 pull up resistor between the DATA pin and VCC.
---
### Platform
I use HiveMQ as my online MQTT broker to publish my sensor values to. Then I use telegraf locally on my raspberry to retrieve those values and store them inside my influxDB.
Grafana then retrieves the values from the database and displays it in a comprehensive way.
#### Flow:

A bit further down you will find the docker-compose file. If you want to use it, create a file and name it docker-compose with the extension (.yml) and paste the content. You also need to create a file in the same directory called .env (no name) to hold all your "secrets".
If you look at lines 30-38 you can see that I use string interpolation with placeholders so that secrets are hidden. You need to declare these yourself inside the .env file.
You also need to change the IP-address on lines 39 and 40 to the IP-address of the machine that will host the docker containers so that Grafana can render images, more on that in section "*Presenting the data*".
The `telegraf.conf` file is also necessary and needs to be placed in the same directory as your `docker-compose.yml` file. In the configuration file below you need to set the MQTT broker to the one you're using as well as the topic you want to subscribe to, and also change lines 14, 16 and 17 to your database information.
`telegraf.conf`
````=
[agent]
flush_interval = "15s"
interval = "15s"
[[inputs.mqtt_consumer]]
name_override = "hivemq"
servers = ["tcp://broker.hivemq.com:1883"]
qos = 0
connection_timeout = "30s"
topics = [ "home/groundFloor/#" ]
data_format = "json"
[[outputs.influxdb]]
database = "sensorValues"
urls = [ "http://influxdb:8086" ]
username = "Admin"
password = "mp"
````
After that, open your terminal and navigate to the directory where the docker-compose file is located and run the following command:
````bash
docker-compose up -d
````
To check that the containers are running type:
````bash
docker ps
````

If Grafana is not starting it might be user privileges related and if you look at line 28 I have added (user: "104"), so run the command below and it should be fixed. Change out the path to your specific absolute path.
You can also remove line 28 and then "chown" with Grafana default user id 472.
The data/grafana folder should be located in the same directory as the `docker-compose.yml` file.
````bash
sudo chown -R 104:104 /YOUR/ABSOLUTE/PATH/data/grafana
````
`docker-compose.yml`:
````=
version: '3.8'
networks:
tig-net:
driver: bridge
services:
influxdb:
image: influxdb:latest
container_name: influxdb
ports:
- 8086:8086
environment:
INFLUXDB_HTTP_AUTH_ENABLED: "true"
INFLUXDB_DB: "sensorValues"
INFLUXDB_ADMIN_USER: "Admin"
INFLUXDB_ADMIN_PASSWORD: "mp"
networks:
- tig-net
volumes:
- ./data/influxdb:/var/lib/influxdb
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- 3000:3000
user: "104"
environment:
- GF_SECURITY_ADMIN_USER=${ADMIN_USER}
- GF_SECURITY_ADMIN_PASSWORD=${ADMIN_PASSWORD}
- GF_SMTP_ENABLED=${SMTP_ENABLED}
- GF_SMTP_HOST=${SMTP_HOST}
- GF_SMTP_USER=${SMTP_USER}
- GF_SMTP_PASSWORD=${SMTP_PASSWORD}
- GF_SMTP_SKIP_VERIFY=${SMTP_SKIP_VERIFY}
- GF_SMTP_FROM_ADDRESS=${SMTP_FROM_ADDRESS}
- GF_SMTP_FROM_NAME=${SMTP_FROM_NAME}
- GF_RENDERING_SERVER_URL=http://192.168.1.121:8081/render
- GF_RENDERING_CALLBACK_URL=http://192.168.1.121:3000/
- GF_LOG_FILTERS=rendering:debug
volumes:
- ./data/grafana:/var/lib/grafana
networks:
- tig-net
restart: always
renderer:
image: adejong/grafana-image-renderer-pi:1.0.8-beta2
container_name: grafana-image-renderer
ports:
- 8081:8081
environment:
- ENABLE_METRICS=true
telegraf:
image: telegraf:latest
depends_on:
- "influxdb"
environment:
HOST_NAME: "telegraf"
INFLUXDB_HOST: "influxdb"
INFLUXDB_PORT: "8086"
DATABASE: "sensorValues"
volumes:
- ./telegraf.conf:/etc/telegraf/telegraf.conf
tty: true
networks:
- tig-net
privileged: true
````
If I would want to scale the idea then the first step would be to deploy my docker containers to some cloud hosting site such as AWS, Google cloud or Microsoft Azure.
---
### The code
I will not include the whole code only the most important parts to keep it short, but you can get it [**here.**](https://github.com/Softaren/IoT-Course)
Inside the file `main.py` I start the function `send()` with a new thread. When booting the first time, it will call the function `mqtHand.send_temp_value()` but if the device is woken up by the PIR sensor that has detected motion it will call the function `mqtHand.send_mvmt_value(True)`.
When those functions are done I call `Sleep()` which put the device to deep sleep for 3 hours or until the PIR sensor detects motion.
`main.py`
````python=
import mqttHandler as mqtHand
import _thread
import machine
# Send temp or mvmt values depending on wake_reason
def send():
if machine.wake_reason()[0] == 1:
mqtHand.send_mvmt_value(True)
else:
mqtHand.send_temp_value()
sleep()
# Go to deepsleep for 3 hours, allow P22 (PIR sensor) to wake machine so it's able to send motion detected,
# otherwise wake up every third hour to send temp data.
def sleep():
machine.pin_sleep_wakeup(['P22'], mode=machine.WAKEUP_ANY_HIGH, enable_pull=False)
print("Deepsleep for 3 hours")
machine.deepsleep(3 * 60 * 60 * 1000)
# Start thread to send data
_thread.start_new_thread(send, ())
````
The function `send_temp_value()` adds it specific topic and calls `read_dht.value()` which returns the sensor data from the dht11. Then it creates a JSON object with the data and passes it into `publish_sensor_value(topic, sensorData)` along with the topic.
The same goes for `send_mvmt_value(movement)` but instead of reading the data you pass in a boolean value depending on if the device was woken up by the sensor or not.
Function `send_temp_value()`:
````python=
def send_temp_value():
topic = topic_pub + "/temp"
try:
dht_T, dht_RH = read_dht.value()
print('dht temp: ', dht_T)
print('dht RH: ', dht_RH)
sensorData = {
"groundFloorTempAndHumi":{
"dht temp": dht_T,
"dht RH": dht_RH
}
}
publish_sensor_value(topic, sensorData)
except Exception as e:
print("Failed to read temp data")
````
The function `publish_sensor_value(topic, sensorData)` takes in two parameters. The topic it should publish to and the sensor data. First it connects the global MQTT client, then it tries to publish the data. If successful the led on the LoPy4 will blink green. When finished it will disconnect the client.
Function `publish_sensor_value(topic, sensorData)`:
````python=
def publish_sensor_value(topic, sensorData):
client.connect()
try:
client.publish(topic,json.dumps(sensorData))
print('Sensor data sent ..')
client.disconnect()
led.blink_led_green()
except(NameError, ValueError, TypeError) as e:
print("Fail to send data!")
print(e)
````
---
### Transmitting the data / connectivity
#### How often is the data sent
The temperature and humidity is sent every third hour when the device wakes up from the deep sleep timer. But motion detection send data every time a motion is detected, so that Grafana can send out email alerts.
#### Which wireless protocols were used
The only wireless protocols I used were WiFi. Unfortunately I was not within range of a LoRa gateway.
#### Which transport protocols were used
The docker containers are using UDP and TCP to communicate over the docker network and together with the transfer protocol smtp to send email alerts.
I am using MQTT to transport the sensor data from my device to the HiveMQ broker.
---
### Presenting the data
#### Dashboard

(Data sent more frequently for visualization purpose)
The dashboard is made with Grafana.
**Top** panel is called "Room Movement" and displays each time the PIR sensor has detected motion.
**Bottom left** panel is called "Room Humidity" and display the humidity in the room.
**Bottom right** panel is called "Room Temperature" and displays the Temperature in the room.
#### How often is data saved in the database
Data is saved every time I publish data from my device which is every third hour. But as I said before the PIR sensor send data every time it detects motion and this data also gets stored in the database.
#### Database
I Chose influxDB because it is optimized to handle large volumes of time series data, exactly the type of data we are dealing with. A relational database could handle the same type of workloads and data but not as optimized.
#### Alert triggers
Every time motion is detected Grafana sends out email alerts using gmail's smtp server.
The render service we created in the docker-compose file renders an image of the graph and includes it in the email.
It is worth mentioning that if you are using a raspberry pi with 32 bit architecture, Grafana's dockerhub [**image**](https://hub.docker.com/r/grafana/grafana-image-renderer) for the "image-renderer" doesn't work because it only supports 64 bit. That is why I am using a built modified image of the original to support 32 bit, available on docker hub [**here**](https://hub.docker.com/r/adejong/grafana-image-renderer-pi).
If you are on 64 bit architecture you can change the image on line 217 to `grafana/grafana-image-renderer:latest`
From `docker-compose.yml`
````=216
renderer:
image: adejong/grafana-image-renderer-pi:1.0.8-beta2
container_name: grafana-image-renderer
ports:
- 8081:8081
environment:
- ENABLE_METRICS=true
````
---
### Finalizing the design
Configuration:

I think the project went really well and was very educational. I have been doing software related stuff in the past but this was my first time doing anything Electrical engineering related and it was very interesting and has most certainly sparked my interest. I will continue to dive deeper and explore the world that is Electrical engineering.
---