Ross
Published © GPL3+

Improved WeatherStation 20x4

Temperature, humidity and barometric pressure showing a comparison to a previous point in time and graphing the trend.

IntermediateShowcase (no instructions)9,458
Improved WeatherStation 20x4

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Robojax BMP280
×1
DSD Tech DHT22
×1
3.3V-5V 4 Channels Logic Level Converter
×1
SainSmart LCD Module For Arduino 20 X 4
×1

Story

Read more

Schematics

Weather Station v1

WeatherStation

Code

WeatherStation_20x4_v7_final.ino

Arduino
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
//#include <Wire.h>
#include <dht.h>
#include "i2c.h"
#include "i2c_BMP280.h"

dht DHT;
BMP280 bmp280;

//specify the temp sensor
#define DHTTYPE DHT22;
#define DHT22_PIN 6

#define I2C_ADDR    0x27  // Define I2C Address where the PCF8574A is
#define BACKLIGHT_PIN     3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7

LiquidCrystal_I2C  lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);

//total delay = (lcdDelayScreen1 + lcdDelayScreen2 + lcdDelayScreen3) * loopCount (in seconds)
int lcdDelayScreen1 = 44; //seconds displaying primary info
int lcdDelayScreen2 = 8; //seconds displaying secondary info
int lcdDelayScreen3 = 8; //seconds displaying secondary info

//these all have to match
int loopCount = 60;  //total loops 
float dataPointT[60];  //temperature data points
float dataPointB[60];  //pressure data points

int mainLoop;  //primary loop
int loopBaroGraph;  //secondary loop
int loopTempGraph;  //secondary loop

float currentTemp;
float currentHumid;

float baroPressure;
float currentPressure;

float tempDifference = 0;
float tempValueComparative;

int offset;
int mt;
int mp;

float pressDifference = 0;
float pressValueComparative;

//engineeringtoolbox.com/barometers-elevation-compensation-d_1812.html
float altitudeAdjustment = 1;

float minTemp;
float maxTemp;
float minPressure;
float maxPressure;

int rangeLowGraph;
int rangeHighGraph;

float percentOfCol;
float pixelHeightPercent;
int pixelHeight;

bool firstLoopComplete = false;

//define characters for temperature indicators
byte arrowUp[8] = {
  B00100,
  B01110,
  B10101,
  B00100,
  B00100,
  B00100,
  B00100,
  B00100,
};

byte arrowDown[8] = {
  B00100,
  B00100,
  B00100,
  B00100,
  B00100,
  B10101,
  B01110,
  B00100,
};

byte equalSign[8] = {
  B00100,
  B01110,
  B10101,
  B00100,
  B00100,
  B10101,
  B01110,
  B00100,
};

byte row1[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
};

byte row2[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
};

byte row3[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111,
};

byte row4[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111,
  B11111,
};

byte row5[8] = {
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
};

byte row6[8] = {
  B00000,
  B00000,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
};

byte row7[8] = {
  B00000,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
};

byte row8[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
};

void setup() {

  int setupLoop;
  bool dotPosition = true;

  Serial.begin(9600); 

  lcd.begin (20,4);

  //Switch on the backlight
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.home ();

  //delay a few seconds so the sensors are ready
  for (setupLoop = 1; setupLoop < 8; setupLoop++)
  {
    lcd.clear();
    
    if (dotPosition)
    {
      lcd.print("Initializing .");
      lcd.setCursor(0, 1);
      lcd.print("WeatherStation v.1");
      
    }
      else
    {
      lcd.print("Initializing  .");
      lcd.setCursor(0, 1);
      lcd.print("WeatherStation v.1");
    }

    dotPosition = !dotPosition;
    delay(500);
  }

  //Check if BMP 280 is ready
  if (bmp280.initialize()) 
  {
    lcd.setCursor(0, 2);
    lcd.print("Barometer ready");
  }
    else
  {
      lcd.print("Barometer error");
  }

  lcd.setCursor(0, 3);
  
  //check if DHT22 is ready
  int chk = DHT.read22(DHT22_PIN);
  switch (chk)
  {
    case DHTLIB_OK:  
    lcd.print("Temp sensor ready"); 
    break;
    
    case DHTLIB_ERROR_CHECKSUM: 
    lcd.print("Temp checksum error"); 
    break;
    
    case DHTLIB_ERROR_TIMEOUT: 
    lcd.print("Temp timeout"); 
    break;
    
    default: 
    lcd.print("Temp sensor error"); 
    break;
  }

  //leave info on screen long enough
  delay(2000);
    
  bmp280.setEnabled(0);
  bmp280.triggerMeasurement();

  bmp280.awaitMeasurement();
  bmp280.getPressure(baroPressure);
  DHT.read22(DHT22_PIN);

  //populate baseline datapoints with startup values
  int p;
  for (p = 0; p <= loopCount - 1; p++)
  {
    dataPointT[p] = DHT.temperature;
    dataPointB[p] = (baroPressure / 1000) + altitudeAdjustment;
  }

  //wait for sensors to be ready again
  delay(500);
}

