5. IOT Cloud
Posted April 11, 2024
As for the platform I want to use, I have previously tested two platform in the Interface and Application Programming week and I have decided to use thinger.io because it have more options in terms of data monitoring and data analysis after the data reaches the platform, But unfortunately this platform is not cheap if I want to expand the sensor data im collecting, So I decided to go with Arduino cloud and buy the maker plan So I can push all my data to the cloud and have 90 days of data retention. (Alhamdollelah I have a gift code which reduced 20 % for me)
However Arduino cloud is so easy to use and very convenient for naive as the cloud will provide every thing related to the code and how to push your data to the cloud and then how to create the dashboard from scratch.
Let’s GO Ahead and Code
-
I will start very fast and code my device using the sketch the Arduino cloud will generate and then adds up my components libraries and my functions previously created in the sensor testing.
-
First of all I will create a device and set it up.
For more Information Please refer to this LINK on how to set up a device and also set a full working device with the IOT platform.
- After adding the device I will add a new thing as stated in the platform.
- Now in this section I will add all the variables I want then I will add my code.
-
Here I have 11 variables added (For the free version its only 5 variables).
-
Then I will move to sketch and start adding my code if I want to choose the online compiler or I can just copy and paste on a local sketch and save it.
We have to remember to copy the header file also and name exactly the same as it in the code (You can change but remember they must match).
-
Now I will only connect the codes I have previously built for each sensor.
-
I will only make sure to push the data I want to the cloud.
For more Information About how to set the code for the cloud and how to connect with it please refer to this LINK
- Now I need to make sure that the variables I’m gonna use are the same in the header file so I can push them to the cloud.
Sometimes I create local variables within the function so its important to push this data to the global variable other wise it won’t make any difference (Reminding my self).
Code I have Used
#include "thingProperties.h"
#include <Adafruit_SCD30.h>//CO2 Sensor Library
#include "Adafruit_AGS02MA.h"//TVOC Library
#include "Adafruit_PM25AQI.h"//PM Library
#include <HardwareSerial.h> // The hardware serial library to use the other serial port within the Xiao esp32c3
#include <Adafruit_NeoPixel.h> // Neopixel Library
HardwareSerial pmSerial(0); // Setting the hardware serial for the PArticulate matter sensor.
Adafruit_PM25AQI aqi = Adafruit_PM25AQI(); // PM constructor
Adafruit_SCD30 scd30; // CO2 Sensor Constructor
Adafruit_AGS02MA ags; // TVOC sensor Constructor
Adafruit_NeoPixel zaid = Adafruit_NeoPixel(16, 3 , NEO_GRB + NEO_KHZ800); // NEOPIXEL Constructor
int rColor ; // Variable to store the RGB color
void setup() {
// Initialize serial and wait for port to open:
Serial.begin(115200);
//while (!Serial) delay(10);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
if (!scd30.begin()) {
Serial.println("Failed to find SCD30 chip");
while (1) { delay(10); }
} // This function is not necessary to be used at all in the final version (I have used it for the debug only)
Serial.println("SCD30 Found!");
if (! ags.begin(&Wire, 0x1A)) {
// if (! ags.begin(&Wire1, 0x1A)) { // or use Wire1 instead!
Serial.println("Couldn't find AGS20MA sensor, check your wiring and pullup resistors!");
while (1) yield();
}// This function is also not necessary in the final code just used for debugging.
Serial.print("Firmware version: 0x");
Serial.println(ags.getFirmwareVersion(), HEX); // The firmware version of the TVOC sensor
ags.printSensorDetails();
Wire.setClock(16000); // I2C Clock speed to 16K
pmSerial.begin(9600,SERIAL_8N1, -1, -1);// hardware serial default for tx 6 and rx 7 in xiaoesp32c3
if (! aqi.begin_UART(&pmSerial)) {
Serial.println("Could not find PM 2.5 sensor!");
while (1) delay(10);
}else {Serial.println("PM25 found!");} // This function is not necessary to be used in the final stage its only used in depugging.
zaid.begin(); // Initiallize the RGB Class (Zaid)
zaid.setBrightness(100); // setting the brightness of the RGB to full
zaid.show(); // Initialize all pixels to 'off'
// Defined in thingProperties.h
initProperties();
// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
}
void loop() {
ArduinoCloud.update();
// Your code here
PM25_AQI_Data data;// Particulate matter sensor class (Data)
tVOC = ags.getTVOC();// pushing the TVOC sensor reading to the global variable to be pushed to the cloud
if ( aqi.read(&data)) {// this function will check if the class data of the PM sensor is ready
pMStatus = HIGH; // pushing the status of the PM sensor to the cloud (HIGH)
pM2_5 = data.pm25_standard;// Pushing the data of the PM2.5 to the global variable
pM10 = data.pm100_standard ;// Pushing the data of the PM10 to the global variable
pM1_0 = data.pm10_standard; // Pushing the data of the PM1.0 to the global variable
}else{pMStatus = LOW;// If readings are not ready the status is OFF}
scd30.setMeasurementInterval(10);// setting the reading interval of the SCD30 (CO2 Sensor) to 10 seconds {This sensor can takes reading from 2 Seconds to 180 seconds}
if (scd30.dataReady()){if (!scd30.read()){ Serial.println("Error reading sensor data"); return; }// This function is not necessary just for debugging or we can elevate its use for status but in this case we need to create another variable for this.
temperature = scd30.temperature; // Pushing the temperature data to the global variable
humidity = scd30.relative_humidity;// Pushing the Humidity data to the global variable
cO2 = scd30.CO2;// Pushing the CO2 data to the global variable
// the following are only used for debugging you can exclude them.
Serial.print("Temperature: ");
Serial.println(temperature);
Serial.print("Humidity: ");
Serial.println(humidity);
Serial.print("CO2: ");
Serial.println(cO2);
Serial.print("TVOC: ");
Serial.println(tVOC);
Serial.print(F("PM 2.5: ")); Serial.println(data.pm25_standard);
}
onRGBChange(); // calling the RGB function
}
// This function is for the RGB ring to show only one color on the ring
void test(uint32_t c){
for (int i =0 ;i<zaid.numPixels();i++){
zaid.setPixelColor(i,c); // Setting the pixel color by passing the pixel number and the color of each pixel
zaid.show(); // Turn the pixel on
delay(10); // delay for the function to take effect.
}
}
void onRGBChange() {
// Add your code here to act upon Brightness change
bool RGBstate = rGB.getSwitch(); // Getting the state of the RGB from the cloud
if(RGBstate == 1){// If the state is 1 thats mean the RGB is running and we need to take the RGB values from the cloud so the ring can hue with the same color.
uint8_t r, g, b;//local variable to stor the data coming from the cloud
rGB.getValue().getRGB(r,g,b); // Getting the Value from the cloud
rColor = zaid.Color(r,g,b); // Passing the Value to the color function I have for my RGB
if (rainbow == 1){// Taking the status from the cloud to check for the need of animation or not if satus 1 animation are going to be produced.
if (animation_type == 1){ // ANimation case types.
rainbowtest(5);// Moving rainbow function
zaid.show();// To initialize the RGB to show the last function
}else if (animation_type == 2){
zaid.rainbow();// Calling the static rainbow function
zaid.show();
}else if (animation_type == 3){
theaterChaseRainbow(10);// calling the chasing function with 10 milli second delay
}else if (animation_type == 4){
theaterChase(rColor,20);// Calling the cahsing theater function by pushing the color needed and the delay for the chase.
}
}else{test(rColor);// if the state of the animation is off just show the color normaly}
//Serial.print("red");Serial.println(r);
zaid.setBrightness(rGB.getBrightness());// Changing the brigtness of my RGB by getting the Value from the Cloud and pass it to the local function.
}else{// If status of the RGB is off from the cloud the ring will be powered off
zaid.clear();
zaid.show();
}
//Serial.print("IN Chabge");Serial.println(rGB.getBrightness());
}
void onRainbowChange() {
// Add your code here to act upon Rainbow change
}
void onAnimationTypeChange(){
}
// Neopixel functions
void rainbowtest(int wait) {
// Hue of first pixel runs 5 complete loops through the color wheel.
// Color wheel has a range of 65536 but it's OK if we roll over, so
// just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
// means we'll make 5*65536/256 = 1280 passes through this loop:
for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
// strip.rainbow() can take a single argument (first pixel hue) or
// optionally a few extras: number of rainbow repetitions (default 1),
// saturation and value (brightness) (both 0-255, similar to the
// ColorHSV() function, default 255), and a true/false flag for whether
// to apply gamma correction to provide 'truer' colors (default true).
zaid.rainbow(firstPixelHue);
// Above line is equivalent to:
// strip.rainbow(firstPixelHue, 1, 255, 255, true);
zaid.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
void theaterChaseRainbow(int wait) {
int firstPixelHue = 0; // First pixel starts at red (hue 0)
for(int a=0; a<30; a++) { // Repeat 30 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
zaid.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in increments of 3...
for(int c=b; c<zaid.numPixels(); c += 3) {
// hue of pixel 'c' is offset by an amount to make one full
// revolution of the color wheel (range 65536) along the length
// of the strip (strip.numPixels() steps):
int hue = firstPixelHue + c * 65536L / zaid.numPixels();
uint32_t color = zaid.gamma32(zaid.ColorHSV(hue)); // hue -> RGB
zaid.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
zaid.show(); // Update strip with new contents
delay(wait); // Pause for a moment
firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
}
}
}
void theaterChase(uint32_t color, int wait) {
for(int a=0; a<10; a++) { // Repeat 10 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
zaid.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in steps of 3...
for(int c=b; c<zaid.numPixels(); c += 3) {
zaid.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
zaid.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
}
- Now I need to set the Dashboard to push the data to it.
- Now I will start adding my first widget, which is gonna be the color for the RGB (Where I can control the RGB color and brightness in addition to Switch the RGB on and off)
- NOw this Widget is ready I will just need to press link variable and then OK
- Now the first widget is done.
- Now I will Add a switch for the animation.
- Now the two widget are ready.
- Now I will add a selector for the animation.
-
NOw I have all the RGB related done.
-
I will need only to sort them as I want and then I can jump to the next value I need to represent.
- Now I will add an advanced chart to represent the important values.
- NOw I can say the chart is ready and I can view the data I have been collecting.
-
Now I will Just Add the rest of the data I want to visualize in the same way.
-
Now after some hard work and sorting here is the Dashboard is ready.
- Now I need to move to the Hardware Part and start building my PCB so I can have a great system integration in my project.