Devin McKillopAlejandro Angulo
Published

MEGR 3171 DIY Weather Dashboard

DIY Weather Dashboard allows you to check real-time, localized weather data from the comfort of your home.

IntermediateFull instructions provided6
MEGR 3171 DIY Weather Dashboard

Things used in this project

Hardware components

Argon
Particle Argon
×2
DGZZI Water Level Sensor
×1
SparkFun Atmospheric Sensor Breakout - BME280
SparkFun Atmospheric Sensor Breakout - BME280
×1
Sparkfun 16x2 LCD Display
×1
Breadboard (generic)
Breadboard (generic)
×2
Multi-Turn Precision Potentiometer- 10k ohms (25 Turn)
Multi-Turn Precision Potentiometer- 10k ohms (25 Turn)
×1
Jumper wires (generic)
Jumper wires (generic)
×1

Software apps and online services

Particle Build Web IDE
Particle Build Web IDE
ThingSpeak API
ThingSpeak API

Story

Read more

Schematics

Fritzing_Diagram

IOT_Circuit_Diagram

This diagram details the circuit setup for the DIY Weather Dashboard. A few important things to note are:
1. The transistor is representative of the DGZZI Water Level Sensor, as Fritzing does not have a matching circuit element option.
2. The circuits both make use of a Particle Photon, as Fritzing does not have an option for the Argon.
3. On an Argon, the D0 and D1 pins are replaced by SDA and SCL pins, but the circuit setup remains the same.

Code

Sensor Module

C/C++
This code reads data from the DGZZI and BME280 sensors, and publishes the results to both Particle Events and to ThingSpeak. Additionally, it notifies the user, via the D7 LED, when the communication between the two Argon devices is successful.
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//INCLUDE NECESSARY LIBRARIES AND INITIALIZE VARIABLES
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#include <ThingSpeak.h> //Thingspeak library

#include <Adafruit_BME280.h>// BME280 library

#include <Adafruit_Sensor.h> //BME companion library

#include <Wire.h> //Library to allow I2C communication for the BME

#include <Particle.h> //Library for Particle functions

#define SEALEVELPRESSURE_HPA (1013.25) //define standard sealvl pressure in hectoPascals

