**By Erik Kroon Celander, ek223ur**
This project revolves around creating a simple yet functional Internet of Things (IoT) device using a Raspberry Pi Pico WH. The device measures temperature and humidity, providing real-time data that can be monitored remotely.
This tutorial will approximately take 4-10 hours from start to finish depending on the amount of troubleshooting one is required to perform, which could be a lot since encountering minor problems is common when learning new things.
The products used in this tutorial will set you back a total of 315 SEK or ≈ 27€.
## Objective
For my IoT project, I chose to make a device that measures temperature and humidity. The main reason was that all the parts I needed were in the start kit. But it wasn't just about convenience - I saw a chance to make something I will find useful and learn more about IoT at the same time.
Although simple in its design, this temperature and humidity monitor serves a functional purpose. Living in a northern European climate, I often find myself grappling with adjusting indoor conditions to maintain an optimal comfort level. This device will now allow me to observe these internal fluctuations more precisely, creating an opportunity to optimize my use of heating and cooling systems for a more energy-efficient living environment.
With the data generated by this device, I anticipate gaining deeper insights into my indoor microclimate. More than just numbers, this data presents a narrative about how my indoor environment reacts to external weather conditions. This knowledge will help me use my heating and cooling systems more wisely, which could lead to lower energy use and a more comfortable home.
## Material
Below is the list of components used in this project, which will cost in total **315 SEK** or **≈ 27€**. These products might be available for a lower sum at an alternative retailer, however since I purchased [this kit](https://www.electrokit.com/produkt/start-kit-applied-iot-at-linnaeus-university-2023/) from [electrokit](electrokit.com), this is where gathered the individual component cost from.
| Image | Product | Description | Price |
| ----- | ------- | ----------- | ----- |
| <img src="https://www.electrokit.com/uploads/productimage/41019/PICO-WH-HERO.jpg" width="200"> | [Raspberry Pi Pico WH](https://www.electrokit.com/en/product/raspberry-pi-pico-wh/) | Microcontroller | 109 SEK |
| <img src="https://www.electrokit.com/uploads/productimage/41015/41015728-1.jpg" width="200"> | [Digital temperature and humidity sensor DHT11](https://www.electrokit.com/en/product/digital-temperature-and-humidity-sensor-dht11/) | Temperature and humidity sensor | 49 SEK |
| <img src="https://www.electrokit.com/uploads/productimage/10160/10160840.jpg" width="200"> |[Solderless Breadboard 840 tie-points](https://www.electrokit.com/en/product/solderless-breadboard-840-tie-points-2/) | Breadboard | 69 SEK |
| <img src="https://www.electrokit.com/uploads/productimage/41003/41003290.jpg" width="200"> | [USB cable A-male – microB-male 1.8m](https://www.electrokit.com/en/product/usb-cable-a-male-microb-male-1-8m/) | USB-Cable | 39 SEK |
| <img src="https://www.electrokit.com/uploads/productimage/41012/41012684.jpg" width="200"> | [Jumper wires 40-pin 30cm male/male](https://www.electrokit.com/en/product/jumper-wires-40-pin-30cm-male-male/) | Jumper wires | 49 SEK |
## Computer setup
* **Step 1: Install VSCode and PyMakr**
* Go to the official Visual Studio Code website: https://code.visualstudio.com/
Click on the download button for your operating system (Windows, Linux, or MacOS).
Open the downloaded file and follow the instructions on the installation wizard to install VSCode.
* Launch Visual Studio Code.
On the left-hand side, click on the Extensions icon (it looks like four squares with one square detached).
In the search bar at the top, type "PyMakr" and press enter.
You'll see the PyMakr extension in the search results. Click the "Install" button next to it.
Once installed, VSCode may need to reload to activate the PyMakr extension.
* **Step 2: Install Python**
* Go to the official Python website's downloads page: https://www.python.org/downloads/
Click on the button corresponding to your operating system and preferred Python version. Open the downloaded file and follow the instructions on the installation wizard to install Python. Once complete, you can verify that it has been successfully installed by typing: `python --version`
* **Step 3: Download and install the MicroPython firmware on to the Pico WH**
* Visit the official MicroPython website's download page: https://micropython.org/download/rp2-pico-w/
Click on the latest version to download the .uf2 file.
* Connect your Raspberry Pi Pico WH and computer with the USB-cable while holding down the white 'BOOTSEL' button on top of the microcontroller. This will cause it to appear as a mass storage device.
* Drag the previously downloaded .uf2 firmware file on to the device.
* **Step 4: Upload your code to the device**
Now that your Pico WH is flashed and has the necessary firmware, you can write the code and upload it to the device by using the previously installed VSCode extension PyMakr:
* On the left hand side, where we previously found the Extensions icon, you will now find a PyMakr icon, press it and you will see the PyMakr tab.
* Add your device by pressing 'Add device' and selecting it. If successful, you will find the device in the device list of the PyMakr tab. Press the 'Connect device' icon next to the device name to connect your Pico WH with the PyMakr extension.
* After connecting to the device and you want to upload your MicroPython code to the device, press the now clickable 'Upload to device' icon button to upload it.
## Putting everything together
### Electronics
In this project, we connect a Raspberry Pi Pico WH with a DHT11 sensor, which is a cost-effective digital temperature and humidity sensor.
The DHT11 sensor has three pins: VCC (power), Data (for communication), and GND (ground).
* **Power (VCC)**: Connect the VCC pin of the DHT11 sensor to the 3.3V pin (pin 36) on the Raspberry Pi Pico WH. The Pi Pico WH provides 3.3V power output, suitable for powering the DHT11 sensor.
* **Data**: Connect the Data pin of the DHT11 to GP13 (pin 17) on the Pi Pico WH. We will use this GPIO pin in our code to read data from the sensor. To ensure reliable readings from the DHT11, a pull-up resistor (between 4.7kΩ to 10kΩ) should be connected between the Data pin and the VCC.
* **Ground (GND)**: Connect the GND pin on the DHT11 sensor to the GND pin (pin 38) on the Raspberry Pi Pico WH to complete the circuit.

Don't forget to disconnect power before making changes as well as double-checking your wiring before connecting power again!
### Platform
For this project, I've utilized the cloud-based service Adafruit IO. It's web-based, ensuring data is accessible from any device with internet, thus enhancing versatility and convenience I'm using the free tier, offering limited data points per minute and a 30-day data storage which is more then enough sufficient for this project.
I chose Adafruit IO for its simplicity, compatibility with devices and protocols used, and its beginner-friendly nature as well as the fact that i've had previous experience using it. It offers real-time data visualization, historical data viewing, the ability to create alerts based on specific data events and integrates seamlessly with the MQTT protocol used by the Raspberry Pi Pico WH.
## The code
### <span>boot.py</span>
In **<span>boot.py</span>**, the core functionality resides in the **do_connect()** function.
#### do_connect()
```
def do_connect():
sta_if = network.WLAN(network.STA_IF)
sta_if.active(False) # Disconnect from any active connection
print('connecting to network...')
sta_if.active(True)
sta_if.connect(SSID, SSID_PASSWORD)
while not sta_if.isconnected():
print("Attempting to connect....")
utime.sleep(1)
print('Connected! Network config:', sta_if.ifconfig())
print("Connecting to your wifi…")
```
This function sets up the network interface and tries to connect to the predefined WiFi network. The script actively checks if the device is connected to the network by calling **sta_if.isconnected()**, and if it is not, it tries again every second until a successful connection is established. Once connected, the network configuration details are printed to the console. The **do_connect()** function establishes the WiFi connection, which is needed for MQTT communication.
### <span>main.py</span>
In **<span>main.py</span>**, the two core functions are **get_sensor_reading()** and **main()**.
#### get_sensor_reading()
```
def get_sensor_reading():
time.sleep(2)
try:
t = sensor.temperature
time.sleep(2)
h = sensor.humidity
except Exception as e:
print("An exception occurred:", str(e))
return None
return {"Temperature": t, "Humidity": h}
```
This function attempts to gather temperature and humidity readings from the sensor. It starts by having a small delay to ensure accurate sensor readings. If the sensor provides valid data, the function returns it as a python dictionary with "Temperature" and "Humidity" as the keys.
#### main()
```
def main():
print(f"Begin connection with MQTT Broker :: {MQTT_BROKER}")
mqttClient = MQTTClient(CLIENT_ID, MQTT_BROKER, PORT, ADAFRUIT_USERNAME, ADAFRUIT_PASSWORD, keepalive=60)
mqttClient.set_callback(sub_cb)
mqttClient.connect()
mqttClient.subscribe(SUBSCRIBE_TOPIC)
print(f"Connected to MQTT Broker :: {MQTT_BROKER}, and waiting for callback function to be called!")
while True:
mqttClient.check_msg()
global last_publish
if (time.time() - last_publish) >= publish_interval:
sensor_data = get_sensor_reading()
if sensor_data is not None:
temperature = sensor_data["Temperature"]
humidity = sensor_data["Humidity"]
mqttClient.publish(PUBLISH_TEMP, str(temperature).encode())
mqttClient.publish(PUBLISH_HUMIDITY, str(humidity).encode())
last_publish = time.time()
print("Sent temperature data:", temperature)
print("Sent humidity data:", humidity)
time.sleep(1)
```
This **main()** function sets up the MQTT client and continuously checks for new messages from the MQTT broker as well as publishes the temperature and humidity readings to their respective MQTT topics whenever the time since the last publish equals or exceeds the value of the publish_interval variable, which I have defined to 10 seconds at the top of the **<span>main.py</span>** along with other variables.
```
# Sensor setup
pin = Pin(13, Pin.OUT, Pin.PULL_DOWN)
sensor = DHT11(pin)
# MQTT setup
CLIENT_ID = ubinascii.hexlify(machine.unique_id())
MQTT_BROKER = "io.adafruit.com"
PORT = 1883
ADAFRUIT_USERNAME = "username"
ADAFRUIT_PASSWORD = "password"
SUBSCRIBE_TOPIC = b"username/f/led"
PUBLISH_TEMP = b"username/f/temp"
PUBLISH_HUMIDITY = b"username/f/humidity"
last_publish = time.time() # time of the last published message
publish_interval = 10 # send message every 10 seconds
```
The full code can be viewed in my [repository](https://github.com/erikcelander/iotsummer).
## Transmitting the data / connectivity
For this project, the core functions **do_connect()** in **<span>boot.py</span>** and **main()** in **<span>main.py</span>** handle the transmission of sensor data to the internet. The Wi-Fi connection is established via the **do_connect()** function. This function initiates a station interface, activates it, and then attempts to connect to the provided SSID. It continues to try to connect until a successful connection is established.
Once the device is connected to the internet, the main function takes over. Data from the DHT11 sensor is collected and then published to the Adafruit IO platform using MQTT. The data is sent in the form of temperature and humidity readings. These are sent separately to their respective topics every ten seconds.
I selected Wi-Fi as the wireless protocol because of its ubiquity and simplicity to set up. Although Wi-Fi limits the device's range, it is a reasonable trade-off considering the project's requirements and common home infrastructure.
I chose MQTT as the transport protocol because of its lightweight nature which is ideal for small IoT devices with limited processing capabilities. Adafruit IO is the cloud service used in this project and it natively supports MQTT, which made the choice easy.
The device is currently powered by a USB cable. However, it is possible to power it by a battery to make it more portable. I should note that the current data transmission rate of ten seconds is designed for constant power and should be adjusted if one were to use a battery to power it instead.
While the device's power consumption wasn't directly measured, it is primarily influenced by the Wi-Fi connection and the frequency of data transmission. Exploring lower power consumption strategies, such as alternative wireless protocols like LoRa or implementing power saving modes, could be interesting future improvements to this project.
## Presenting the data
For the data visualization part of the project, the data from the DHT11 sensor is sent to the Adafruit IO platform, where it is displayed in a dedicated dashboard. This dashboard provides real-time visual updates of the temperature and humidity readings.
To create the dashboard, I first created twoo feeds on Adafruit IO and named them 'Temperature' and 'Humidity'.
After that I created a dashboard and building it was very intuitive with the easy-to-use interface. It involves creating new blocks for each data type we want to display, which in this case are the temperature and humidity readings.
Here's how my dashboard looks:

As I have previously mentioned, I chose Adafruit IO as the database and platform for this project due to its user-friendly interface, native support for MQTT, and in general easy integration (which I am aware of because of preivous experience with it). It's a straightforward solution for prototyping IoT projects and provides convenient data visualization tools without the need for extensive setup or maintenance.
As for automation or triggers, Adafruit IO allows you to set up reactions to specific events. For example, if the temperature goes above a certain threshold, an email alert can be sent. Although I haven't set up such automation for this project, it's good to know and a nice feature to consider for future improvements or other projects.
## Finalizing the design
Looking back at the work done on this project, I am quite pleased with the final results. The main objective was successfully achieved, as can be seen by the images i've attached in this tutorial.
I found that the most rewarding part of the project was seeing each component fall into place as expected. Being able to take an initial idea and turn it into a tangible, working system was a very satisfying experience.
## The final product:

