owned this note
owned this note
Published
Linked with GitHub
# Real-Time Environmental Monitoring for a Gaming Room/Office using TIG-stack and Docker
## Author
Adam Engström (ae224yu)
## Short Project Overview
This project demonstrates how to build an IoT system to monitor temperature, humidity, and light levels in a gaming room/office (or any other room) using a Raspberry Pi Pico WH. The collected data is sent to an MQTT broker, processed by a TIG stack (Telegraf, InfluxDB, Grafana), and visualized in real-time using Grafana dashboards. The entire system runs within Docker containers on your computer.
### Time Estimate
The estimated time to complete this project is approximately 6-8 hours.
## Objective
In this project, I have chosen to build a real-time environmental monitoring system for my gaming room/office, which is quite small and in the far end of the apartment, so it can get really warm and dark in there. The primary reasons for undertaking this project are both practical and educational. I decided to do this project to gain hands-on experience with IoT devices, MQTT communication, and Docker containerization. Additionally, I wanted to create a practical solution to monitor and maintain an optimal environment in my gaming room/office.
### Purpose
The main purpose of this device is to monitor environmental parameters such as light intensity, temperature, and humidity within the gaming room/office. By keeping track of these factors, I aim to ensure a comfortable and consistent environment for gaming and other activities.
The idea grew from when I got home from a couple of years away from my apartment and changed the guest room into a gaming room/office. After a couple of sessions in the room, I noticed that it get really warm and dark in there and the idea of keeping track of the environment grew.
Overall, this project not only serves a practical need but also enhance my technical skills and understanding of IoT systems.
## Materials
For this project, I used the Raspberry Pi Pico WH along with a breadboard, three different sensors and jumper wires. Below is a list of all materials used, along with their purpose and costs. All materials were bought at electrokit.com.
| Product | Purpose | Cost |
|-----------------------------|----------------------------------------------------------------------------------------------|-------|
| Raspberry Pi Pico WH | Main controller for the device. | 109 kr|
| Breadboard, 840 connections | For connecting all the components together. | 69 kr |
| Temperature sensor DS18B20 | Measures temperatures between -55C to 125C and has an accuracy of 0.5+- degrees. | 42 kr |
| DHT11 | Measures temperature and humidity, between 0-50C and 20-90%RH and has an accuracy of 2+- degrees and 5+-%RH. | 49 kr |
| Photoresistor CdS 4-7 kohm | Measures light intensity by varying the resistance based on the intensity of the light. | 8 kr |
| Resistor 4.7 kohm | Connects with the photoresistor to get a measurable value from the voltage of the light intensity. | 3 kr |
| Jumper wires (male to male) 30-pack | Used to connect all the components to the microcontroller on the breadboard. | 39 kr |
| **Total** | | 319 kr|
**NOTE**: You can just stick with the DHT11 for temperature as well and reduce the cost of the device if you don't mind that it has poor accuracy.
## Computer Setup
In this section, I'll go through the steps required to set up your computer for programming the Raspberry Pi Pico with MicroPython.
### Flash MicroPython Firmware on Raspberry Pi Pico
Before you can upload your MicroPython code, you need to flash the MicroPython firmware onto the Raspberry Pi Pico.
1. Download the MicroPython firmware for the Raspberry Pi Pico from the official MicroPython [website](https://micropython.org/download/RPI_PICO_W/).
2. Connect your Raspberry Pi Pico to your computer while holding down the BOOTSEL button to put it in USB mass storage mode.
3. Drag and drop the downloaded MicroPython firmware (a .uf2 file) onto the RPI-RP2 drive that appears on your computer. The Pico will automatically reboot with MicroPython installed.
### Docker Desktop
You should also download docker desktop to your computer, you can download the software [here.](https://www.docker.com/products/docker-desktop/)
### Chosen IDE
For this project, I used Visual Studio Code as the IDE.
### Steps for Setting Up the Development Environment
1. Download and install Visual Studio Code from the [official website](https://code.visualstudio.com/download). Follow the installation instructions for your operating system.
2. **Install Node.js**: Node.js is required for the PyMakr extension, which simplifies communication between your computer and the Raspberry Pi Pico. Download and install Node.js from the [official website](https://nodejs.org/en/download/package-manager).
3. **Install the PyMakr Extension**:
- Open VS Code.
- Go to the Extensions view by clicking on the Extensions icon in the Activity Bar on the left side of the window.
- Search for "PyMakr" and click on the "Install" button.
You will now have a tab on your left side with PyMakr, press on it and press “Create project”. Enter the desired name of the project. After that, you should plug in your Raspberry Pi Pico to the computer and it should appear on the left side of the window under the “Devices” section. Hover over it and press the lightning icon to connect to the device.

Press the “start development mode” button next to your project name and it will upload the code to the device and start it. 
## Putting everything together
Here is the set up for connecting all the sensors to the Pico.

## Platform
For this project, I went for a self-hosting installation platform using Docker compose to deploy a TIG stack (Telegraf, InfluxDB, and Grafana) along with a Mosquitto MQTT broker.
### Functionality of the Platform
- **Mosquitto MQTT Broker**: Acts as a message broker for MQTT protocol, facilitating communication between IoT devices and the server. It receives sensor data from the Raspberry Pi Pico and forwards it to Telegraf.
- **Telegraf**: Collects, processes, and forwards data to InfluxDB. It subscribes to MQTT topics from the Mosquitto broker and writes the sensor data to InfluxDB.
- **InfluxDB**: A time-series database optimized for high-availability storage and retrieval of time series data. It stores the sensor data received from Telegraf.
- **Grafana**: An open-source platform for monitoring and observability. It visualizes the data stored in InfluxDB, providing a user-friendly dashboard to monitor sensor readings.

### Docker compose
I created a directory called "TIG-stack" which would hold the docker-compose.yml and other configuration files for the components of the stack. The docker-compose looks like this.
```
services:
mosquitto:
image: eclipse-mosquitto:latest
container_name: mosquitto
ports:
- "1883:1883"
- "9001:9001"
volumes:
- mosquitto_data:/mosquitto/data
- mosquitto_log:/mosquitto/log
- ./mosquitto:/etc/mosquitto
- ./mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf
networks:
- tig-net
influxdb:
image: influxdb:1.8.6
container_name: influxdb
ports:
- "8086:8086"
volumes:
- influxdb_data:/var/lib/influxdb
- ./init-influxdb.sh:/docker-entrypoint-initdb.d/init-influxdb.sh
environment:
- INFLUXDB_DB=(DATABASE_NAME)
- INFLUXDB_ADMIN_USER=(YOUR_ADMIN_NAME)
- INFLUXDB_ADMIN_PASSWORD=(YOUR_ADMIN_PASSWORD)
networks:
- tig-net
telegraf:
image: telegraf:1.19.0
container_name: telegraf
depends_on:
- influxdb
- mosquitto
volumes:
- ./telegraf.conf:/etc/telegraf/telegraf.conf:ro
networks:
- tig-net
grafana:
image: grafana/grafana:7.5.9
container_name: grafana
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_USER=(ADMIN_USERNAME)
- GF_SECURITY_ADMIN_PASSWORD=(ADMIN_PASSWORD)
networks:
- tig-net
volumes:
mosquitto_data:
mosquitto_log:
influxdb_data:
grafana_data:
networks:
tig-net:
driver: bridge
```
**NOTE:** The parentheses "()" in the file abowe indicates the users chosen usernames and passwords for the TIG-stack components.
### Mosquitto.conf
For the mosquitto.conf file I followed this [guide](https://cedalo.com/blog/mosquitto-docker-configuration-ultimate-guide/), for setting up the configuration of the mosquitto broker. In the guide however, when they are setting up the password-file without the compose set up. By running ```docker compose up -d``` in a terminal window of the working directory, will download and start the TIG-stack and then configure the password-file. After setting up the password-file, just type ```docker compose down```.
```
persistence true
persistence_location /mosquitto/data/
persistence_file mosquitto.db
log_dest file /mosquitto/log/mosquitto.log
listener 1883
allow_anonymous false
password_file /etc/mosquitto/passwd
```
### Telegraf.conf
For the telegraf.conf file I wrote this:
```
[agent]
interval = "15s"
flush_interval = "15s"
[[outputs.influxdb]]
urls = ["http://influxdb:8086"]
database = "(YOUR_INFLUXDB_NAME)"
username = "(YOUR_INFLUX_USER)"
password = "(YOUR_PASSWORD)"
write_consistency = "any"
[[inputs.mqtt_consumer]]
servers = ["tcp://mosquitto:1883"]
topics = [
"gamingroom/sensor/temperature",
"gamingroom/sensor/humidity",
"gamingroom/sensor/light"
]
qos = 0
connection_timeout = "30s"
client_id = "telegraf"
username = "(MOSQUITTO_USERNAME)"
password = "(MOSQUITTO_PASSWORD)"
data_format = "json"
tag_keys = ["topic"]
```
**NOTE:** username and password for influx are the user and password you wrote in the docker-compose.yml. For the mosquitto it is the user and password when setting up the configuration in the previous part.
**NOTE:** The mosquitto will refuse the connection of the telegraf if you use ```http://mosquitto:1883```. So instead use ```tcp://```as shown above in the telegraf.conf file.
## The code
The code is split into smaller modules to keep the ```main.py``` and ```boot.py``` files low on code. The main parts of the code is setting up a WiFi connection, establish a connection to the mqtt broker, read data from sensors and then transmitting the data to the mqtt broker.
### WiFi connection
The ```boot.py```file calls the function ```connect()``` to establish a WiFi connection for the Pico when the device is turned on. (The source code can be found [here](https://hackmd.io/@lnu-iot/rJVQizwUh)).
**NOTE:** As you see on line 12 when connecting to the WiFi it says: ```keys.WIFI_SSID``` and ```keys.WIFI_PASS```, you should have a seperate file with credentials and import them to keep passwords and other things hidden.
```
import keys
import network
from time import sleep
def connect(): # Function that ensures a connection to your local wifi
wlan = network.WLAN(network.STA_IF)
if not wlan.isconnected():
print('connecting to network...')
wlan.active(True)
wlan.config(pm = 0xa11140)
wlan.connect(keys.WIFI_SSID, keys.WIFI_PASS)
print('Waiting for connection...', end='')
while not wlan.isconnected() and wlan.status() >= 0:
print('.', end='')
sleep(1)
ip = wlan.ifconfig()[0]
print('\nConnected on {}'.format(ip))
return ip
def disconnect(): # Function that disconnect to the wifi
wlan = network.WLAN(network.STA_IF)
wlan.disconnect()
wlan = None
```
### Main-file
For connecting to the mqtt broker I've used the ```umqtt.simple``` library, which can be found [here](https://github.com/micropython/micropython-lib/tree/master/micropython/umqtt.simple). Once the connection is established, I save the boolean value in ```successful``` and start the main while-loop for reading and sending the sensor-data to the broker.
```
import time, json
from lib import dhtLib, ds18Lib, photoResLib, mqttKeys, connectMqtt
humidity, temperature, light = None, None, None
successful = connectMqtt.connectToMqtt() # Connect to mosquitto broker
def read_sensors(): # Function that reads from the sensors, which are located in other files.
global humidity, temperature, light
humidity = dhtLib.read_dht11()
temperature = ds18Lib.read_ds12b20()
light = photoResLib.read_light_percentage()
def send_data(): # Converts data to json and sends it to the mosquitto broker with the right topic
global temperature, humidity, light
temp_json = json.dumps({'temp': temperature})
humid_json = json.dumps({'humid': humidity})
light_json = json.dumps({'light': light})
connectMqtt.publishToMqtt(mqttKeys.MQTT_TOPIC_TEMP, temp_json)
connectMqtt.publishToMqtt(mqttKeys.MQTT_TOPIC_HUMID, humid_json)
connectMqtt.publishToMqtt(mqttKeys.MQTT_TOPIC_LIGHT, light_json)
while successful: # Main loop, executes if connection to the broker is successful
try:
read_sensors()
send_data()
except Exception as error:
print("Exception occurred", error)
time.sleep(60)
```
### Read_light_percentage
The sensor-libraries are set up the same with imports, connecting to the pins and a read-function that returns the value from the sensor. But the photo resistor is a little bit special in terms of what type of data it returns. The ```read_u16```function returns a raw value in the range of 0-65535, where lower values indicates higher light and vice versa.
By subtracting the value with the max possible value, then divide it with the max value and at last multiply it with 100, gives a nice percentage value between 0-100 which is much more readable than value ranging from 0-65535. So this function returns a higher percentage when there is sufficient light and lower percentage when it's dark.
```
from machine import ADC, Pin
photo_res = ADC(Pin(26))
def read_light_percentage():
value = photo_res.read_u16()
light_percantage = ((65535 - value) / 65535) * 100
return light_percantage
```
## Transmitting the Data / Connectivity
### Data Transmission Method
MQTT protocol is used to transmit sensor data from the Raspberry Pi Pico to the local TIG-stack server.
### Steps to Transmit Data
- **Collect Data**:
- Sensors (DS18B20 for temperature, DHT11 for humidity, CDS photoresistor for light) gather data every minute.
- **Format Data**:
- Data is packaged into JSON format.
- **Publish Data**:
- Using the `umqtt.simple` library in MicroPython, the Pico connects to the Mosquitto MQTT broker. The data is published to these topics:
- `gamingroom/sensor/temperature`
- `gamingroom/sensor/humidity`
- `gamingroom/sensor/light`
### Wireless and Transport Protocols
- **WiFi**: Chosen for its reliability and ease of integration with home networks.
- **MQTT**: A lightweight protocol optimized for efficient data transmission in low-bandwidth networks.
## Presenting the Data
### Dashboard Overview
The data from the sensors is visualized using Grafana, providing a real-time and historical view of the gaming room/office environment.
### Dashboard Components
1. **Single Stat Panels**:
- **Temperature**: Displays the current temperature in Celsius.
- **Humidity**: Shows the current humidity level.
2. **Gauge Panel**:
- **Light**: Indicates the current light intensity as a percentage.
3. **Time Series Panels**:
- **Temperature Over Time**: Plots temperature data to visualize changes over time.
- **Humidity Over Time**: Shows humidity levels over time.

### Data Preservation and Frequency
- **Data Retention**: The data is stored in the InfluxDB database for two weeks, but that can be changed.
- **Data Saving Frequency**: Sensor data is transmitted and saved to the database every minute.
## Finalizing the Design
#### Final Results
The project successfully monitors the temperature, humidity, and light levels in my gaming room/office and visualizes the data in real-time using Grafana. The data is collected by sensors connected to a Raspberry Pi Pico WH, transmitted via MQTT, and processed and stored in a TIG stack (Telegraf, InfluxDB, Grafana) running in Docker containers.


#### Project Reflections
The project provided valuable hands-on experience with IoT devices, MQTT communication, and Docker containerization. The path of doing a self-hosted solution helped me to better understand how to manage and deploy a fullstack. The coding wasn't that big of an issue, but the code really could need improvements.
#### Improvements and Future Work
- **Accuracy of Sensors**: The DHT11 sensor could be replaced with a more accurate sensor for better humidity readings. Also both the DS18B20 and DHT11 could be replaced with the DHT22.
- **Alert System**: Implementing an alert system in Grafana to notify when the environmental parameters exceed certain thresholds would enhance the system's functionality.
- **Scalability**: The project can be scaled to monitor multiple rooms or different environments by adding more sensors and adjusting the data processing setup accordingly.
- **Green house**: A soil moisture sensor could be added to the device and it would be an effective green house monitor.
- **Wiring**: The wires on the device are all over the place and could with an effort be better.
#### Final Thoughts
This project not only fulfilled its primary objective but also served as a great education into the world of IoT and data visualization. This project was really fun and be able to get hands on experience with hardware, when previous experience has only circled around software. My internet provider of course had alot of issues during the development, where I was stuck without internet for 30 minutes up to 5 hours every other day. But in the end I managed to pull through and got everything up and running. This will definetly not be the last IoT I will make in the future.