void loop() {

  for (mainLoop = 0; mainLoop <= loopCount - 1; mainLoop++)
  {
    bmp280.awaitMeasurement();
    
    DHT.read22(DHT22_PIN);
    currentTemp = DHT.temperature;
    currentHumid = DHT.humidity;

    bmp280.getPressure(baroPressure);
    bmp280.triggerMeasurement();
    currentPressure = (baroPressure / 1000) + altitudeAdjustment;

    //read and store the array value before overwriting it
    tempValueComparative = dataPointT[mainLoop];
    dataPointT[mainLoop] = currentTemp;
    tempDifference = currentTemp - tempValueComparative;

    pressValueComparative = dataPointB[mainLoop];
    dataPointB[mainLoop] = currentPressure;
    pressDifference = currentPressure - pressValueComparative;

    //create lcd chars defined above
    lcd.createChar(0, arrowUp);
    lcd.createChar(1, arrowDown);
    lcd.createChar(2, equalSign);

    //LCD Output begin
    lcd.clear();
    lcd.print(currentTemp, 1);
    lcd.print((char)223);
    lcd.print("C ");
  
    //determine which trend indicator to display
    showTrendIndicator(tempDifference);

    lcd.print(" ");
  
    //then display the temperature diff
    lcd.print(tempDifference);
  
    //move to the next line and display humidity
    lcd.setCursor(0, 1);
    lcd.print(currentPressure, 1);
    lcd.print(" kPa ");

    showTrendIndicator(pressDifference);

    lcd.print(" ");
  
    lcd.print(pressDifference);

    lcd.setCursor(0, 2);
    lcd.print(currentHumid, 1);
    lcd.print(" % Rel Hum");

    lcd.setCursor(0, 3);
    lcd.print("Data age: ");

    //this ensures the 'data age' value displays the max after the first loop completes
    if (!firstLoopComplete)
    {
      if (mainLoop < (loopCount - 1))
      {
        lcd.print(mainLoop);
      }
        else
      {
        lcd.print(loopCount);
        firstLoopComplete = true;
      }
    }
      else
    {
      lcd.print(loopCount);
    }
    
    lcd.print(" m");   

    //countdown until next screen
    screenWaitRight(lcdDelayScreen1);
    
 //+++++++++++++++Screen 1 End+++++++++++++++

    
 //+++++++++++++++Screen 2 Start+++++++++++++++

    //bar chart characters
    lcd.createChar(0, row1);
    lcd.createChar(1, row2);
    lcd.createChar(2, row3);
    lcd.createChar(3, row4);
    lcd.createChar(4, row5);
    lcd.createChar(5, row6);
    lcd.createChar(6, row7);
    lcd.createChar(7, row8);

    //initialize to something these will never be
    minTemp = 50;
    maxTemp = -50;
    //find min and max temps
    for (mt = 0; mt <= loopCount - 1; mt++)
    {
      //offset value translates a negative result for 'mainLoop - mt' into the appropriate
      //value in the array sequence
      offset = getOffsetValue(mainLoop - mt);
      if (minTemp > dataPointT[offset])
      {
        minTemp = dataPointT[offset];
      }
    }

    for (mt = 0; mt <= loopCount - 1; mt++)
    {
      offset = getOffsetValue(mainLoop - mt);
      if (maxTemp < dataPointT[offset])
      {
        maxTemp = dataPointT[offset];
      }
    }

    //this sets the min/max range that the graph will show
    rangeLowGraph = minTemp - 1.5;
    rangeHighGraph = maxTemp + 1.5;
       
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print((char)223);
    lcd.print("C ");
    lcd.setCursor(0, 1);
    lcd.print("H");
    lcd.print(maxTemp, 1);
    lcd.setCursor(0, 2);
    lcd.print("L");
    lcd.print(minTemp, 1);

    for (loopTempGraph = 0; loopTempGraph <= loopCount - 1; loopTempGraph += 4)
    {
      offset = getOffsetValue(mainLoop - loopTempGraph);
      currentTemp = dataPointT[offset];
      //i add 50 so the values never go below zero
      currentTemp = (currentTemp + 50) - (rangeLowGraph + 50);
      percentOfCol = currentTemp / ((rangeHighGraph + 50) - (rangeLowGraph + 50));
      //32 = total pixels vertical
      pixelHeightPercent = 32 * percentOfCol;
      pixelHeight = pixelHeightPercent;
      showGraphColumn(pixelHeight, loopTempGraph / 4);
    }

    screenWaitLeft(lcdDelayScreen2);
    
 //+++++++++++++++Screen 2 End+++++++++++++++


 //+++++++++++++++Screen 3 Start+++++++++++++++
    
    //initialize to something these will never be
    minPressure = 250;
    maxPressure = 75;
    //find min and max pressure
    for (mp = 0; mp <= loopCount - 1; mp++)
    {
      offset = getOffsetValue(mainLoop - mp);
      if (minPressure > dataPointB[offset])
      {
        minPressure = dataPointB[offset];
      }
    }

    for (mp = 0; mp <= loopCount - 1; mp++)
    {
      offset = getOffsetValue(mainLoop - mp);
      if (maxPressure < dataPointB[offset])
      {
        maxPressure = dataPointB[offset];
      }
    }
   
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("kPa");
    lcd.setCursor(0, 1);
    //lcd.print("H");  //doesn't fit on screen :(
    lcd.print(maxPressure, 1);
    lcd.setCursor(0, 2);
    //lcd.print("L"); //doesn't fit on screen :(
    lcd.print(minPressure, 1);

    for (loopBaroGraph = 0; loopBaroGraph <= loopCount - 1; loopBaroGraph += 4)
    {   
      offset = getOffsetValue(mainLoop - loopBaroGraph);     
      currentPressure = dataPointB[offset];
      currentPressure = currentPressure - (minPressure - 1.5);
      percentOfCol = currentPressure / ((maxPressure + 1.5) - (minPressure - 1.5));
      pixelHeightPercent = 32 * percentOfCol;
      pixelHeight = pixelHeightPercent;
      showGraphColumn(pixelHeight, loopBaroGraph / 4);   
    }
    
    screenWaitLeft(lcdDelayScreen3);
  
  } //main for loop end 
}


