###### Tags: `IoT` `Pycom` `Lopy4` `MQTT` `TIG Stack` `Micropython` # Attic Monitoring using IoT _written by Magnus Passi, mp223yb_ ## Table of contents * [Project Overview](#Project-Overview) * [Objective](#Objective) * [Material](#Material) * [Main components](#Main-components) * [Sensors](#Sensors) * [Miscellaneous](#Miscellaneous) * [Computer setup](#Computer-Setup) * [Putting everything together](#Putting-everything-together) * [Platform](#Platform) * [MQTT](#MQTT) * [Telegraf](#Telegraf) * [InfluxDB](#InfluxDB) * [Grafana](#Grafana) * [The code](#The-code) * [Configuration file](#Configuration-file) * [Establish network connection](#Establish-network-connection) * [Code for the main application](#Code-for-the-main-application) * [Main functions](#Main-functions) * [MQTT](#MQTT) * [Sensors](#Sensors) * [Transmitting the data / connectivity](#Transmitting-the-data-/-connectivity) * [Presenting the data](#Presenting-the-data) * [Finalizing the design](#Finalizing-the-design) * [Final thoughts](#Final-thoughts) ## Project Overview Having your own house may have it's advantages but it also brings more responsibilities and things to be worried about. One of those worries are mold. This tutorial will show you how to build a device which can monitor environmental qualities such as temperature, relative humidity, carbon dioxide (eCO2) and total volatile organic compounds (TVOC). In my case, I will use it in the attic to monitor if there is a risk of mold but it could have other use cases. The device collects data which is transmitted to a virtual machine which presents the data in a web interface. __Estimated time to build:__ ~3-8 hours (depending on previous experience). ## Objective The objective with this project is to explore the possibilites with IoT and to gain more experience. With the chosen project more experience will be gained by learning how to interact with an __IoT__-device, a __Lopy4__ in this case, learn how to connect and use sensors, setting up the enviroment for transmission and presentation and also gain more experience with the __Python__/__Micropython__ programming language. The project will gather information about the air quality in the attic and present the data in an accessible way which may lead to prevention of mold or other hazards. ## Material Materials used in this project is presented in tables below with prices, functions and links to where they can be bought. :::info I happened to find most of the parts used. The prices here are based on the vendors. ::: ### Main components ![lopy4](https://pycom.io/wp-content/uploads/2018/08/lopySide-1.png) _The Pycom Lopy4. Image source: [Pycom](https://pycom.io/)_ | Part | Function | Price | Link | | :--------------------- | :-------------- | ------: | ------------------------------------------- | | Pycom Lopy4 | Microcontroller | €38.45 | [pycom.io](https://pycom.io/product/lopy4/) | | Pycom Expansion Board 3 | Expansion board | €17.60 | [pycom.io](https://pycom.io/product/expansion-board-3-0/) | ### Sensors | Part | Function | Price | Link | | :----- | :------------------------------ | -----: | ---- | | DHT11 | Temperature and humidity sensor | €5.24 | [Electrokit](https://www.electrokit.com/produkt/digital-temperatur-och-fuktsensor-dht11/) | | CCS811 | TVOC and eCO2 sensor | €29.85 | [Electrokit](https://www.electrokit.com/produkt/adafruit-ccs811-air-quality-sensor-breakout-voc-and-eco2/) | ### Miscellaneous | Part | Function | Price | Link | | :--- | :------- | ----: | ---- | | USB cable | For connecting to and powerering the Expansion Board | €5.24 | [Electrokit](https://www.electrokit.com/produkt/usb-kabel-a-hane-micro-b-hane-3m/) | | Breadboard | For easier connections between sensors and the Expansion board | €6.31 | [Electrokit](https://www.electrokit.com/produkt/kopplingsdack-400-anslutningar/) | | Jump wires | For connections between the breadboard and the Expansion board | €4.17 | [Electrokit](https://www.electrokit.com/produkt/kopplingstrad-byglar-for-kopplingsdack-mjuka-65st/) | | WiFi antenna | For better connection to WiFi | €11.66 | [Electrokit](https://www.electrokit.com/produkt/antenn-2-4ghz-5dbi-rp-sma/) | | Li-Po battery | Makes the device portable | €9.31 | [Kjell & Company](https://www.kjell.com/se/produkter/el-verktyg/arduino/arduino-tillbehor/luxorparts-li-po-batteri-37-v-med-kontakt-1200-mah-p87924) | | Case | For protection of the device | €8.85 | [Biltema](https://www.biltema.se/bygg/elinstallationer/eldosor/kopplingsdosa-130-x-220-x-95-mm-2000047448) | ## Computer setup The development environment consist of a laptop running __Fedora__ as operating system (OS) and __Atom__ as integrated development environment (IDE). For the IDE to be able to communicate with the __Lopy4__ a plugin needs to be installed, __pymakr__. The documentation provided by __Pycom__ on their website is a good way to learn how to proceed. [This guide](https://docs.pycom.io/gettingstarted/) is a good starting pointing point. Below are some steps for getting started. 1. Install an IDE, __pymakr__ is available for __Atom__ and __VS Code__ 2. Install __pymakr__ 3. Install __Node.js__ if needed 4. Close the IDE 5. Connect your device 6. If needed, upgrade the firmware using [this guide](https://docs.pycom.io/updatefirmware/device/) 7. Open your IDE If everything went well you should be able to interact with the device using a terminal in your chosen IDE. ![success](https://i.imgur.com/gFjrY31.gif) _Signs of success!_ :::warning If you're not able to interact with your device, you might need to add your user to the dailout group. ```bash sudo usermod -aG dailout $USER ``` ::: ## Putting everything together To get started with connecting all the hardware and start experimenting, using the [documentation](https://docs.pycom.io/gitbook/assets/specsheets/Pycom_002_Specsheets_LoPy4_v2.pdf) is the best way of gaining the required knowledge. If you are new to electronics, learning how to use a breadboard is a good start. [This article](https://thimble.io/how-to-use-a-breadboard-an-in-depth-guide/) is a good place to learn about simple electronics and breadboards. The [documentation](https://docs.pycom.io/gitbook/assets/specsheets/Pycom_002_Specsheets_LoPy4_v2.pdf) contains the pinout information which enables you to know which pins to use for your sensors. The sensors used in this project are a __DHT11__ and a __CCS811__. The __DHT11__ needs a digital pin and the __CCS811__ needs the __SCL__ and __SDA__ pins to function. Below is an example of how it can be connected. ![fritzing](https://i.imgur.com/qH48C9z.png) :::warning I had some trouble getting my DHT11 to work properly. I thought I had a faulty sensor but it turned out I had a bad library. After testing a library from a secondary source, the sensor started to work. ::: ## Platform The platform for this project is based on a self hosted solution and open source software. The data will be transmitted with the __MQTT__ protocol. All the backend software will be installed on a virtual machine on a private server. The software that will be installed is the so-called __TIG__-stack (__T__ stands for __Telegraf__, __I__ stands for __InfluxDB__ and __G__ stands for __Grafana__). This stack handles everything from data collection to presentation. The __TIG__-stack was installed using a __`docker`__ compose file, code below: ```yaml volumes: tig-data: services: influxdb: image: influxdb:1.8 container_name: influxdb ports: - 8086:8086 environment: INFLUXDB_HTTP_AUTH_ENABLED: "true" INFLUXDB_DB: "iot" INFLUXDB_ADMIN_USER: "INSERT_USERNAME_HERE" INFLUXDB_ADMIN_PASSWORD: "INSERT_PASSWORD_HERE" volumes: - tig-data:/var/lib/influxdb grafana: image: grafana/grafana container_name: grafana ports: - 3000:3000 environment: GF_SECURITY_ADMIN_USER: "INSERT_USERNAME_HERE" GF_SECURITY_ADMIN_PASSWORD: "INSERT_PASSWORD_HERE" volumes: - tig-data:/var/lib/grafana restart: always telegraf: image: telegraf:1.19.0 depends_on: - "influxdb" environment: HOST_NAME: "telegraf" INFLUXDB_HOST: "influxdb" INFLUXDB_PORT: "8086" DATABASE: "iot" volumes: - ./telegraf/telegraf.conf:/etc/telegraf/telegraf.conf tty: true privileged: true ``` ### MQTT __MQTT__ is a light-weight messaging protocol. It is designed to minimise network bandwidth and device resource requirements while still provide reliability and some level of assurance of delivery. In this project, the data will from the IoT device will be sent using this protocol. _[https://mqtt.org/](https://mqtt.org/)_ ### Telegraf __Telegraf__ is a server-based agent which can collect and send metrics and events from databases, systems and __IoT__ devices. In this project, __Telegraf__ will collect the data from the __MQTT__ broker and send it to a database. _[https://www.influxdata.com/time-series-platform/telegraf/](https://www.influxdata.com/time-series-platform/telegraf/)_ ### InfluxDB __InfluxDB__ is a database optimised for time-series-based applications. It will act as the database for storing the data in this project. _[https://www.influxdata.com/products/influxdb/](https://www.influxdata.com/products/influxdb/)_ ### Grafana __Grafana__ is a monitoring solution which has support for many different databases. In this project, it will mainly act as a web interface for visualizing the data. It can be used in many more different ways. _[https://grafana.com/](https://grafana.com/)_ ## The code The microcontroller used in this project is a __Pycom Lopy4__ which supports __Micropython__. The code is written in this language as well as some __JSON__. ### Configuration file This is a file written in __JSON__ which contains credentials for __WiFi__ and __MQTT__ in this project. I felt that seperating the credentials made it easier when working with different __WiFi__ connections and different __MQTT__ servers. ```json { "wifi": [ { "ssid": "INSERT_SSID_HERE", "passwd": "INSERT_WIFI_PASSWORD_HERE" } ] "mqtt": [ { "id": "INSERT_MQTT_ID_HERE", "broker_ip": "INSERT_BROKER_ID_HERE", "port": "INSERT_MQTT_PORT_HERE", "topic": "INSERT_MQTT_TOPIC_HERE" } ] } ``` ### Establish network connection The __`boot.py`__ executes before the __`main.py`__ file which makes it a good place to have the code for __WiFi__ connectivity. The code for establishing a network connection is located in the __`boot.py`__ file. Some of the code parses the information from the configuration file using the __`json`__ module. ```python import json with open('config.json', 'r') as f: data = json.load(f) f.close() for wifi in data['wifi']: ssid = wifi['ssid'] wifi_passwd = wifi['passwd'] ``` With the necessary information for the WiFi connection, the rest of the code handles the establishing of a connection. A timeout argument is added so the device does not try to connect indefinitely. ```python import machine from network import WLAN wlan = WLAN(mode=WLAN.STA) wlan.connect(ssid, auth=(WLAN.WPA2, wifi_passwd), timeout=5000) while not wlan.isconnected(): machine.idle() print("Connected to Wifi\n") ``` ### Code for the main application The __`main.py`__ file is the file which will contain the code for the main application that will be run by the microcontroller. For this project, a number of external libraries has been used. External libraries will be placed in the __`lib`__ directory on the microcontrollers internal flash memory. | Library | Link | | :------- | :---- | | ccs811 | [Gitlab](https://gitlab.com/magnuspassi/attic-monitor/-/blob/main/lib/ccs811.py) | | dht | [Gitlab](https://gitlab.com/magnuspassi/attic-monitor/-/blob/main/lib/dht.py) | | mqtt_client | [Gitlab](https://gitlab.com/magnuspassi/attic-monitor/-/blob/main/lib/mqtt_client.py) | ### Main functions To establish the connection to the __MQTT__ broker some functions from the __`mqtt_client`__ library is used. The credentials are stored in the configuration file so it needs to be parsed with the __`json`__ module. #### MQTT ```python with open('config.json', 'r') as f: data = json.load(f) f.close() for mqtt in data['mqtt']: mqtt_id = mqtt['id'] broker_ip = mqtt['broker_ip'] broker_port = int(mqtt['port']) mqtt_topic = mqtt['topic'] client = MQTTClient(mqtt_id, broker_ip, broker_port, keepalive=30) client.connect() ``` #### Sensors As mentioned earlier, the sensors used in this project are the __DHT11__ and __CCS811__. To be able to use the the sensors we need to use the libraries for each sensor. To configure the pin for the __DHT11__, the following code was used: ```python th = DTH(Pin('P23', mode=Pin.OPEN_DRAIN), 0) ``` The __CCS811__ uses two pins, the __SDA__ and __SCL__ which is the 9th and 10th pin on the Lopy4. To configure the pins for the __CCS811__, the following code was used: ```python i2c = I2C(0, I2C.MASTER, baudrate=100000) ccs = ccs811.CCS811(i2c, addr=90) ``` Now the sensors are ready to be used. To read from the sensors, some methods can be used in a __`while`__ loop as shown in the code below: ```python while(True): result = th.read() # DHT11 while not result.is_valid(): # Check if result is valid time.sleep(.5) result = th.read() ccs.data_ready() # CCS811 time.sleep(5) eco2 = ccs.eCO2 # Variable for eCO2 tvoc = ccs.tVOC # Variable for tVOC temp = result.temperature # Variable for temperature hum = result.humidity # Variable for humidity ``` With the sensors running and collecting data, all that is needed now is to transmit the result using __MQTT__. The result is in __JSON__ format as shown in the code below: ```python print('Sending values...') client.publish(mqtt_topic, '{"Attic Monitor": { "eco2":' + str(eco2) + ',"tvoc":' + str(tvoc) + ',"temp":' + str(temp) + ',"hum":' + str(hum) + ',"batt":' + str(bat_percent) + '}}') print('Values sent successfully!') ``` :::success The code in its entirety can be found [here](https://gitlab.com/magnuspassi/attic-monitor). ::: ## Transmitting the data / connectivity The device is connected via __WiFi__ so it will transmit the data locally to a virtual machine on a private server. As of now, the data is sent every 10 seconds which made the battery last about 24 hours. To increase the battery life, just increase the time interval. The __MQTT__ broker software used in this project is __[Mosquitto](https://mosquitto.org/)__ and is installed on the virtual machine with __docker__. [This article](https://blog.feabhas.com/2020/02/running-the-eclipse-mosquitto-mqtt-broker-in-a-docker-container/) is a great guide on how to install __Mosquitto__ with __docker__. To confirm that the transmission is successful, a software called __[MQTT Explorer](http://mqtt-explorer.com/)__ can be used as shown below. ![mqtt_explorer](https://i.imgur.com/RExUMGm.png) ## Presenting the data Thanks to __Telegraf__, the data is now stored in an __InfluxDB__ database. During the creation of the database, no retention policy was specified so, for now, the data will be stored indefinitely or until storage space runs out. As of now the data is saved to the database every 10 seconds. The data is presented using a web interface, __Grafana__, which queries the data from the __InfluxDB__ database. __Grafana__ is a very flexible tool and the data can be presented in a multitude of ways. In this project, the panel types used are gauges and time series, see figure below. ![grafana](https://i.imgur.com/mT2reNJ.png) ## Finalizing the design With all the wiring and code complete a good next step would be to protect the hardware with a case as shown below. ![finished_product](https://imgur.com/unsA9Nu.jpg) _Finished device!_ And with that the device is complete and functional. This journey has been incredibly fulfilling and interesting. Everything from getting the hardware to work together and setting up the __MQTT__ and __TIG__-stack has been fun and educational. ![beautiful_mess](https://i.imgur.com/NjIJu2D.jpg) _Finished device without the lid._ ![breadboard_connections](https://i.imgur.com/S2r8h8D.jpg) _Mounted breadboard with the sensors and connections._ ### Final thoughts I am overjoyed with how the device came together. The most fulfilling parts with this project was to get the hardware to work, learning how to parse __JSON__ files for convinient configuration and to learn how to calculate the battery percentage from the voltage. Still have some more to learn with the last part though and the parsing of __JSON__ files will be something I will keep using in future projects. Below is a list for future development. * __Case__ - Buying a case can be somewhat limiting. Printing a custom case with a 3D printer would be optimal. * __Adding more functionalities__ - Maybe more sensors the measure more aspects of air quality or functions for better usability such as displays and buttons * __Soldering__ - Using a breadboard is convinient, but with a complete device it would be better with sturdier soldering and circuit boards. * __Keep learning__ - IoT has a lot more to offer. I will keep learning since I'm now hooked. With that, we have reached the end of this project, but hopefully not the end of our IoT adventures. I already have some ideas for future projects. Take care!