Scott Phan
Published

Weather Station With Real Time Data Collection

Collecting real time weather data and storing it within a database, and then using the database to display the live data from anywhere.

IntermediateFull instructions provided270
Weather Station With Real Time Data Collection

Things used in this project

Hardware components

Arduino Nano esp32
×1
DHT11 Temperature & Humidity Sensor (3 pins)
DHT11 Temperature & Humidity Sensor (3 pins)
×1
Adafruit Anemometer Wind Speed Sensor w/Analog Voltage Output
×1
9V Battery Clip
9V Battery Clip
×1
Battery, 9 V
Battery, 9 V
×1
Photon 2
Particle Photon 2
×1
Resistor 10k ohm
Resistor 10k ohm
×2
DC POWER JACK 2.1MM BARREL-TYPE PCB MOUNT
TaydaElectronics DC POWER JACK 2.1MM BARREL-TYPE PCB MOUNT
×1
5V 2.5A Switching Power Supply
Digilent 5V 2.5A Switching Power Supply
×1
Button
×1
1602 LCD Display Module 16x02
×1
I2C Serial Interface for 1602 LCD
×1

Software apps and online services

Arduino IDE
Arduino IDE
Particle Build Web IDE
Particle Build Web IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free
Perf Borad
Pin Headers
Solid Core Wire
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires

Story

Read more

Schematics

Weather Station

Circuit Diagram of Weather Station

Live Weather Display

Circuit Diagram of Live Weather Display

Code

Weather Station Firmware

C/C++
This is the firmware that should be on the arduino nano esp32 for the weather station.
#include <WiFi.h>
#include <Firebase_ESP_Client.h>
#include "addons/TokenHelper.h"
#include "addons/RTDBHelper.h"
#include <DHT.h>

#define WIFI_SSID "SSID"
#define WIFI_PASSWORD "PASSWORD"
#define API_KEY "FIREBASE_KEY"
#define URL "REALTIME_DATABASE_URL"

//pin dht is plugged in
#define DHTPIN 2
//pin ds18b20 is plugged in
#define ONE_WIRE_BUS 4
//dht type
#define DHTTYPE DHT11
//sensor pin for anemometer
#define SENSORPIN A0
//min anemometer voltage
#define MINVOLTAGE 0.4
//max anemometer voltage
#define MAXVOLTAGE 2.0

FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;

bool dataChnage = false;
bool signupOK = false;

//sensor inputs
int sensorVal = 0;
float voltage = 0.0;
float windSpeed = 0.0;
float windSpeedMPH = 0.0;
float temp = 0.0;
float humid = 0.0;

//old values
float tempOld = 0.0;
float humidOld = 0.0;
float windSpeedMPHOld = 0.0;

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  dht.begin();

  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  while(WiFi.status() != WL_CONNECTED){
    delay(300);
  }

  config.api_key = API_KEY;
  config.database_url = URL;

  if(Firebase.signUp(&config, &auth, "", "")){
    signupOK = true;
  }
  else{
    signupOK = false;
  }

  config.token_status_callback = tokenStatusCallback;
  Firebase.begin(&config, &auth);
  Firebase.reconnectWiFi(true);
}

//this function only workds with farenheit and wind speeds in mph
//if the requiremnets for windchill or heat index aren't met then the function returns the temperature
float feelsLike(float temp, float humid, float windSpeed){
  float feel = temp;

  //windchill only works temperatures below 50ºF and wind speeds above 3 mph and below 110 mph
  if(temp < 10.0 && windSpeed > 1.3 && windSpeed < 49.2){
    feel = 35.74 + (0.6215 * (temp)) - (35.75 * pow(windSpeed, 0.16)) + (0.4275 * temp * pow(windSpeed, 0.16));;
  }

  //heat index only works for temperatures above 80ºF and relative humidity above 40%
  else if(humid > 40 && temp > 80){
    feel = -42.379 + (2.04901523 * temp) + (10.14333127 * humid) - (0.22475541 * temp * humid) - (0.00683783 * temp * temp) - (0.05481717 * humid * humid) + (0.00122874 * temp * temp * humid) + (0.00085282 * temp * humid * humid) - (0.00000199 * temp * temp * humid * humid);
  }

  return feel;
}