// Initialize the BME280 sensor object
Adafruit_BME280 bme;
//Initialize the TCP client for webhooks to send to Thingspeak
TCPClient client;
//channel ID and apikey for sending webooks
unsigned long channelID = 2107163; 
const char *apiKey = "0XHVPRI41G44F06K";
//initialize variables that will be called from getBMEvalues
int getBMEValues(int &temp, int &humidity, int &pressure);
//initialize the analog pin to read DGGZI
int waterSensor = A0; 
//init. LED pin to light up once successful communication occurs between argons
int ledPin = D7;

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//SETUP FUNCTION INITIALIZES BME280, ledPin, and DGZZI pin. CHECKS IF BME280 I2C CONNECTION BEGINS
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void setup() {
    //initialize pin A0 as an input
    pinMode(waterSensor, INPUT);
    //init. d7 pin as an output
    pinMode(ledPin, OUTPUT);
    // Initialize the BME280 sensor, and check if it is ready/ receiving values
    if (bme.begin())
        {
            Particle.publish("BME280 Sensor ready.");
        }
    else
        {
            Particle.publish("BME280 Sensor ERROR!");
        }
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//LOOP READS SENSOR VALUES, COMMUNICATES AND WRITES TO THINGSPEAK FIELDS, PUBLISHES TO PARTICLE EVENTS
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void loop() {
    ThingSpeak.begin(client); //begin thingspeak client
    
    int temp, pressure, humidity; //init local variables from BME
    int waterVal = analogRead(waterSensor); //assign DGZZI value to int
    String level = String(waterVal); //convert int value to string so it can be published
    //Serial.println(waterVal); this is just to debug if needed
    
    //assign local vars values from function
    getBMEValues(temp, pressure, humidity);
    //set Thingspeak fields to receive these variables
    ThingSpeak.setField(1,temp);
    ThingSpeak.setField(2,pressure);
    ThingSpeak.setField(3,humidity);
    ThingSpeak.setField(4,waterVal);
    
    //publish message to determine whether webhook integration succeeds/fails
    //this will light up the d7 ledPin when successful, and turn it off if there is a problem
    int response = ThingSpeak.writeFields(channelID, apiKey);
      if (response == 200) {
        Particle.publish("Success", "Data sent to ThingSpeak");
        digitalWrite(ledPin, HIGH);
      } else {
        Particle.publish("Error", "Could not send data to ThingSpeak");
        digitalWrite(ledPin, LOW);
      }
    delay(1000); // this delay is here to avoid issues with the publishing lines below, without the delay the "raining" publish gets overrode and not published
    //publish data to particle events log
    Particle.publish("Temp (C):", String(temp));
    Particle.publish("Pressure (hPa):", String(pressure));
    Particle.publish("Humidity (%):", String(humidity));
    Particle.publish("Raining:", level, PRIVATE);
        
    //15 second delay between readings
    delay(15000);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//FUNCTION TO READ VALUES FROM BME280
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
int getBMEValues(int &temp, int &pressure, int &humidity){
    temp = (int)bme.readTemperature();
    pressure = (int)(bme.readPressure() / 100.0F);
    humidity = (int)bme.readHumidity();

    return 1;
}

LCD Dashboard

C/C++
This code reads the data published to the Particle Events board, and displays it on a 16x2 LCD. The code initiates a greeting screen, which transitions to a continuously looping display for each of the four sensor values.
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//INCLUDE NECESSARY LIBRARIES AND INITIALIZE VARIABLES
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#include <LiquidCrystal.h> //include library for a 16x2 LCD display

//int ledPin = D7;// can be used to check if they communicate, not implemented in this version

//init. values to be displayed on LCD
int temp, hum, pres, rain;

//initialize current value, this var tracks which value should be displayed, as the values will loop
int currentValue = 0;

// Variable to keep track of the time elapsed between each display, ini at 0
unsigned long previousMillis = 0;

// Interval between each display in milliseconds, equivalent to 20sec
const unsigned long interval = 20000;
//init. digital pins for lcd display
LiquidCrystal lcd(5, 4, 3, 2, 1, 0);

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//SETUP FUNCTION INITIALIZES LCD DISPLAY AND SUBSCRIBES TO PARTICLE EVENTS
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void setup() {
    //pinMode(ledPin, OUTPUT); //not used in this version, can be used to check communication between argons
    lcd.clear(); // clear screen
    lcd.begin(16, 2);//initialize lcd
    lcd.setCursor(0, 0);//set at beginning of line 1
    lcd.print("DIY Weather Dash");
    lcd.setCursor(0,1);//set cursor to beginning of line 2
    lcd.print("Stay Tuned...");//placeholder message while argons initiate and is waiting for published data
    //subscribe to data published from other argon
    Particle.subscribe("Temp (C):", displayTempData);
    Particle.subscribe("Pressure (hPa):", displayPresData);
    Particle.subscribe("Humidity (%):", displayHumData);
    Particle.subscribe("Raining:", displayRainData);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//CONSTANT LOOP CONTROLS THE LCD DISPLAY CYCLE
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void loop() {
    // Check if it's time to display the next value
    unsigned long currentMillis = millis(); // set currentmillis to system clock time
    //current millis will keep incrementing, but when the diff between current and previous is more than 20000, activate if statement
    if (currentMillis - previousMillis >= interval) {
        //set previousMillis to currentMillis, this means that on next loop iteration difference will begin at 0 again, again begin increasing back to 20k
        previousMillis = currentMillis;
    
        // Set cursor to 2nd line on the LCD screen
        lcd.setCursor(0, 1);
    
        // Update the current value being displayed (temp,pres,hum,or rain)
        currentValue = (currentValue + 1) % 4; // the % is a remainder operator, which ensures that the value never increments past 3
  }
    //Particle.publish("all_clear",)
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//FUNCTIONS TO HANDLE THE DISPLAY BASED ON WHICH EVENT VALUE SHOULD BE DISPLAYED
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

//function that handles displaying Temperature value
void displayTempData(const char* eventName, const char*data){
    //convert the published char value to an integer
    temp = atoi(data);
    //check if this value should be displayed based on main loop fxn
    if (currentValue == 0) {
        lcd.setCursor(0, 1);//set cursor to 2nd line
        lcd.print("                ");//clear line by printing 16 blank space chars
        lcd.setCursor(0, 1);//place cursor back to beginning of 2nd line
        //display temp in Celsius
        lcd.print("Temp: ");
        lcd.print(temp);
        lcd.print(" C");
    }
}

//function that handles displaying Pressure value
void displayPresData(const char* eventName, const char*data){
    //convert the published char value to an integer
    pres = atoi(data);
    //check if this value should be displayed based on main loop fxn
    if (currentValue == 1) {
        lcd.setCursor(0, 1);//cursor @ 2nd line
        lcd.print("                ");//clear previous
        lcd.setCursor(0, 1);//cursor @ start of 2nd line
        //display Pressure in hPa
        lcd.print("Pres: ");
        lcd.print(pres);
        lcd.print(" hPa");
    }
}

//fxn that handles displaying humidity values
void displayHumData(const char* eventName, const char*data){
    //convert the published char value to an integer
    hum = atoi(data);
    //check if this value should be displayed based on main loop fxn
    if (currentValue == 2) {
        lcd.setCursor(0, 1);//cursor @ 2nd line
        lcd.print("                "); // clear line
        lcd.setCursor(0, 1);//cursor back to beginning of 2nd line
        //display humidity as percentage
        lcd.print("Humidity: ");
        lcd.print(hum);
        lcd.print("%");
    }
}

//fxn that handles displaying rain status
void displayRainData(const char* eventName, const char*data){
    //convert the published char value to an integer
    rain = atoi(data);
    //check if this value should be displayed based on main loop fxn
    if (currentValue == 3) {
        
        //check whether to display that it is or isnt raining, this is based on a threshold, as when not wet, DGZZI reads between 0 and 20 generally
        if (rain >= 100){ // if it is above 100, it is typically actively raining, and not simply leftover water droplets from an already passed storm, or from dew
            lcd.setCursor(0, 1);//cursor @ 2nd line
            lcd.print("                "); // clear line
            lcd.setCursor(0, 1);//cursor back to beginning of 2nd line
            //display rain status as yes or no
            lcd.print("It is raining!");
        }
        else{
            lcd.setCursor(0, 1);//cursor @ 2nd line
            lcd.print("                "); // clear line
            lcd.setCursor(0, 1);//cursor back to beginning of 2nd line
            //display rain status as yes or no
            lcd.print("Not raining.");
        }
    }
}
Credits

Credits

Devin McKillop

Devin McKillop

0 projects • 0 followers
Alejandro Angulo

Alejandro Angulo

0 projects • 0 followers

Comments

Add projectSign up / Login