**Written by Joel Josefsson (jj224jr)**
---
**Table of Contents**
[TOC]
---
# Project Overview
The aim of this project is to expand the knowledge of IoT using the Firebase Realtime Database to access the data anywhere in the world.
This project features temperature and humidity measurements using a DHT11 module. The values are then transmitted to the database using WiFi. An android app then subscribes to the changes in the database and visualizes the data.
## Time Estimation
The estimated time the project took to complete is presented in the table below.
| | Circuit | Database | MicroPython | Android app | Total |
| -------- | -------- | -------- | ----------- | ---------- | ----- |
| Hours | 3 | 6 | 10 | 10 | 29 |
# Objective
This project was chosen based on the interest in building something functional to use in the home which can be used with a smartphone anywhere in the world.
When you want to know the outside temperature it is common to go on your smartphone and look at some weather application which shows the temperature over a whole city. However, is that the actual temperature on my balcony? Hence, the purpose of this project is to get an accurate temperature and humidity reading on my balcony during the summer heat which can be viewed on my phone.
# Bill of Materials (BOM)
The materials used in this project is presented in the table below:
| Device | Quantity | Description | Price/Link |
|:------------------------------------------------------------------------------------------------- | -------- | ----------------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| Raspberry Pi Pico W<br /> | 1 | Used to collect sensor data and transmit to the database. It features WiFi and the RP2040 chip. It has 26 GPIO pins and operates on 1.8-5.5V DC input power. | 98 SEK <br /> [Electrokit](https://www.electrokit.com/produkt/raspberry-pi-pico-w/) |
| USB-A male - Micro-USB<br />| 1 | Used to connect the Raspberry Pi Pico W to the computer to upload code | 39 SEK <br /> [Electrokit](https://www.electrokit.com/produkt/usb-kabel-a-hane-micro-b-5p-hane-1-8m/) |
| Push Button<br /> | 1 | Used as a way to reset the board without pulling the cable. | 9,22 SEK <br /> [Elfa](https://www.elfa.se/en/tactile-switch-1no-momentary-function-57n-12x12mm-wuerth-elektronik-430476073716/p/30142287?trackQuery=cat-DNAV_PL_050115&pos=25&origPos=253&origPageSize=50&filterapplied=filter_Mounting+Type%3dThrough+Hole%26filter_Switch+Colour%3dBlack&track=true) |
| DHT11 Module<br /> | 1 | Used to measure the ambient temperature and humidity. It measures temperature using an NTC component and humidity using a resistive component. It operates at 3.3-5.5V DC with the accuracy of ±2°C for temperature and ±5%RH for the humidity. | 49 SEK <br /> [Electrokit](https://www.electrokit.com/produkt/digital-temperatur-och-fuktsensor-dht11/) |
| Breadboard <br /> | 1 | Used to put the components together | 69 SEK <br /> [Electrokit](https://www.electrokit.com/produkt/kopplingsdack-840-anslutningar/) |
| Jumper Wires <br />  | 7 | Used to connect the components on the breadboard. | 49 SEK <br /> [Electrokit](https://www.electrokit.com/produkt/labbsladd-40-pin-30cm-hane-hane/) |
| Android Phone (Optional)|1|Used to visualize the data. (An emulator can be used instead)||
# Computer setup
To program the Raspberry Pi Pico W we need an IDE. This project uses Thonny based on the simplicity of setting it up and saving the file to the microcontroller. The project is also utilizing Android Studio to make the android app.
## Thonny
Thonny is a very simple IDE for Python and is very easy to setup for Raspberry Pi Pico W. Micropython can be flashed on the microcontroller directly from Thonny.
### Installing Thonny
1. Thonny is downloaded from their [Github](https://github.com/thonny/thonny/releases/tag/v4.1.1) with instructions on which to download based on your operating system. Since This project uses windows we download thonny-4.1.1.exe 
2. Start the downloaded .exe file and press next. 
3. Accept the Licence Agreement and press next. 
4. Choose if you want to have a desktop icon and press next. 
5. Press install to start the installation. 
6. When the installation is complete click finish to close the window. 
### Setup
1. Open Thonny and plug in the Raspberry Pi Pico W using the micro-USB to USB-A cable where the micro-USB plugs into the microcontroller and USB-A to the computer.
2. Next press the Python interpreter option in Thonnys lower right corner and select Install MicroPython. 
3. A window appears with some information on how to install. The Target volume will be automatically selected to the appropriate volume as well as the MicroPython family. You only need to select the variant Raspberry Pi Pico W and then install. Then press close when the installation is done. <br /> 
4. Now you can select the Raspberry Pi Pico board in the interpreter and start coding 
### Using Thonny
In Thonny you can either save your python files on the computer or on the board. To save the file on the board simply select save and then a popup window lets you choose the Raspberry Pi Pico 
Then choose a name for you file ending in .py and press ok to save on the board. 
The file is now saved as hello_world.py on your Raspberry Pi Pico W and can be executed by pressing the play button at the top. The board is then reset and the words "Hello World" is printed in the REPL. 
If you want the code to run when the microcontroller gets plugged in without pressing the play button name it ``main.py``. You can also have a ``boot.py`` file which is the first file to run when plugged in. This is usually for connecting to the network and such.
## Android Studio
Android Studio is used to make the app for the android phone.
To install [Android Studio](https://developer.android.com/studio/install), they have very good instruction with a video on how to do the installation steps. It also have instructions for several different operating systems. Furthermore, to create a virtual device [Android studio](https://developer.android.com/studio/run/managing-avds) have great tutorial on how to create a android virtual device to debug your code on.
## Firebase
Firebase is googles own cloud database service. Hence, first you will need to have a google account and sign in to it. Next, to create a Realtime Database, [Firebase](https://firebase.google.com/docs/database/android/start) have a good tutorial on how to set up the database. They also have a tutorial on how to set up Firebase for your app in Android Studio on [Firebase](https://firebase.google.com/docs/android/setup#assistant).
# Putting everything together
## Circuit
The circuit of the components are illustrated below.

### Power and Ground
We make one 3.3V line from pin 36 on Raspberry Pi Pico W to the row closest to the blue line and one ground line from pin 38 to the row closest to the red line.
### DHT11
The DHT11 module have the pins signal, power and ground respectively from left to right. Hence, the signal pin is connected to the GPIO pin 16 on our microcontroller, ground is connected to the ground line and the power line is connected to the 3.3V power line which will be sufficient to power the DHT11. Since the module already features a pull up resistor there is no need to add an extra resistor between the signal and power line. The DHT11 also draws 2.5mA at the maximum which is significantly lower than the limit of our microcontroller, so no need for external power.
### Button
The button is connected with the left side to ground and right side to GPIO pin 17. The internal circuit of the Raspberry Pi Pico W already have a pull up resistor so no need for that. One not when connecting a button is on which pins to connect. A button is basically two circuits which connects when the button is pressed. One circuit on the two right pins and one circuit on the two left pins. Hence, when connecting the button make sure to connect the ground and signal to two different internal circuits, otherwise it will constantly be short circuited and read the same value regardless of the state of the button. When the button is not pressed no signal is carried to the GPIO pin and the pull up resistor will pull up the signal to 1. When the button is pressed the circuit is short circuited and the resulting signal to the pin is 0.
## Platform
The platform used for this project is Firebase Realtime Database which is a NoSQL cloud database synced in realtime across all connected devices. The data is stored as JSON. The free account can have 100 connections, 1 GB storage and 360 MB Downloads per day which is more than enough for this project. You can either update a variable to have sort of MQTT functionality but you can also save lots of data in order to make a dataset or to have the data to present in a graph.
# The code
The main code for the microcontroller and for the android app is presented here.
## Microcontroller
The library to connect and push data to the Firebase database is ufirebase downloaded from [Github](https://github.com/ckoever/micropython-firebase-realtime-database) and saved to the microcontroller under the lib folder.
### Secrets
The first step is to make a file where all the secrets are held such as the WiFi information as is structured as such:
```python=
SSID = "Your SSID"
WIFIPASS = "Your WiFi password"
FIREBASEURL = "URL to the Firebase Realtime Database"
```
and save it as secrets.py on the microcontroller
### Connecting to WiFi
First off we need to connect to the WiFi in our boot.py file. We import the necessary libraries
```python=
from machine import Pin
from time import sleep_ms
import network
import secrets
```
The Pin class is used to blink the on board LED to have visual feedback when connecting. The sleep_ms is used when waiting on connecting. The network is used to connect to the WiFi and secrets are our secrets file made before.
Next we define a variable led to refer to the on board LED:
```python=
led = Pin('LED', Pin.OUT)
```
Then to connect to the network:
```python=
sta_if = network.WLAN(network.STA_IF)
if not sta_if.isconnected():
sta_if.active(True)
sta_if.connect(secrets.SSID, secrets.WIFIPASS)
while not sta_if.isconnected():
led.toggle()
sleep_ms(200)
led.off()
```
First off we make a WLAN client which is then checked if already connected. If it is not we make the network interface active and connect using the SSID and password of the router. Next while the board is connected the on board led is blinking every 0.2s to indicate that it is trying to connect.
### Main program
The ufirebase is the library downloaded to access Firebase Realtime Database. It has the function to connect to the database, get data and put data from Firebase. We import it and give it the name ``firebase`` To define the URL to the firebase to set it up we use ``firebase.setURL()`` as such:
```python=
import secrets
import lib.ufirebase as firebase
firebase.setURL(secrets.FIREBASEURL)
```
We also need to define the variables refering to the DHT11 and the button. It is done with the Pin class from the machine library. The DHT11 is defined using the DHT11 class from the dht library.
```python=
from machine import Pin
from dht import DHT11
d = DHT11(Pin(16))
button = Pin(17, Pin.IN, Pin.PULL_UP)
```
To have our microcontroller take maesurements every hour and post them to the database we use a timer defined in the machine library. The timer is set to periodic with a period of one hour meaning that the timer will restart after it runs out every hour. The callback function of the timer takes the measurements using the d variable and post them in the database under the respective key using ``firebase.put()``. They are saved as strings as it is easier to work with in android studio later.
```python=
from machine import Timer
def timer_handler(t):
d.measure()
temp = d.temperature()
hum = d.humidity()
print(temp)
print(hum)
firebase.put("Temperature", str(temp), bg=0)
firebase.put("Humidity", str(hum), bg=0)
t = Timer()
t.init(mode=Timer.PERIODIC, period=3600000, callback=timer_handler)
```
*[IRQ]: Interrupt Request
Finally we use an IRQ on the button to instantly reset the board when pressed. The variable ``button`` is set to trigger on a falling edge with the function to reset the board as handler. The button is triggered on the falling edge since the pull up resistor in the board always makes the button read as ``1`` and when we press the button it reads ``0``.
```python=
from machine import reset
def reset_button_handler(pin):
print("Resetting Machine")
reset()
button.irq(trigger=Pin.IRQ_FALLING, handler=reset_button_handler)
```
## Android app
### App Design
The layout of the app is made using jetpack composables. The function ``Card(){}`` is used to present each of the measurements. Inside the function ``Text()`` is used to present the data.
```kotlin=
@Composable
fun cardLayout(title: String,
mainText: String,
CardColor: Color,
modifier: Modifier = Modifier) {
Card(modifier = modifier
.padding(16.dp),
colors = CardDefaults.cardColors(containerColor = CardColor),
elevation = CardDefaults.cardElevation(defaultElevation = 8.dp)) {
Text(text = title,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp))
Text(text = mainText,
fontSize = 50.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
modifier = Modifier.fillMaxWidth().padding(start = 16.dp))
}
}
```
To have the data in our cards update with the database ``Livedata<T>`` is used which is observed in the composable as a state.
```kotlin=
@Composable
fun appLayout(CurrentHum:LiveData<String>,
CurrentTemp:LiveData<String>,
modifier: Modifier = Modifier){
val CurrentHumidity: String? by CurrentHum.observeAsState()
val CurrentTemperature: String? by CurrentTemp.observeAsState()
}
```
### Recieving data from Firebase
In the class ``MainActivity`` three constructors are defined, two for the data from the database using ``MutableLiveData<T>`` and one refering to the database.
```kotlin=
class MainActivity : ComponentActivity() {
private val tempData = MutableLiveData<String>()
private val humidData = MutableLiveData<String>()
private val database = Firebase.database
````
In the class, a function ``readData()`` takes the database constructor and defines two references, one for the path to the temperature data and one for the path to the humidity data.
````kotlin=
private fun readData(){
val tempRef = database.getReference("Temperature")
val humRef = database.getReference("Humidity")
````
Then two eventlisteners are made, one for temperature and one for humidity. They are exactly the same except they post to the data to ``tempData`` for temperature and ``humData`` for humidity. When new data is posted to the database the eventlistener will be triggered and get the key and the value of the changed data which will be posted to the respective ``MutableLiveData<T>`` variable.
````kotlin=
val tempPostListener = object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
Log.i("firebase", "Number of messages: ${snapshot.childrenCount}")
val post = snapshot.getValue<String>()
tempData.postValue(post)
}
override fun onCancelled(error: DatabaseError) {
Log.e("firebase", "loadPost:onCancelled", error.toException())
}
}
````
# Transmitting data
The data from the DHT11 is transmitted to Firebase Realtime Database using WiFi once every hour in order to minimize the power consumption but also since the temperature outside does not often change instantly. The transport protocol used to send data to the database is TCP protocol using sockets.
# Presenting the data

The data is saved to the database once every hour and stays there until it is removed.
# Finalizing the design
The database looks like this when done:

There are only two keys, ``Humidity`` and ``Temperature`` which is all we need for this project. However, it can be further expanded in the future to include past data which can serve as a database for an machine learning model or to have displayed in the app.
