The goal of this project is to build a weather notifier for people with disabilities while they are swimming. This is important, since sometimes there are meteorological phenomena such as hurricanes that affect the activities of the towns where they hit. Below I show you the block diagram of the device I designed.
There are some rules of thumb to help us understand how relative humidity works at a basic level, although it is important to remember that unless you are in a closed system - such as an environmental test chamber - there are other factors that can affect the results. measurement. The general rule is that as temperature increases, the air becomes drier (relative humidity decreases) and as temperature decreases, the air becomes more humid (relative humidity increases). Although there are several types of climates around the world, for this project I will indicate three possibilities: sunny day, rainy day and unstable weather day for the other types. You can modify my project according to the climate of your location.
How does it works?
- The DHT20 humidity sensor measures humidity and temperature data from the environment.
- The Blues kit is used to capture the data measured by the DHT20 sensor, and send it to the internet cloud. This kit consists of the Notecarrier-A, and the Blues Swan cards and the Global Cellular Notecard.
- The data arrives at the Blues Notehub server and we can observe many data from the link, especially the captured humidity and temperature data, in addition to time and location.
- Next, we forward the data to the ThingSpeak Server cloud. Here we can see humidity and temperature data in attractive graphs and widgets.
- On the ThingSpeak server we will create an alert to be sent to our Gmail email. To achieve this, we will first create an application with MATLAB Analysis and TimeControl.
- When this alert is activated, a message will arrive in our Gmail inbox.
- Finally, I have synchronized my Gmail account with my Smartphone and my Smartwatch to see the notifications that arrive in my main inbox.
Below I show you the electrical diagram of the project.
Notecarrier-A
- Simple. Provides breadboard compatible pins or solderable mask for direct connections.
- Compatible. Level shifters ensure compatibility with 3.3V or 5V equipment.
- Convenient. Powered by a micro-USB connector (requires 2A supply).
- GPS Ready. Models are either active GPS compatible, or feature a built-in antenna to enable GNSS connectivity.
Notecard Cellular
- Global cellular coverage over LTE CAT-1, CAT-M, or NB-IoT
- Precise location tracking through a GNSS/GPS module
- Embedded SIM with pre-provisioned network access
- 500MB of cellular connectivity and 5, 000 consumption credits included with every device
- Secure “off the internet” communications from device-to-cloud
- Low-power hardware (~8µA when idle), power-conscious firmware
- Embed with onboard M.2 Key E connector or via a companion board
- Unmatched developer experience and JSON-based API
Blues Swan
- Feather-compatible dev board, powered by an STM32L4+ @ 120 MHz with 2MB of Flash and 640KB of RAM
- Expandable to 55 pins for access to additional I/O and buses
- Plenty of Flash and RAM for edge ML workloads or complex applications
- Support for C/C++, Arduino, and CircuitPython
- CORTEX Debug connector, enabling the use of Visual Studio Code, IAR, and STM32CubeIDE with optional SWD programmer
DHT20 Sensor
- Temperature Accuracy:± 0.5 ℃
- Humidity Accuracy:± 3 % RH ( 25 ℃ )
- Measuring Range (Humidity):0 ~ 100% RH
- Measuring Range (Temperature):-40 ~ + 80 ℃
- I²C interface
- Wide voltage support 2.5-5.5V DC
Below I show you the wired and assembled device.
Blues has enough documentation to start programming the Blues Swan board. Here is a link for beginners: https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/
After I installed PlatformIO in Visual Studio, I created the WeatherMonitor project.
To continue with this project I have used as reference this Blues tutorial: https://dev.blues.io/guides-and-tutorials/collecting-sensor-data/notecarrier-a/adafruit-feather-m4-express/c-cpp-arduino-wiring/#collecting-sensor-data
Next, the configuration of the platformio.ini
file is as shown below:
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:bw_swan_r5]
platform = ststm32
board = bw_swan_r5
upload_protocol = dfu
framework = arduino
build_flags = -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
monitor_speed = 115200
lib_deps =
Wire
blues/Blues Wireless Notecard@^1.4.5
blues/Blues Wireless Notecard Pseudo Sensor@^1.1.0
robtillaart/DHT20@^0.2.3
As we can see, here is the configuration of the Notecard board and the Grove DHT20 sensor library. Now I'll show you the code from the main.cpp
file and then I'll show you how it works.
#include <Arduino.h>
#include <Notecard.h>
#include <NotecardPseudoSensor.h>
#include "DHT20.h" //DHT20
DHT20 DHT; //DHT20
using namespace blues;
#define usbSerial Serial
#define productUID "com.blues.tvantoll.your_project" // paste here your UID project
Notecard notecard;
NotecardPseudoSensor sensor(notecard);
void setup() {
// put your setup code here, to run once:
DHT.begin(); //DHT20
delay(2500);
usbSerial.begin(115200);
notecard.begin();
notecard.setDebugOutputStream(usbSerial);
J *req = notecard.newRequest("hub.set");
JAddStringToObject(req, "product", productUID);
JAddStringToObject(req, "mode", "continuous");
notecard.sendRequest(req);
}
void loop() {
// put your main code here, to run repeatedly: UPDATE
int status = DHT.read(); //DHT20
float temperature = DHT.getTemperature(); //DHT20
float humidity = DHT.getHumidity(); //DHT20
usbSerial.print("Temperature = ");
usbSerial.print(temperature);
usbSerial.println(" *C");
usbSerial.print("Humidity = ");
usbSerial.print(humidity);
usbSerial.println(" %");
switch (status)
{
case DHT20_OK:
usbSerial.print("OK");
break;
case DHT20_ERROR_CHECKSUM:
usbSerial.print("Checksum error");
break;
case DHT20_ERROR_CONNECT:
usbSerial.print("Connect error");
break;
case DHT20_MISSING_BYTES:
usbSerial.print("Missing bytes");
break;
case DHT20_ERROR_BYTES_ALL_ZERO:
usbSerial.print("All bytes read zero");
break;
case DHT20_ERROR_READ_TIMEOUT:
usbSerial.print("Read time out");
break;
case DHT20_ERROR_LASTREAD:
usbSerial.print("Error read too fast");
break;
default:
usbSerial.print("Unknown error");
break;
}
usbSerial.print("\n");
J *req = notecard.newRequest("note.add");
if (req != NULL)
{
JAddStringToObject(req, "file", "sensors.qo");
JAddBoolToObject(req, "sync", true);
J *body = JAddObjectToObject(req, "body");
if (body)
{
JAddNumberToObject(body, "temp", temperature);
JAddNumberToObject(body, "humidity", humidity);
}
notecard.sendRequest(req);
}
delay(15000);
}
Note: Please, copy and paste the "productUID" variable that you are going to get from the Blues Notehub project explained in the next section.
Blues NotehubNotehub is a cloud-based service designed to connect to Notecard devices and synchronize Notefiles. You can open a free account here: https://blues.io/products/notehub/
- Securely route Notecard-provided data to any cloud application
- Optimize data payloads on-the-fly with JSONata
- Organize and manage fleets of Notecard devices
- OTA host MCU and Notecard firmware updates
- Automatic certificate management and device provisioning
- No monthly subscriptions or hidden fees
Please, to route data to ThingSpeak cloud, follow the steps of next documentation: https://dev.blues.io/guides-and-tutorials/routing-data-to-cloud/thingspeak/
Here I have created the "SensorData" project. It's important that you copy the UID and save it in a Notepad or another, since it will be necessary to write it in the productUID variable of the "main.cpp" code of the previous section.
Now, I have created the ThingSpeak route to redirect my data to that IoT server.
- Please, in configuration tab don't forget to name the path (ThingSpeak), and the URL (https://api.thingspeak.com/update.json) as shown below.
- In Filters tab activate "Selected Notefiles" and "sensors.qo"
- In Data tab activate "JSONata Expression" and insert this code.
{
"api_key":"GMSA2OM2T8TY5UPS",
"field1": body.temp,
"field2": body.humidity,
"field3": tower_location & ', ' & tower_country,
"field4": when
}
This code helps us send only the next data to the IoT server: temperature, humidity, time and location. Be sure to change the api_key placeholder to match the value from your ThingSpeak channel (Write API Key).
ThingSpeakThingSpeak™ is an IoT analytics platform service that allows you to aggregate, visualize and analyze live data streams in the cloud. ThingSpeak provides instant. Please open a free account here: https://thingspeak.com/
.Here I have created the "Notecard Blues DHT20" channel with the next configuration:
Take note of the "Write Api Key", which will be used in the section prior to this.
Below I show you the graphs of the first tests to verify the proper functioning of the project up to this point.
Remember that my goal is to send an email notification, and ThingSpeak has added an alerts API to let you send emails from your ThingSpeak account. Here I show you the documentation addressing the topic: https://la.mathworks.com/help/thingspeak/analyze-channel-data-to-send-email.html
First open the MATLAB Analysis App..
I have created the "Notecard Blues Weather Notification" App.
To get the alert api key, you can go to Account > My Profile
All the information about alert API key is here: https://la.mathworks.com/help/thingspeak/alerts-api.html
Please insert the next MATLAB code and save the App:
% Enter your MATLAB Code below
channelID = 2295928;
%alert_body = 'Successful email with ThingSpeak';
alert_subject = 'What is the weather like today?';
alert_api_key = 'TAKasSlj8EwIBptu8PQ'; % insert your Alert API Key here
alert_url = "https://api.thingspeak.com/alerts/send";
% Read the recent data.
temperatureData = thingSpeakRead(channelID,'NumDays',1,'Fields',1);
humidityData = thingSpeakRead(channelID,'NumDays',1,'Fields',2);
% Check to make sure the data was read correctly from the channel.
if (temperatureData > 27) & (humidityData < 70);
alertBody = "It's gonna be a sunny day!";
elseif (temperatureData < 27 & (humidityData > 70));
alertBody = "It's gonna be a rainy day!";
else
alertBody = "It's gonna be a unstable weather day!";
end
jsonmessage = sprintf(['{"subject": "%s", "body": "%s"}'], alert_subject, alertBody);
options = weboptions("HeaderFields", {'Thingspeak-Alerts-API-Key', alert_api_key; 'Content-Type','application/json'});
result = webwrite(alert_url, jsonmessage, options);
As you can see, I have programmed three possible events:
- If the temperature is greater than 27 and the humidity less than 70, then print "It's gonna be a sunny day!"
- If the temperature is less than 27 and the humidity is greater than 70, then print "It's gonna be a rainy day!"
- Any other combination prints "It's gonna be an unstable weather day!"
Now, it's necessary to create a "TimeControl" application to run this code.
I have created the "Notecard Blues Weather Time Control" app.
I have inserted the next configuration. Please, in Action select "MATLAB Analysis", and in Code to execute select "Notecard Blues Weather Notification".
Now we are ready to test the entire project.
fitbit inspire 2In this project I have used the fitbit inspire 2 smartwatch, but you can use any other smartwatch that is waterproof and can synchronize with your Smartphone and your Gmail account to receive notifications.
You can get all the documentation about this Google smartwatch at this link: https://device101.fitbit.com/guides/proxima-101.html
Common settings and modes: Auto exercise recognition, Sleep tracking & Sleep Score, Silent alarms, Countdown timer & stopwatch, Menstrual health, Reminders to Move, Goal-based exercise modes, and Real-time pace & distance.
In the next video you can learn how to see messages from smartphone on FITBIT Inspire 2.
TestFirst test
Below I show you a video of the first test carried out with the Blues Kit.
Screenshots
Below I share some test images of the project:
Test With the Smartwatch Underwater
In this last test I show you that the system continues to work well with the smartwatch underwater. I clarify that the fitbit inspire 2 is waterproof and has a range of 30 feet.
TroubleshootingBelow I show you the problems I faced and their solutions:
- I recommend that the name of your project in PlatformIO be without spaces and placed in the root of your hard drive. Otherwise, when you want to compile it, Visual Studio will give you errors such as that it cannot find files or libraries.
- When you use the ThingSpeak platform, the MATLAB Analysis App only allows you two tests every 30 minutes. Otherwise it will throw you programming errors.
- If you use the Fitbit inspire 2 smartwatch, remember that its maximum range is 30 feet, and before using it you can test notifications with your smartphone.
- Any other type of failure, I recommend resetting or restarting the entire system and the platforms used.
- So far I have fulfilled the main goal of building a weather notifier for people with motor disabilities, since the Fitbit smartwatch is waterproof and user can hold it on different parts of the body.
- When the user receives a notification they will feel its vibration.
- In the last test I did a experiment with the smartwatch underwater to verify operation of the system.
- We have demonstrated its functionality, so the disabled person can be sure of their system notifications. I clarify that more sensors or notifications can be added to this system according to the user's needs.
In this second part of my project I show you an improvement, since I added the CCS811 air quality sensor. Considering the experience of the first version, I will show you all the steps in a single chapter. Below I show you the schematic diagram of my project.
As you can see, I have added the CCS811 sensor using an i2C qwiic cable over the Blues Swan board connector. This sensor has the next features:
- Total Volatile Organic Compound (TVOC) sensing from 0 to 32, 768 parts per billion
- CO2 sensing from 400 parts per million to 29, 206 ppm
- Integrated MCU
- Onboard Processing
- Standard I2C Digital Interface
- Optimized Low-Power Modes
CO2 concentration levels?
- Outdoors, CO2 levels are usually between 300 and 400 ppm, and can reach values of up to 550 ppm in urban areas.
- In non-industrial indoor environments such as offices, schools and services in general, values of 2, 000 and up to 3, 000 ppm are found.
- For professionals, the daily 8-hour exposure limit is 5, 000 ppm.
- In specific exposures of a maximum duration of 15 min. These have a limit value of 15, 000 ppm.
- If these levels are exceeded, it may be due to uncontrolled combustion, in which case the health risk may not be due to carbon dioxide but to the presence of other by-products of combustion, mainly carbon monoxide (CO), whose limit exposure is much lower (25 ppm).
- In the domestic sphere, the ideal values of carbon dioxide in a home are between 300 - 500 ppm, when values of 1000 -1200 ppm are exceeded, measures must be taken and all rooms ventilated.
Acceptable levels of VOCs in the air for human health
- Volatile organic compounds or VOCs are organic chemicals that turn into a gas at room temperature and are the main source of ground-level air pollution.
- Low concentration levels of VOCs are considered to be less than 0.3 mg/m3. Acceptable TVOC levels range from 0.3 to 0.5 mg/m3 concentration. From 0.5 mg/m3 TVOC concentration levels onwards, the concern is considered considerable or high.
- TVOC can be measured in micrograms per cubic meter (µg/m3) of air, milligrams per cubic meter (mg/m3), parts per million (ppm), or parts per billion (ppb).
PlatformIO Project
In PlatformIO I have created the project "WeatherMonitorVer2". You can download the project at the Github link that I have added at the end of this tutorial. Below I show you the platformio.ini file:
[env:bw_swan_r5]
platform = ststm32
board = bw_swan_r5
upload_protocol = dfu
framework = arduino
build_flags = -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
monitor_speed = 115200
lib_deps =
Wire
blues/Blues Wireless Notecard@^1.4.5
blues/Blues Wireless Notecard Pseudo Sensor@^1.1.0
sparkfun/SparkFun CCS811 Arduino Library@^2.0.3
robtillaart/DHT20@^0.2.3
Now I show you the main.cpp file:
// AUTHOR: GUILLERMO PEREZ GUILLEN
#include <Arduino.h>
#include <Notecard.h>
#include <NotecardPseudoSensor.h>
#include <Wire.h>
#include "SparkFunCCS811.h" //CCS811
#include "DHT20.h" //DHT20
DHT20 DHT; //DHT20
using namespace blues;
#define CCS811_ADDR 0x5B //Default I2C Address
CCS811 mySensor(CCS811_ADDR);
#define productUID "com.yahoo.guillengap:weather_monitor_version2"
Notecard notecard;
NotecardPseudoSensor sensor(notecard);
void setup()
{
DHT.begin(); //DHT20
delay(2500); //DHT20
Serial.begin(115200);
Serial.println("CCS811 Basic Example");
Wire.begin(); //Compilation will fail here if your hardware doesn't support additional Wire ports
//This begins the CCS811 sensor and prints error status of .beginWithStatus()
CCS811Core::CCS811_Status_e returnCode = mySensor.beginWithStatus(Wire); //Pass Wire1 into the library
Serial.print("CCS811 begin exited with: ");
Serial.println(mySensor.statusString(returnCode));
notecard.begin();
notecard.setDebugOutputStream(Serial);
J *req = notecard.newRequest("hub.set");
JAddStringToObject(req, "product", productUID);
JAddStringToObject(req, "mode", "continuous");
notecard.sendRequest(req);
}
void loop()
{
//Check to see if data is ready with .dataAvailable()
if (mySensor.dataAvailable())
{
//If so, have the sensor read and calculate the results.
//Get them later
mySensor.readAlgorithmResults(); //CCS811
float CO2 = mySensor.getCO2(); //CCS811
float tVOC = mySensor.getTVOC(); //CCS811
Serial.print("CO2 = ");
Serial.print(CO2);
Serial.println(" ppm");
Serial.print("tVOC = ");
Serial.print(tVOC);
Serial.println(" ppb");
int status = DHT.read(); //DHT20
float temperature = DHT.getTemperature(); //DHT20
float humidity = DHT.getHumidity(); //DHT20
Serial.print("Temperature = "); //DHT20
Serial.print(temperature); //DHT20
Serial.println(" *C"); //DHT20
Serial.print("Humidity = "); //DHT20
Serial.print(humidity); //DHT20
Serial.println(" %"); //DHT20
J *req = notecard.newRequest("note.add");
if (req != NULL)
{
mySensor.readAlgorithmResults(); //CCS811
float CO2 = mySensor.getCO2(); //CCS811
float tVOC = mySensor.getTVOC(); //CCS811
int status = DHT.read(); //DHT20
float temperature = DHT.getTemperature(); //DHT20
float humidity = DHT.getHumidity(); //DHT20
JAddStringToObject(req, "file", "sensors.qo");
JAddBoolToObject(req, "sync", true);
J *body = JAddObjectToObject(req, "body");
if (body)
{
JAddNumberToObject(body, "temp", temperature);
JAddNumberToObject(body, "humidity", humidity);
JAddNumberToObject(body, "CO2", CO2);
JAddNumberToObject(body, "tVOC", tVOC);
}
notecard.sendRequest(req);
}
}
delay(5000); //Don't spam the I2C bus
}
Blues Notehub
Remember to replace the productUID data with the one you obtain in your Notehub project. In my case I have created the Weather_Monitor_Version2 project as shown below:
Remember that to join this project with the ThingSpeak platform we created the ThingSpeak route as shown below:
In order to simplify the amount of data sent to the project created in ThingSpeak, I have added the following JSONata expression to the created route:
{
"api_key":"FGFKMNOLZHXSFIYR",
"field1": body.temp,
"field2": body.humidity,
"field3": body.CO2,
"field4": body.tVOC
}
ThingSpeak Project
Remember that the api_key is obtained from the project created in ThingSpeak. In my case the project created is Weather_Monitor_Version_2. Observe the order and names that I have given to the variables to monitor.
MATLAB Analysis
Finally, to send messages to our email account, we have created an alert with MATLAB Analysis called Weather Notifier Version 2. Below I show you the code:
% Aurhor: Guillermo Perez Guillen
channelID = 2326612
%alert_body = 'Successful email with ThingSpeak';
alert_subject = 'What is the weather like today?';
alert_api_key = 'TAKpzSli9EwIRptu9CQ';
alert_url = "https://api.thingspeak.com/alerts/send";
% Read the recent data.
temperatureData = thingSpeakRead(channelID,'NumDays',1,'Fields',1);
humidityData = thingSpeakRead(channelID,'NumDays',1,'Fields',2);
co2Data = thingSpeakRead(channelID,'NumDays',1,'Fields',3);
tvocData = thingSpeakRead(channelID,'NumDays',1,'Fields',4);
% Check to make sure the data was read correctly from the channel.
if (temperatureData > 27) & (humidityData < 70) & (co2Data < 550) & (tvocData < 600);
alertBody = "It's gonna be a sunny day and good air quality!";
elseif (temperatureData > 27) & (humidityData < 70) & ((co2Data > 550) | (tvocData > 600));
alertBody = "It's gonna be a sunny day and bad air quality!";
elseif (temperatureData < 27) & (humidityData > 70) & (co2Data < 550) & (tvocData < 600);
alertBody = "It's gonna be a rainy day and good air quality!";
elseif (temperatureData < 27) & (humidityData > 70) & ((co2Data > 550) | (tvocData > 600));
alertBody = "It's gonna be a rainy day and bad air quality!";
elseif (co2Data < 550) & (tvocData < 600);
alertBody = "It's gonna be a cloudy day and good air quality!";
else
alertBody = "It's gonna be a cloudy day and bad air quality!";
end
jsonmessage = sprintf(['{"subject": "%s", "body": "%s"}'], alert_subject, alertBody);
options = weboptions("HeaderFields", {'Thingspeak-Alerts-API-Key', alert_api_key; 'Content-Type','application/json'});
result = webwrite(alert_url, jsonmessage, options);
To program this code, I have documented myself and found that the air quality is moderate for values greater than 550 of CO2, and values greater than 600 of tVOC. For practical purposes you can modify the code that I propose according to your location.
Test
Below I show you the test
Screenshots
Below I show you some images of the tests carried out with this project:
I'm glad you liked this!
Comments