# MegaWeather2000
###### tags: 'IOT', 'Tutorials', 'esp32' 'LnU', 'Applied IOT 2022', 'DIY', 'DHT11', 'BMP180', 'Heltec WIFI LoRa 32'

A tutorial/report on how to make a simple temperature/humidity/pressure sensor and then connecting it to the internet, thereby making it an IOT device. A project for the 2022 applied IOT course at Linnaeus university, Sweden.
Author: Jonas Hagberth (LnU id: jh225cm)
## Overview
This project is about building a small IOT weather station that measures temperature, humidity and barometric pressure for the 2022 applied IOT course at Linnaeus University. The device connects to the internet via WiFi and sends the sensor data with the MQTT protocol to Datacake to log and make a visual representation of it. Originally the project was a bit more complex and I had plans to make more involved sensor and actuator setup to control an irrigation system in a greenhouse. Due to logistics I recieved my parts extremely late and so I had to adapt the project to fit the new timeframe available. Overall time to make this will likely vary depending on the readers experience, but my guesstimation is about 2-5 hours. I am very much new to coding in any language, so in advance: please excuse my (probably) sloppy code that I cobbled together from various tutorials and google searches to make this work as intended.
## Objective
The main reason for the project is actually not measuring and monitoring weather data, even though I plan to use the device in another project for automating the irrigation system in a small greenhouse. The main reason for building this device is actually to learn the fundamentals of IOT, programming, sensors and microcontrollers so that I can later on apply that knowledge in other projects related to my masters education in Design. Making something "simple" using readily available and well documented parts and software enables better understanding the fundamentals of how the technology works, something that is relevant to all of us in an increasingly digital world. In short, the objective is to learn.
## Bill of materials (what you need)
| Item | Description | Price + Where I got it |
| -------- | -------- | -------- |
| Heltec WIFI LoRa 32 V2 | ESP32 based microcontroller with wifi and LoRa and a nice little OLED screen |369.99kr @ [AZDelivery](https://www.amazon.se/AZDelivery-NodeMCU-Heltec-OLED-sk%C3%A4rm-inklusive/dp/B08243JHMW/ref=sr_1_1?keywords=heltec+lora+32&qid=1656576869&sprefix=heltec+l%2Caps%2C155&sr=8-1)
Breadboard | Board for prototype connections |99.99kr @ [AZDelivery](https://www.amazon.se/AZDelivery-Breadboard-400-Stift-Kraftskenor-kompatibel/dp/B07VFK5CRP/ref=sr_1_7?keywords=breadboard&qid=1656577091&sprefix=bread%2Caps%2C304&sr=8-7)
| DHT11 sensor | Sensor for temperature and humidity | 70.99kr @ [AZDelivery](https://www.amazon.se/AZDelivery-temperatursensormodul-kompatibel-Arduino-Raspberry/dp/B089W8DB5P/ref=sr_1_15?keywords=dht11+temperature+humidity+sensor&qid=1656578225&sprefix=DHT11%2Caps%2C887&sr=8-15)
| Jumper cables male-male | Used for making prototype connections on breadboard | 29kr @ [electrokit](https://www.electrokit.com/produkt/labsladd-1-pin-hane-hane-150mm-10-pack/)
| Jumper cables male-female | Used for making prototype connections on breadboard | 29kr @ [electrokit](https://www.electrokit.com/produkt/labsladd-1-pin-hane-hona-150mm-10-pack/)
| BMP180 sensor | Sensor for barometric pressure and temperature using I2C protocol |59.99kr @ [AZDelivery](https://www.amazon.se/AZDelivery-Barometrisk-Lufttryck-Temperaturgivare-kompatibel/dp/B07D8S617X/ref=pd_sim_sccl_1_1/262-4022249-8995965?pd_rd_w=WH0SO&content-id=amzn1.sym.5762e4bf-8fcc-4b9c-81f6-5b42ec93743d&pf_rd_p=5762e4bf-8fcc-4b9c-81f6-5b42ec93743d&pf_rd_r=CHEXT093SF22HR4DYB3P&pd_rd_wg=wd9w0&pd_rd_r=2729fd9b-4698-44de-ab90-7b95a4fcdd26&pd_rd_i=B07D8S617X&psc=1)
Other handy things to have is a soldering iron for soldering the headers on the Heltec board and a standard data enabled microUSB cable for progamming and powering the device (I used an old phone cable). Please be careful when soldering the Heltec headers, if you are not experienced you can easily damage the OLED display cable. To ensure proper seating, a tip is to attach the board and headers to the breadboard while soldering. Ensure that there are no bad solder joints as the tiny pcb pads could lift easily if the leg is not properly secured. A multimeter is always good to have too, if you need to troubleshoot and check your voltages and connections. If you want to use the device on battery you need a [lipo battery](https://www.amazon.se/Seamuing-uppladdningsbara-3C-batterier-integrerat-Development/dp/B08V11Z88Q/ref=sr_1_9?crid=2CF3ZU0L48BIO&keywords=JST-GH+1.25mm+lipo&qid=1656666922&sprefix=jst-gh+1.25mm+lipo%2Caps%2C163&sr=8-9) with a micro JST 1.25mm connector or a usb powerbank that doesnt shut down after a set time period (a lot of them do if there is no/little current draw)
### Heltec WIFI LoRa 32 V2
https://heltec.org/project/wifi-lora-32/

In this project I have chosen the Heltec WIFI LoRa V2 because it is cheap, has many GPIO pins that are exposed, has LoRa connectivity (but not LTE) that I would like to explore later on (there are sadly no LoRa gateways nearby so I had to use Wifi), and uses a common microcontroller from Espressif called the ESP32. This microcontroller has a lot of support available, is fast enough to even run simple machine learning programs on the EDGE which is something I wish to explore later on. All in all, the device is very suitable for an IOT project. Also it has a nice OLED screen.
Please use this image as pinout reference when connecting your sensors:

Here is the library to connect and use the screen on the I2C bus: [ssd1306 OLED library](https://raw.githubusercontent.com/RuiSantosdotme/ESP-MicroPython/master/code/Others/OLED/ssd1306.py)
I used [this tutorial](https://randomnerdtutorials.com/micropython-oled-display-esp32-esp8266/) to make the screen work.
### DHT11
[Datasheet](https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf)

DHT11 is a low cost temperature and humidity sensor that is readily available. In this project I use it only to measure humidity as I found that the BMP180 sensor has better temperature accuracy.
Here is the needed sensor library and code example for this sensor which we will use later on to connect the sensor to the Heltec board:
[DHT11 sensor library](https://github.com/iot-lnu/applied-iot/tree/master/sensor-examples/DHT11%20%26%20DHT22%20-%20Humidity%20%26%20Temperature%20Sensor)
### BMP180
[Datasheet](https://eu.mouser.com/datasheet/2/783/BST-BMP180-DS000-1509579.pdf)

BMP180 is a sensor that measures temperature and pressure. The sensor uses a digital I2C connection for data transmission. The sensor comes without headers soldered so If you are unsure of your soldering skills do solder this before tackling the Heltec headers.
Here is the needed sensor library and code example for this sensor:
[BMP180 sensor library](https://github.com/iot-lnu/applied-iot/tree/master/sensor-examples/BMP085%20%26%20BMP180%20Temperature%20%26%20Pressure%20Sensor)
### Breadboard and jumper cables
This is a breadboard.
It connects components electrically with jumper cables. It is very simple to use. [Here](https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard/all) is a tutorial on how to use one.
## Computer setup
I a used windows 10 machine for connecting to and programming my Heltec device.
I chose the Atom text editor as it is simple to use and has good functionality and set it up as a micropython IDE using the pymakr plugin. The pymakr plugin enables ATOM to have a REPL console, which is what we use to communicate with our Heltec board and upload code to it. I followed this guide from LnU university to [setup my computer](https://hackmd.io/@lnu-iot/SydH7MTcw)
To make this work you have to install
1. Node js. This is a simple install package available [here.](https://nodejs.org/en/) Just follow the instructions.
2. [Atom](https://atom.io/) texteditor also a simple install package...you know what to do. There are of course other IDEs available, this one works for me.
3. [pymakr for Atom](https://github.com/pycom/pymakr-atom/) plugin. In Atom go to settings, then install, then type "pymakr" in the search and then press install, and Atom will install it for you automagically.
To make Atom be able to communicate with our Heltec board, we need to flash it with a micropython firmware. I followed this [guide](https://hackmd.io/@lnu-iot/By5ZUqvOq) from LnU.
To make your board work and be able to communicate and send code to it you need to:
1. connect Heltec board to computer with microusb cable
2. download and install the [driver](https://www.silabs.com/documents/public/software/CP210x_Windows_Drivers.zip) for the uart to usb com port
3. check windows device manager so that your computer can find the device and drivers are installed correctly. windows button, type device manager then press enter and scroll to see "silicon labs cp210x..." entity. Make note of the (COMn) number at the end. Mine says COM3.
4. Open ATOM settings, install, search for pymakr and then settings. Under "Device adresses" put in your "COM" number. Like COM4, COM2 or what it happens to be.
5. Download the [micropython firmware](https://github.com/H-Ryan/Heltec/blob/main/PyCom%20MicroPython/Heltec%20PyCom%20MicroPython.zip?raw=true) for the Heltec board here:
6. Flash the board using a web flasher for ESP32 and choose the silicon labs c210x for your device. I suggest you look at the [guide](https://hackmd.io/@lnu-iot/By5ZUqvOq) from LnU linked above so avoid bricking your device.
7. Open Atom, in lower left corner, press connect device (ctrl+alt+c) and also choose your COM number.
8. Then try code "Print ("I am a computer wizard!")" If the result is that the console prints: I am a computer wizard! on the next line you are good to go!
9. To upload your amazing code to the board so it can run stand alone from the computer, you first save the file, then press the "upload project to device" button (shortcut ctrl+alt+s). Watch the prompt in the console for status messages, you might have to reconnect and try again sometimes.
Then start a new project in ATOM by making a new folder on your computer and calling it something nice like "MegaWeather2000". Then also create a /lib folder as a subfolder to this one. This is where we will store sensor libraries and other auxillary code (you can put everything in root folder too of your device, but one can at least try to keep things tidy). Pressing ctrl+shift+a in ATOM and then select the folder and press ok. Make a new file and call it main.py. This is our main code file.
## Putting everything together
So, fortunately this is a fairly simple setup. First of all: The Heltec board itself needs power over USB or battery. Since this project is more about learning than putting electronic devices in the wild outdoors where weather and non ip classed DIY casing might be the one thing actually destroying the device, I opted for a simple usb cable connected to my computer powering the device. Also the connector for the battery is not your standard jst connector so I did not have anything appropriate laying around.
The usb cable is supplying 5v dc to the Heltec pcb, and the power regulators on the pcb also creates 3.3vdc rail from the 5v rail which is used for powering the sensors and the microcontroller itself. The breadboard is used to distribute 3.3vdc rail to the sensors and also to connect the sensors data lines to the appropriate GPIO pins (general purpose input output pins), that is the way for the microcontroller to communicate with the world. Since no battery is used, there is no need to do current consumption calculations, but if I were to put this device outside on battery, such calculations would make sense to estimate battery time. I I would likely also set the sleep values between messages sent to longer times to save on battery. Since the sensor boards I used have internal Pull-up resistors [(pullup resistors explained here)](https://learn.sparkfun.com/tutorials/pull-up-resistors/all) soldered to them there is no need to add external resistors.
Below is a sketch of the electrical connections:

## The Platform
The platform i have chosen for my project to collect and present the data collected by my device is [Datacake](https://datacake.co/). Datacake is a low code IOT solution that offers a free plan which is suitable for testing out my project, and for learning purposes it fulfills my needs quite well for now as a beginner. Being this type of low coding service it is cloud based with a nice GUI that is easy to understand. The platform has many capabilities I have not yet explored, I use MQTT and WIFI to send my sensor data to datacake MQTT broker and into their system. Then when the data is in their system there is a dashboard builder that I used to create a graphical representation of my data. If I were to further develop my project I would likely host my own stack of software on a raspberryPi, mainly to learn how to do that and also have more control over data integrity depending on the type of data being transmitted. Due to time restraints I had to stick with the cloud solution.
## The code
As I am a coding beginner, this portion might be a bit messy, but I will try to do my best to explain the different parts of the code.
### Wifi connection
To make this work, you first have to import the WLAN part of the Network library
```
from network import WLAN
```
This code below sets up the wifi connection and is the easiest way I could find to do this after trying to get LoRa to work for a whole day on both helium and TTN only to discover I live way out in nowhere not close enough to any gateways. So Wifi it is!
```
# configure the WLAN subsystem in station mode (the default is AP)
wlan = WLAN(mode=WLAN.STA)
wlan.connect('IOT', auth=(WLAN.WPA2, 'IOTRULES'))
while not wlan.isconnected():
pass
print(wlan.ifconfig())
```
### Setup of I2C bus for OLED screen and BMP180 sensor
First import I2C and Pin code from Machine library
```
from machine import I2C
from machine import Pin
```
Below sets up the I2C bus on pins P4 and P3. Note that the OLED screen and BMP180 share the same pins. I had trouble getting the I2C bus to work until I used the P type naming convention of the pins.
```
#I2c bus for OLED and BMP180 setup
i2c_scl = Pin('P4', mode=Pin.OUT, pull=Pin.PULL_UP)
i2c_sda = Pin('P3', mode=Pin.OUT, pull=Pin.PULL_UP)
i2c = I2C(0, I2C.MASTER, baudrate=100000, pins=(i2c_sda,i2c_scl))
```
Also import the libraries for the OLED and BMP180 sensor and assign them to variables
```
import ssd1306`#import OLED library
import from bmp085 import BMP180 #import bmp180 library
bmp = BMP180(i2c) #define the BMP180 library part = bmp
oled = ssd1306.SSD1306_I2C(128, 64, i2c, addr=0x3c) #setup oled screen as = oled
````
This allows us to use the OLED and BMP180 on the same I2C bus and to write things on the screen using `oled.text('Your text is too long as always', 0, 0)`
### Setup of DHT11 sensor
First import the sensor library `from dht import DHT`
Then use this code to setup the sensor
```
th = DHT(Pin('P19', mode=Pin.OPEN_DRAIN), 0)
```
### Setup of MQTT
I followed part of [this tutorial](https://hackmd.io/@lnu-iot/r1aui0B59) to setup my MQTT client on my end and the MQTT subscriber/broker on the Datacake end, and changed things around to make it work for my project. To setup the client, first we have to import the MQTT library found [here](https://raw.githubusercontent.com/pycom/pycom-libraries/master/lib/mqtt/mqtt.py) and ujson
```
from mqtt import MQTTClient
import ujson
```
Then I created a config.py file with my datacake credentials (see LnU tutorial above how to get these from datacake) and also the three topics I want to publish to (Temperature, Humidity, Pressure). These topics you recieve from from datacake enables them to subscribe to your published messages to get them into your Datacake account. Please also remember to import config.py in your code by putting it on your device then do `import config`
```
#Datacake credentials and my topics
SERIAL_NUMBER = 'serial'
MQTT_BROKER = 'mqtt.datacake.co'
TOKEN = 'secrettoken'
PORT = 1883
TOPIC = 'dtck-pub/megaweather2000/"stringnr-i-got-from-datacake-for-publishing"/TEMPERATURE'
TOPIC2 = 'dtck-pub/megaweather2000/"stringnr-i-got-from-datacake-for-publishing"/HUMIDITY'
TOPIC3 = 'dtck-pub/megaweather2000/"stringnr-i-got-from-datacake-for-publishing"/PRESSURE'
```
Then in main.py I connect to the datacake MQTT broker
```
# MQTT Setup
def sub_cb(topic, msg):
print(msg)
client = MQTTClient(config.SERIAL_NUMBER,
config.MQTT_BROKER,
user=config.TOKEN,
password=config.TOKEN,
port=config.PORT)
client.set_callback(sub_cb)
client.connect()
print('connected to MQTT broker')
# The MQTT topics that we publish data to
my_topic = config.TOPIC
my_topic2 = config.TOPIC2
my_topic3 = config.TOPIC3
```
I can now publish messages to these topics using simple code. The sensor results being the part with msg=str(....) where str is used to convert the float numbers to a string that can be sent as a message that your Datacake account is subscribed to.
```
client.publish(topic=my_topic, msg=str(bmp.temperature))
client.publish(topic=my_topic2, msg=str(result.humidity))
client.publish(topic=my_topic3, msg=str(bmp.pressure))
```
### The main loop that reads the sensors and sends messages through MQTT protocol to datacake
First we establish a loop that runs indefinately. The loop prints the results of the sensors to the console and the OLED screen, then publishes the data to datacake using MQTT and wifi. After that it sleeps for 180 seconds before it starts over again. Dont forget to also `import time` to be able to set the device to sleep
```
while True:
result = th.read()
while not result.is_valid():
time.sleep(.5)
result = th.read() #used to read DHT11 sensor
#Print results in console
print('Temp:', result.temperature)
print('RH:', result.humidity)
print('Temperature', bmp.temperature)
print('Pressure', bmp.pressure)
#Convert results to strings and assign to variables
temperature_string = str(result.temperature)
temperature180_string = str(bmp.temperature)
humidity_string = str(result.humidity)
pressure_string = str(bmp.pressure)
#Print results on OLED screen
oled.fill(0)
oled.text('MegaWeather2000', 0, 0)
oled.text(temperature180_string + "C", 0, 20)
oled.text(humidity_string + "%", 0, 35)
oled.text(pressure_string + "hPa", 0, 50)
oled.show()
time.sleep(1)
#Publish results to datacake using MQTT
#topics here corresponds with fields that datacake is subscribed to
#messages corresponds with sensor data
client.publish(topic=my_topic, msg=str(bmp.temperature))
client.publish(topic=my_topic2, msg=str(result.humidity))
client.publish(topic=my_topic3, msg=str(bmp.pressure))
print("Send data to MQTT broker, sleeping for 3 minutes...")
time.sleep(180) # Wait 3 minutes (180 seconds)
```
## Transmitting the data / connectivity
As previously mentioned the device uses WiFi for wireless communication, and the MQTT protocol for the transmission of data. Since LoRa did not work in my location I had to use Wifi and the public internet for connectivity. Using wifi is less secure due to attacks being more common with wifi and the public internet than using LoRa WAN or LTE. Therefore I have created an isolated network for my device on my router. The data is sent through three MQTT messages covering the three different topics relevant to the device every three minutes:
* Humidity
* Pressure
* Temperature
That means in total of 60 messages per hour *24=1440 datapoints/day. I used a LnU promocode to get 1500 datapoints per day. So im still fine. I would like to know if its possible to send all of the sensor data in one message and decode in datacake end (probably is), but I did not have time to figure it out. If I had used LoRa WAN I would have to conserve data to save bandwidth and battery, but im too far from a LoRa gateway and my wifi coverage is not very far. So to develop project for outside use I would have to get a LTE device or install my own LoRa gateway.
Basically to send data to datacake, you (in datacake) create MQTT topics for their system to listen to corresponding to your sensor data (called fields), then you send the data with your credentials to datacake MQTT broker with the corresponding topics. Since datacake on their end is setup to subscribe to your sent topics it also shows up in their system where you can use it, for instance in a dashboard. More detailed information in a tutorial from LnU on how to connect your Heltec to datacake through wifi and MQTT can be found [here](https://hackmd.io/@lnu-iot/r1aui0B59)
## Presenting the data

Pictured here is the dashboard I constructed with datacake dashboard editor. It provides the data visualized in two ways. The latest published values are clearly displayed on top, and below are diagrams which contextualize the data in a temporal manner, allowing to see the data history more clearly. The data is saved every time the heltec device makes a new entry (3 messages every 3 minutes), and is logged for at least a year. You can even do a CSV export of your sensor data, nice! I also added an email notification in case the device goes offline. Using datacake is simple, and even a non-coder like me can use it. Here is an example of a dashboard editor where you can setup how to visualize your data in lots of different ways.  To make my dashboard, I simply pressed "add widget", select the type of representation (I used value and chart) and then selected which field to connect to the widget.
## Finalizing the design
The final result of the project is a working prototype with the intended functionality of sending temperature, humidity and pressure data over Wifi using MQTT to Datacake, where the data is logged and given visual representation. Obviously this prototype is not built to withstand any prolonged use. To make it usable as an actual product, I would have to build a proper case for it, make a pcb or at least solder the connections on a protoboard, sort out the power situation by installing a lipo battery and a way to charge said battery. I already know how to do all of this things, but what I didn“t know before is how to code and implement an IOT solution and all the background knowledge and context this course has provided me with. Seeing as the objective of the course for me was to learn, I can with confidence say that the course has been a success. Likely there are much details in the code that can be optimized, for instance how to minimize the data sent by sending everything in one message and then decoding it on the other end. Another use case could potentially be calculating fermentation times of sourdough that I like to make pizza with. That would require some math and a model of dough behaviour at different temperatures and humidity to be implemented. Perhaps one could also solve that problem with edge machine learning, a camera and a classifier that is trained on properly fermented doughs, and then some sort of notification system...A lot of fun possibilities! Anyhow, there is the fact that had I not recieved my parts much later than intended, I would likely have embarked on a much more complex and ambitious project. But since I have the parts now, I can still do that even after the course has ended, and so my learning journey into IOT has just started.
Finally, below are some super simple sketches of how the device could look with a case and mounted in my small greenhouse.


## Have fun exploring your own projects!
Thanks for sticking around until the end/Jonas