***Kavindi Peiris - BP222FG***
## π Introduction
This project introduces a solution to convert a basic humidifier into a smart device, using a DHT11 sensor, Raspberry Pi Pico W, Home Assistant, HiveMQ MQTT broker, Node-RED, and InfluxDB. This IoT-based automation system senses real-time humidity data, analyzes it and uses the information to control the humidifier.
This project was undertaken as part of the course '23ST-1DT305 Introduction to Applied IoT' at Linnaeus University, Sweden. All information, images, and code shared in this report are under a MIT license. You're free to use the provided information as long as you include a copy of the copyright and give credit to the original author. A simple thank you to 'Kavindi Peiris' for the code is appreciated.
> ### β Time requirements
> This project can be completed in a few hours as long as you have all the prerequisite software setup.
## π― Objective
The primary motivation behind this project was to address a functionality gap in the Meross humidifier, a device that brands itself as "smart" but lacks a critical feature: the ability to adjust itself based on environmental humidity. A humidifier's main role is to maintain an optimal level of humidity, making it important for it to understand and react to changes in the environment.
The device is intended to provide a comfortable and healthy indoor environment by maintaining optimal humidity levels, reducing the need for manual adjustments. The collected data offers insights into indoor humidity patterns, which can help inform future automation tasks and contribute to energy conservation. This project could inspire the adaptation of similar techniques to other household appliances as well.
## π¦ Materials
| **Material** | **Purpose** | **Purchased From** | **Cost** | **Image** |
| ----------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Meross MSXH0 Smart Humidifier | Primary device being automated | [Amazon](https://www.amazon.se/-/en/gp/product/B07T9HL5QN/ref=ox_sc_act_title_1?smid=ANU9KP01APNAG&psc=1) | 236 SEK ||
| Raspberry Pi Pico W | Acts as the communication bridge | Electrokit | 109 SEK |  |
| DHT11 Sensor | Measures temperature and humidity | Electrokit | 49 SEK |  |
| Breadboard | For connecting the DHT11 sensor with the Pico W | Electrokit | 49 SEK | |
| Breadboard Wires | Creates electrical connections on the breadboard | Electrokit | 49 SEK |  |
| USB to Micro USB Cable | Powers the Pico W and uploads code | Electrokit | 39 SEK |  |
| Power Bank (Optional) | Portable power supply for Pico W | [NetOnNet](https://www.netonnet.se/art/hem-fritid/el-batterier/powerbank/on-prb-8000-mah/1028130.13728/) | 99 SEK | 
|
- The Electrokit items were purchased as a single package via the [Electrokit LNU Start Kit](https://www.electrokit.com/produkt/start-kit-applied-iot-at-linnaeus-university-2023/).
- Although Iβve used a power bank to power the Raspberry Pi Pico W, you could use any other mechanism.
- The costs associated with setting up a home server haven't been included here, under the assumption that one might already have one setup. Alternatively, all the prerequisite software can be hosted on cloud services as per your preference and feasibility.
## π» Computer Setup
I use Fedora as my daily driver operating system, so these instructions are for Fedora specifically. Feel free to change these according to your operating system.
### 1. Install Node.js
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. It's needed for running the servers and services used in this project. We'll be using `nvm` (Node Version Manager) to install Node.js, as it allows us to easily switch between different versions of Node.js and npm (Node Package Manager). Here are the steps:
- First, we need to install `nvm`. Open your terminal and type:
```bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
```
You might need to replace `v0.39.3` with the [latest version of `nvm`](https://github.com/nvm-sh/nvm/releases).
- Once `nvm` is installed, close your terminal and open a new one. Verify the installation by typing `nvm --version`. It should print the version number.
- Now, we can install Node.js. To install the latest version, type `nvm install node`.
- After installation, verify that Node.js is installed by typing `node --version`.
### 2. Install Visual Studio Code and PyMakr
For programming the Raspberry Pi Pico W, we're going to use Visual Studio Code with the PyMakr plugin.
- You can download Visual Studio Code from the [official website](https://code.visualstudio.com/Download). Install it as you would any other software.
- After installing Visual Studio Code, we'll need to install the PyMakr plugin. Open Visual Studio Code, click on the Extensions view icon on the Sidebar (or press `Ctrl+Shift+X`), search for `PyMakr`, and click Install.
- After installation, I had to run the following command and reboot to get it working.
```bash
sudo usermod -a -G dialout $USER
```
PyMakr allows us to easily write and upload MicroPython code to the Pico W. After installing, you'll see a PyMakr console at the bottom of Visual Studio Code, where you can interact directly with your Pico W.
### 3. Flash MicroPython onto the Raspberry Pi Pico W
Next, we need to prepare the Raspberry Pi Pico W by flashing MicroPython onto it. Here are the steps:
- First, download the [latest version](https://micropython.org/download/rp2-pico-w/) of MicroPython for the Pico.
- Connect your Pico W to your computer via the micro USB cable while holding the `BOOTSEL` button. This will make the Pico appear as a mass storage device.
- Drag and drop the MicroPython .uf2 file you downloaded earlier onto the Pico W.
- Your Pico W should now be running MicroPython! You can interact with it using the PyMakr console in Visual Studio Code.
After following these steps, you should be all set up and ready to start programming your Raspberry Pi Pico W with MicroPython.
## π Circuitry
> **Before you start**: Remember to always exercise caution when working with sensitive electronics. Disconnect the power source before making or changing connections, and double-check your wiring against the circuit diagram before applying power.
First, let's look at the circuit diagram.

In this circuit, the DHT11 sensor is connected to the Pico W as follows:
1. **VCC** pin of DHT11 is connected to the **3V3 (3.3V)** pin of the Pico W. This powers the sensor.
2. **GND** pin of DHT11 is connected to a **GND (Ground)** pin of the Pico W. This completes the circuit.
3. **Data** pin of DHT11 is connected to **GP27** of the Pico W. This is where the sensor sends the data.
### Connecting the Components
Once you have your Pico W and DHT11 sensor, you can connect them using breadboard wires according to the circuit diagram. Make sure that the connections are secure and that there are no shorts.
The DHT11 sensor operates on 3.3V, which is provided by the Pico W. The sensor communicates with the Pico W using a digital signal, so there's no need for additional resistors for this basic setup.
### Considerations
This setup is ideal for a development or home environment. If you're planning to use this in a production environment, you might want to consider using a PCB instead of a breadboard for more robust and reliable connections. You might also want to use a case or enclosure to protect the components.
In terms of power, the Pico W can be powered via the micro USB connection or through a power bank for a more portable setup. However, ensure that the power source can supply a steady 5V to avoid any potential damage to the board or unpredictable behavior.
## π Connectivity
Transmitting the data from the IoT device to the local server is a crucial aspect of this project. This is done using MQTT over WiFi.
### Connectivity
The Raspberry Pi Pico W connects to the local WiFi network, enabling it to transmit data to the local server. The Pico W has built-in WiFi capabilities, which makes it a suitable choice for a home-based IoT project.
WiFi was chosen as the wireless protocol because of its high data rate capabilities and compatibility with the home server setup. It does not require additional hardware as well.
### Data Transmission
The IoT device transmits data using MQTT (Message Queuing Telemetry Transport), a lightweight messaging protocol designed for constrained devices and low-bandwidth, high-latency, or unreliable networks.
MQTT operates on the principle of publish/subscribe. In this project, the Pico W, as a client, publishes the data to an MQTT topic on the HiveMQ broker installed on my local home server. Node-RED, also a client, subscribes to the same MQTT topic, receives the published data, and processes it accordingly.
The data package sent by the Pico W consists of humidity and temperature readings taken by the DHT11 sensor. This data is published to the MQTT topic every 30 seconds.
### Design Choices
The use of MQTT over WiFi allows for efficient and reliable data transmission, especially in a local network setup. MQTT is designed to provide reliable message delivery even in unstable network conditions, which makes it a great choice for IoT.
Using a local WiFi network for data transmission also offers benefits in terms of privacy and control. The data does not leave our local network, which reduces the risk of exposure to external threats and provides a greater level of data privacy.
WiFi allows for a good range within a typical home setting. However, WiFi is more power-hungry compared to other low-power wireless protocols like LoRa or Zigbee. Therefore in the future, power management strategies would need to be implemented to optimize battery life.
## π€ Platform
The next steps outline the selection considerations and the setup process for the platform components. All software and tools used are free and open source. All of these components were deployed on my home server, which is currently running [CasaOS](https://casaos.io/) on [Ubuntu Server](https://ubuntu.com/download/server). CasaOS is a Docker based server management system.
### Node-RED
Node-RED, an open-source programming tool designed to wire together hardware, APIs, and online services, and was a good choice for this project. The main attractions of Node-RED for this project were:
1. **Local Installation**: The ability to install Node-RED locally on a home server. This local setup allows for full control over the system and data, reducing dependence on internet connectivity and eliminating concerns about data privacy that often accompany cloud-based solutions.
2. **Integration with Home Assistant**: Node-RED offers seamless integration with Home Assistant. This integration enables direct control of the smart humidifier and simplifies the overall setup.
The one-click install package for Node-RED in the CasaOS App Store was used for setting up Node-RED. The Node-RED flows used in this project will be detailed in a later section.
### Home Assistant
Home Asssistant is the de-facto platform for home automation. It was already in use elsewhere in my home, and was a no-brainer to use. The reason for using Home Assistant instead of calling the Smart Humidifer directly was the lack of documented APIs for Meross devices, which made it complex to interface with it. This also opens up future expandability to control any device supported by Home Assistant. The one-click install package for Home Assistant in the CasaOS App Store was used for setting it up.
Unfortunately, Meross is not an officially supported integration for Home Assistant at the moment. Nevertheless, two popular unofficial integrations exist for adding Meross devices to Home Assistant; [meross-homeassistant](https://github.com/albertogeniola/meross-homeassistant) and [meross-lan](https://github.com/krahabb/meross_lan). I initially started with the more popular meross-homeassistant, but found the support for the specific MSXH0 humidifier a bit lacking as switching its operating modes through Home Assistant seems to be broken at the moment. Fortunately, the Meross-LAN integration does support this, which I ultimately used.
1. To install the Meross-LAN integration, you should first setup HACS, which is the unofficial integration store for Home Assistant. Installation instructions can be found [here](https://hacs.xyz/).
2. Add Meross-LAN repository on the HACS Integrations page.
3. Restart Home Assistant.
4. At this point, you should be able to setup the Meross LAN integration on Home Assistant by visiting Settings β Integrations β Add Integration and Searching for Meross LAN.
5. The MSXH0 humidifer was simply discovered by the Home Assistant after the installation.
### HiveMQ
HiveMQ was used as the MQTT broker for facilitating transmission of sensor data from the Raspberry Pi Pico to Node-RED. While there are other options like Mosquitto, the ability to use the HiveMQ web UI enticed me to use it. HiveMQ was setup with its Docker image using the following CasaOS configuration.

### InfluxDB
InfluxDB was used as the database for storing the sensor data. Node-RED has an excellent InfluxDB integration, and was quite easy to setup locally with Docker using the following CasaOS configuration.

1. Upon visiting the InfluxDB UI for the first time, youβre prompted to create a user account.
2. Afterwards, I copied the Operator API token.
3. I also created a bucket called `nodered` on the UI.
### Architecture
Now that we have these components setup, letβs look at how they interact with each other.

1. Raspberry Pi Pico W obtains the sensor data from the DHT11 sensor on a fixed interval (every 30 seconds).
2. Obtained humidity and temperature data is then published to a MQTT topic by the Pico W.
3. Node-RED is subscribed to the same MQTT topic and receives the temperature data.
4. Node-RED writes the data to the InfluxDB database.
5. Node-RED also visualizes the data using Node-RED dashboards.
6. On a schedule, Node-RED gets triggered again (every 5 minutes).
7. Node-RED then pulls all data for the past 5 minutes from InfluxDB.
8. A custom NodeJS function is run against the dataset, and a decision is taken on how to control the humidifier.
9. The control decision is then relayed to the humidifer via Home Assistant.
### Scaling
This current setup is ideal for a personal project or a small-scale deployment. However, to scale this idea for a larger deployment or commercial use, one could explore cloud-based solutions.
Cloud platforms such as AWS IoT could be a viable option, offering robust IoT-specific services and resources. These platforms provide advanced features like machine learning, data analytics, and enhanced security at scale.
## π Presentation

The presentation of data is implemented using a Node-RED dashboard and InfluxDB as the database system. This allows for monitoring of humidity and temperature levels, as well as tracking the activity of the humidifier in a user-friendly manner.
### Dashboard
Node-RED's dashboard feature is used to create an interface for real-time data visualization. It offers an intuitive way to present and monitor the humidity and temperature data sent from the Pico W device.
The dashboard includes current state as well as changes in humidity and temperature levels over time. It also visualizes the humidifier activity and its operating mode changes.
### Database
InfluxDB, a time-series database, is used to store the humidity and temperature data. Time-series databases are designed to handle data that changes over time, making InfluxDB a suitable choice for this project.
The data is saved in the database every time it is received, which is every 30 seconds. This frequency ensures a high-resolution picture of the changing environment conditions and humidifier activity.
The choice to use InfluxDB is influenced by its efficiency in storing time-series data, its compatibility with Node-RED, and its powerful querying capabilities.
### Automation and Triggers
The system includes automation features that help maintain optimal humidity levels. Node-RED monitors the data from the Pico W device and the stored history in the InfluxDB. Based on the conditions defined (humidity levels, temperature, time of day, rate of change), it sends commands to the Home Assistant, which controls the operation of the humidifier.
This system provides a comprehensive and automated way to control the humidity levels in your home, ensuring a comfortable environment while saving energy.
## π©πΌβπ» Code
The full code for this project can be found on GitHub.
### Raspberry Pi Pico W
The Pico W uses the `dht11` library to obtain sensor data and the `umqtt.simple` library to publish MQTT messages. This code is run every 30 seconds and publishes to the `home/livingroom/sensor` topic. The message is published as a string of JSON. This logic can be optimized quite a bit in the future, to support capabilities like deep sleep to reduce power usage.
```python
def start_sensing():
c = MQTTClient("humidity_sensor", mqtt["broker"])
c.connect()
sensor = dht.DHT11(Pin(27))
while True:
sensor.measure()
temp = sensor.temperature()
hum = sensor.humidity()
data = { "temperature": temp, "humidity": hum }
data_str = json.dumps(data);
c.publish("home/livingroom/sensor", data_str)
time.sleep(30)
start_sensing()
```
### Node-RED
There are three main flows on Node-RED.

This flow listens to messages to the `home/livingroom/sensor` topic the Pico is publishing to. After receiving a message, it parses it to a JSON object and stores it in the InfluxDB. It also parses this data and after some data wrangling sends it to the Node-RED dashboard nodes.

The second flow runs every 5 minutes, grabbing the last 5 minutes of data from the database. The query used here is written in Flux, the RefluxDB query language. The measurements are combined using the timestamp and aggregated by a 1 minute window to ease calculations.
```python
from(bucket: "nodered")
|> range(start: -5m)
|> filter(fn: (r) => r._measurement == "dht11")
|> aggregateWindow(every: 1m, fn: mean)
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
```
We then run a custom JavaScript function to parse this data and take decisions from it. Before that, we need to have optimal humidity level target we want to reach. We handle that like this. Note that these numbers are based on time of day, current temperature and how fast temperature has been changing. Right now some of the thresholds that are being adjusted are a bit arbitrary, but can be easily changed to fit your comfort levels.
```javascript
const LOWER_HUMIDITY_LIMIT = 30;
const UPPER_HUMIDITY_LIMIT = 50;
// Adjust the humidity limits based on the temperature and its rate of change
let lowerHumidityThreshold = LOWER_HUMIDITY_LIMIT;
let upperHumidityThreshold = UPPER_HUMIDITY_LIMIT;
if (latestDataPoint.temperature > 25 || temperatureChangeRate > 0) {
lowerHumidityThreshold += 5;
upperHumidityThreshold += 5;
} else if (latestDataPoint.temperature < 20 || temperatureChangeRate < 0) {
lowerHumidityThreshold -= 5;
upperHumidityThreshold -= 5;
}
// Adjust the thresholds further based on the time of day
let currentHour = new Date().getHours();
if (currentHour >= 0 && currentHour < 6) { // If it's night time, adjust the humidity thresholds
lowerHumidityThreshold -= 2;
upperHumidityThreshold -= 2;
} else if (currentHour >= 6 && currentHour < 18) { // If it's day time, adjust the humidity thresholds
lowerHumidityThreshold += 2;
upperHumidityThreshold += 2;
}
```
We then use the above limits and the current humidity levels to figure out how we want to control the humidifier. This specific Meross humidifier has two modes of operation: Continuous and Intermittent (Eco mode).
```javascript
// Make a decision about the humidifier based on the adjusted thresholds
let decision;
if (latestDataPoint.humidity < lowerHumidityThreshold - SIGNIFICANT_HUMIDITY_DIFF_MARGIN) {
decision = 'CONTINUOUS'; // Turn on the humidifier continuously if the humidity is significantly below the lower limit
} else if (latestDataPoint.humidity < lowerHumidityThreshold) {
decision = 'INTERMITTENT'; // Turn on the humidifier intermittently if the humidity is slightly below the lower limit
} else if (latestDataPoint.humidity > lowerHumidityThreshold && latestDataPoint.humidity < (lowerHumidityThreshold + SIGNIFICANT_HUMIDITY_DIFF_MARGIN) && humidityChangeRate < 0) {
decision = "INTERMITTENT" // Turn on the humidifier intermittently if the humidity is only slightly within the range, and dropping
} else if (latestDataPoint.humidity > upperHumidityThreshold) {
decision = 'OFF'; // Turn off the humidifier if the humidity is above the upper limit
} else {
decision = 'OFF'; // Turn off the humidifier if the humidity is within the range and not dropping
}
// Return the decision as the output message
return { payload: decision };
```
We then relay this decision to Home Assistant, directly triggering the specific mode on the humidifer.
The third flow reads in the humidifer state from Home Assistant periodically and uses this information to plot a timeline chart in the Node-RED dashboard.

## β¨ Finalizing the Design
The final setup looks something like this:

Overall, I believe the project was successful. It was both a challenging and rewarding experience. I was able to solve a practical problem using the knowledge and skills I've acquired in IoT and coding.
That said, there are a few things that I would consider improving:
- Firstly, I would look into exploring alternative wireless protocols that are more energy-efficient than WiFi. Although WiFi provided sufficient range and data rate for this project, it is relatively power-hungry.
- Secondly, I would consider adding a feature that allows for manual override of the system. While automation is convenient, there might be instances where manual control is necessary or preferred.
- Thirdly, adding notifications would be a valuable improvement. Integrating a notification system through Node-RED would alert users about important changes or conditions, such as low humidity levels or when the humidifier tank needs to be refilled.
This project served as a great practical application of IoT concepts and has opened up new ideas and possibilities. I'm excited to take what I've learned from this project and apply it to new challenges.
## Β© MIT License
Copyright (c) 2023 Kavindi Peiris.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.