void loop() {
  humid = dht.readHumidity();
  temp = dht.readTemperature(true);
  sensorVal = analogRead(SENSORPIN);

  //wind speed calculations
  voltage = sensorVal * (3.3 / 4095.0);
  if(voltage <= MINVOLTAGE){
    windSpeed = 0.0;
  }
  else{
    windSpeed = (voltage - MINVOLTAGE) * (32.4 / (MAXVOLTAGE - MINVOLTAGE));
  }

  windSpeedMPH = windSpeed * 2.237;

  //changes in sensor values
  float tempDiff = abs(temp - tempOld);
  float humidDiff = abs(humid - humidOld);
  float windSpeedMPHDiff = abs(windSpeed - windSpeedMPHOld);

  //windchill and heatindex calculations
  float feels = feelsLike(tempOld, humidOld, windSpeedMPHOld);

  if(tempDiff >= 1 || humidDiff >= 1 || windSpeedMPHDiff >= 2){
    dataChnage = true;
    tempOld = temp;
    humidOld = humid;
    windSpeedMPHOld = windSpeedMPH;
  }
  else{
    dataChnage = false;
  }

  if(Firebase.ready() && signupOK && !(isnan(humid) || isnan(temp)) && dataChnage){
    Firebase.RTDB.setFloat(&fbdo, "Sensor/temp", temp);
    Firebase.RTDB.setFloat(&fbdo, "Sensor/wind_speed", windSpeedMPH);
    Firebase.RTDB.setFloat(&fbdo, "Sensor/humid", humid);
    Firebase.RTDB.setFloat(&fbdo, "Sensor/feels", feels);
  }

  delay(1000);
}

Data Display Firmware

C/C++
This is the firmware that should be flashed onto the photon 2 that is used to pull the live data from the database and displays it.
#include <ArduinoJson.h>
#include <LiquidCrystal_I2C_Spark.h>
#include <Wire.h>
#include "Particle.h"

SYSTEM_MODE(AUTOMATIC);

SerialLogHandler logHandler(LOG_LEVEL_INFO);

//button input
#define BTNPIN D5

//used for deserializing databse data
String jsonText = "";
JsonDocument doc;

//data values
float temp;
float humid;
float wind;
float feels;

// keeping track of LCD position
int yPos = 0;
int yPosOld = -1;

//degree symbol
byte customChar[] = {
  B01110,
  B01010,
  B01110,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};

unsigned long millesOld = 0;
const unsigned long interval = 10 * (1000); //10 second interval

unsigned long buttonTimeOld = 0;
const unsigned long buttonInterval = 200; //200ms debounce time

//LCD screen
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
    waitFor(Particle.connected, 10000);
    Particle.subscribe("hook-response/weather-data", handleResponse, MY_DEVICES);
    
    pinMode(BTNPIN, INPUT);
    
    Wire.begin(0x27);
    
    lcd.init();
    lcd.backlight(); 
    lcd.setCursor(0, 0);
    lcd.createChar(0, customChar);
    
    Particle.publish("weather-data");
}

void loop() {
    unsigned long buttonTimeNow = millis();
    int val = digitalRead(BTNPIN);

    if ((buttonTimeNow - buttonTimeOld) >= buttonInterval) {
        if(val == LOW){
            yPos += 1;
            buttonTimeOld = buttonTimeNow;
        }
    }
    if(yPos > 3){
        yPos = 0;
    }
    
    unsigned long millisNow = millis();
    if(millisNow - millesOld >= interval){
        millesOld = millisNow;
        
        Particle.publish("weather-data");
    }
    
    if(yPos != yPosOld){
        yPosOld = yPos;
        updateLCD();
    }
}

void handleResponse(const char *event, const char *data) {
    jsonText = data;
    
    retrieveValues();
    updateLCD();
}

void retrieveValues(){
    DeserializationError error = deserializeJson(doc, jsonText.c_str());
    if(error){
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Error");
        return;
    }
    
    temp = doc["temp"];
    humid = doc["humid"];
    wind = doc["wind_speed"];
    feels = doc["feels"];
}

//updates the LCD to most recent information and position
void updateLCD(){
    if(yPosOld == 0){
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Temperature:");
        lcd.setCursor(0, 1);
        lcd.print(String(temp, 1));
        lcd.write(0);
        lcd.print("F"); 
    }
    
    if(yPosOld == 1){
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Humidity:");
        lcd.setCursor(0, 1);
        lcd.print(String(humid, 1) + "%");
    }
    
    if(yPosOld == 2){
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Wind Speed:");
        lcd.setCursor(0, 1);
        lcd.print(String(wind, 2) + " mph");
    }

    if(yPosOld == 3){
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Feels Like:");
        lcd.setCursor(0, 1);
        lcd.print(String(feels, 1));
        lcd.write(0);
        lcd.print("F"); 
    }
}

Credits

Scott Phan
3 projects • 0 followers

Comments