int getOffsetValue(int z)
{
  if (z < 0)
  {
    return z + 60;
  }
    else
  {
    return z;
  }
}

void screenWaitRight(int secondsR)
{
  int a;
  for (a = secondsR; a >= 0; a--)
  {
    lcd.setCursor(18, 3);
    if(a >= 10)
    {
      lcd.print(a);
    }
      else
    {
      lcd.print(" ");
      lcd.print(a);
    }
    delay(1000);
  }
}

void screenWaitLeft(int secondsL)
{
  int b;
  for (b = secondsL; b >= 0; b--)
  {
    lcd.setCursor(0, 3);
    if(b >= 10)
    {
      lcd.print(b);
    }
      else
    {
      lcd.print(b);
      lcd.print(" ");
    }
    delay(1000);
  }
}


void showTrendIndicator(float val)
{
  if (val > 0)
  {
    lcd.write(byte(0));
  }
    else if (val < 0)
  {
    lcd.write(byte(1));
  }
    else
  {  
    lcd.write(byte(2));
  }
}
 

void showGraphColumn(int pixelHeight, int c)
{
  switch (pixelHeight)
  {
    case 1:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(0));
    break;
    
    case 2:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(1));
    break;

    case 3:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(2));
    break;

    case 4:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(3));
    break;

    case 5:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(4));
    break;

    case 6:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(5));
    break;

    case 7:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(6));
    break;

    case 8:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    break;

    case 9:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(0));
    break;

    case 10:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(1));
    break;

    case 11:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(2));
    break;

    case 12:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(3));
    break;

    case 13:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(4));
    break;

    case 14:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(5));
    break;

    case 15:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(6));
    break;

    case 16:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));
    break;

    case 17:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(0));
    break;

    case 18:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(1));
    break;

    case 19:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(2));
    break;

    case 20:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(3));
    break;

    case 21:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(4));
    break;

    case 22:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(5));
    break;

    case 23:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(6));
    break;

    case 24:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(7));
    break;

    case 25:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 0);
    lcd.write(byte(0));
    break;

    case 26:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 0);
    lcd.write(byte(1));
    break;

    case 27:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 0);
    lcd.write(byte(2));
    break;

    case 28:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 0);
    lcd.write(byte(3));
    break;

    case 29:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 0);
    lcd.write(byte(4));
    break;

    case 30:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 0);
    lcd.write(byte(5));
    break;

    case 31:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 0);
    lcd.write(byte(6));
    break;

    case 32:
    lcd.setCursor(c + 5, 3);
    lcd.write(byte(7));
    
    lcd.setCursor(c + 5, 2);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 1);
    lcd.write(byte(7));

    lcd.setCursor(c + 5, 0);
    lcd.write(byte(7));
    break;
  }
}

Credits

Ross

Ross

1 project • 10 followers

Comments