Weather Station Project

### Start

This is the Main Project for this kit. We'll be measuring the 3 fundamental weather properties, as well as UV and Infrared light. Below you'll learn how to get data from these two sensors, how the sensors sense that data, and how you can use that data to then analyze the weather.

### Modules

Gather the following parts to complete this project.

All Parts
All Parts
BME280
Sunlight
Button
LCD Display
Cable
Wrapper 2x1
Wrapper 1x1
PartQuantity
BME280 1
Sunlight 1
Button 1
LCD Display 1
Cable 3
Wrapper 2x1 1
Wrapper 1x1 1

### Temperature

Take a cable and unwrap it. Plug one side into the BME280 socket and the other into any I2C socket.

All the parts you'll need
All the parts you'll need
Take a cable...
... and unwrap it
Plug one side into the BME280 socket
... and the other into any I2C socket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "Seeed_BME280.h"
#include <Wire.h>
#include <math.h>

BME280 bme280;

float temperature;

void setup() {
Serial.begin(9600);
if (!bme280.init()) {
Serial.println("Device error!");
}
}

void loop() {
// Get Temperature in degrees Celsius
temperature = bme280.getTemperature();
Serial.println(temperature);
delay(10);
}


#### Observe

Open up the Serial Plotter and check out the temperature. The reading we get back from the BME280 is in Celsius.

#### Modify

Let's change the reading from Celsius to Fahrenheit. In the Creator Set, this was done with a function, which is added in the code below. The function takes a number as an input and applies the Celsius to Fahrenheit formula which is $degreesFahrenheit=degreesCelsius∗1.8+32degreesFahrenheit = degreesCelsius * 1.8 + 32$ . We could have written the conversion in one big line within the void loop() section, but this way is easier to read and modify.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "Seeed_BME280.h"
#include <Wire.h>
#include <math.h>

BME280 bme280;

float temperature;

void setup() {
Serial.begin(9600);
if (!bme280.init()) {
Serial.println("Device error!");
}
}

void loop() {
// Get Temperature in degrees Celsius
temperature = bme280.getTemperature();
// Convert to Fahrenheit
temperature = CtoF(temperature);
Serial.println(temperature);
delay(10);
}

// Function converts Celsius to Fahrenheit
float CtoF(float tempCelsius) {
return tempCelsius * 1.8 + 32;
}


#### Experiment

Look up the formula to change the temperature reading to Kelvin. Implement that conversion in a new function.

#### How Does the Sensor Work?

When you read an actual thermometer, you're are making an observation. You're looking at the fluid level and comparing it to a known scale. The thermometer sensing component of the BME280 does the same, just not with fluid. There are tiny structures within the sensor that are just barely smaller than a human hair. They are made up of two different layers, with each layer being made up of a different material. The bottom layer will be good at absorbing heat, while the top layer will be much worse. When they absorb heat energy from the environment, the difference in absorption rates makes the bottom layer expand faster than the top layer. This uneven expansion creates a bend in the layers and that bend is not only measureable via voltage, but correlates to the amount of heat energy in the environment, thus measuring the temperature.

### Humidity

No extra connections are needed to measure the humidity.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "Seeed_BME280.h"
#include <Wire.h>
#include <math.h>

BME280 bme280;

int humidity;

void setup() {
Serial.begin(9600);
if (!bme280.init()) {
Serial.println("Device error!");
}
}

void loop() {
// Read humidity as a percentage
humidity = bme280.getHumidity();
Serial.println(humidity);
delay(10);
}


#### Observe

Open up the Serial Plotter and check out the humidity in your environment. The humidity is reported back as the relative humidity. The sensor first calculates what the absolute humidity is via the water vapor level and temperature. That number is then converted to relative humidity, which is a percentage.

#### Experiment

You can breathe on the sensor and watch the humidity rise. I'd like to check out the humidity in my refrigerator. A lower humidity is linked to better preservation of fruits and vegetables To do that, I like to use the longer 50cm cable so I can have the BME280 inside my fridge when its closed and collect data.

#### How Does the Sensor Work?

The mechanism that reacts to the water vapor level is very similar to the temperature sensing mechanism. This time the two layers differ in their ability to absorb water molecules. The top layer is very sensitive to water, while the bottom layer won't absorb it at all. When the top layer absorbs water molecules it swells up like a sponge and again causes a bend in the material. A piezo resistor, or resistor that changes its resistance due to physical stress, measures the bend. From this, you can see a trend of making an observation, then comparing it to know values.

### Pressure

No extra connections are needed to measure the pressure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "Seeed_BME280.h"
#include <Wire.h>
#include <math.h>

BME280 bme280;

float pressure;

void setup() {
Serial.begin(9600);
if (!bme280.init()) {
Serial.println("Device error!");
}
}

void loop() {
// Get Pressure Reading in Pa
pressure = bme280.getPressure();
Serial.println(pressure);
delay(10);
}


#### Observe

Open up the Serial Plotter and check out the pressure in your environment. The biggest factor in pressure is your altitude. Higher altitudes will have lower pressures. Storm systems also generate lower pressures. Actually, pressure drops create storm systems.

#### Experiment

Pressure sensors are used with GPS systems to better estimate your altitude. Try going up or down a floor in a building to see if you can measure a pressure difference.

The pressure reading value can be used to calculate altitude. The library we're using for the BME280 includes a function bme280.calcAltitude() that we can use to calculate the altitude, as shown in the code example below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "Seeed_BME280.h"
#include <Wire.h>
#include <math.h>

BME280 bme280;

float pressure;

void setup() {
Serial.begin(9600);
if (!bme280.init()) {
Serial.println("Device error!");
}
}

void loop() {
// Get pressure
pressure = bme280.getPressure();
//Calculate and print altitude data in meters
Serial.print("Altitude: ");
Serial.print(bme280.calcAltitude(pressure));
Serial.println("m");
}


#### How Does the Sensor Work?

The pressure sensor micro structures are a bit different from the two approaches above. In this implementation, there are two plates separated by air. They both act as the two plates needed to create a capacitor. One plate is rigid while the other can be flexed. The current air pressure pushes on the flexible plate pushing it closer to the other plate. This causes a change in the overall capacitance and that change is measured and is compared to known air pressures for that capacitance.

### Let the Sunshine in

Take a cable and unwrap it. Plug one side into the sunlight sensor socket and the other into any I2C socket.

Take a cable...
Take a cable...
... and unwrap it
Plug one side into the sunlight socket
... and the other into any I2C socket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <Wire.h>
#include <Arduino.h>
#include <SI114X.h>

SI114X sunlightSensor;

void setup() {
Serial.begin(9600);
while (!sunlightSensor.Begin()) {
Serial.println("Check connection");
delay(1000);
}
}

void loop() {
Serial.print("//-------------------------------------//\r\n");
Serial.print("Visible light: ");
Serial.print("IR light: ");
Serial.print("UV index: ");
delay(1000);
}


#### Observe

Open up the Serial Monitor not the Plotter. You can do this by navigating to Tools > Serial Monitor. Every second you'll see a new set of readings. There are three reading that we get from the sunlight sensor. Ambient light, Infrared light, and UV light.

#### Experiment

Try taking the sensor close to a window or even outside to get a UV Index reading.

### Going Mobile

Take a cable and unwrap it. Plug one side into the LCD Display socket and the other into any I2C socket.

Take a cable...
Take a cable...
... and unwrap it
Plug one side into the BME280 socket
... and the other into any I2C socket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

#include <Wire.h>
#include "Seeed_BME280.h"
#include <math.h>
#include "rgb_lcd.h"
#include "Arduino.h"
#include "SI114X.h"

SI114X sunlightSensor;
rgb_lcd lcd;
BME280 bme280;

const int colorR = 50;
const int colorG = 50;
const int colorB = 25;

float Dtemp;

void setup() {
lcd.begin(16, 2);
lcd.setRGB(colorR, colorG, colorB);
Serial.begin(9600);
while (!sunlightSensor.Begin()) {
Serial.println("Sunlight Error");
delay(10);
}
if (!bme280.init()) {
Serial.println("BME Error");
}
}

void loop() {

Dtemp = bme280.getTemperature();
Dtemp = Dtemp * 1.8 + 32;

lcd.setCursor(0, 0);
lcd.print("Humidity = ");
lcd.setCursor(11, 0);
lcd.print(bme280.getHumidity());
lcd.setCursor(0, 1);
lcd.print("Tem = ");
lcd.setCursor(6, 1);
lcd.print(Dtemp);
lcd.setCursor(11, 1);
lcd.print("F");

delay(100);
}


#### Observe

The LCD Display will now update with the Humidity and Temperature. The Display is not big enough to show all the data we have at one time, so we'll have to cycle through it.

Temp and Humidity Data

#### Modify

I've cleaned up the code. We can access all our measurements using just one line. Below you'll find the code to display each measurement is within a function. The screen will display 2 measurements before waiting the switchTime then changing to the other two.

The functions take one argument, TOP or BOTTOM. That decides where on the screen the measurement is displayed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <Wire.h>
#include "Seeed_BME280.h"
#include <math.h>
#include "rgb_lcd.h"
#include "Arduino.h"
#include "SI114X.h"

#define TOP 0
#define BOTTOM 1

SI114X sunlightSensor;
rgb_lcd lcd;
BME280 bme280;

const int colorR = 50;
const int colorG = 50;
const int colorB = 25;

int switchTime = 3000;

void setup() {
lcd.begin(16, 2);
lcd.setRGB(colorR, colorG, colorB);
Serial.begin(9600);
while (!sunlightSensor.Begin()) {
Serial.println("Sunlight Error");
delay(10);
}
if (!bme280.init()) {
Serial.println("BME Error");
}
}

void loop() {
displayTemp(TOP);
displayHumidity(BOTTOM);
delay(switchTime);
displayUV(TOP);
displayPressure(BOTTOM);
delay(switchTime);
}

void displayHumidity(int line) {
clearLine(line);
lcd.setCursor(0, line);
lcd.print("Humidity = ");
lcd.setCursor(11, line);
lcd.print(bme280.getHumidity());
lcd.setCursor(13, line);
lcd.print("%");
}

void displayTemp(int line) {
float Dtemp;
Dtemp = bme280.getTemperature();
Dtemp = Dtemp * 1.8 + 32;

clearLine(line);
lcd.setCursor(0, line);
lcd.print("Temp = ");
lcd.setCursor(7, line);
lcd.print(Dtemp);
lcd.setCursor(12, line);
lcd.print("F");
}

void displayPressure(int line) {
clearLine(line);
lcd.setCursor(0, line);
lcd.print("Press = ");
lcd.setCursor(8, line);
lcd.print(bme280.getPressure());
lcd.setCursor(13, line);
lcd.print("Pa");
}

void displayUV(int line) {
clearLine(line);
lcd.setCursor(0, line);
lcd.print("UV = ");
lcd.setCursor(5, line);
}

void clearLine(int toClear) {
lcd.setCursor(0, toClear);
lcd.print("                ");
}



### More Control

Take a cable and unwrap it. Plug one side into the button socket and the other into any Digital socket.

Take a cable...
Take a cable...
... and unwrap it
Plug one side into the Button socket
... and the other into any Digital socket

Upload the following code. The example below uses the D4 digital pin. You can use any of them, just remember to update the sketch.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <Wire.h>
#include "Seeed_BME280.h"
#include <math.h>
#include "rgb_lcd.h"
#include "Arduino.h"
#include "SI114X.h"
#include <OneButton.h>

#define TOP 0
#define BOTTOM 1

SI114X sunlightSensor;
rgb_lcd lcd;
BME280 bme280;

OneButton button(4, false);
bool screen = false;

const int colorR = 50;
const int colorG = 50;
const int colorB = 25;

void setup() {
lcd.begin(16, 2);
lcd.setRGB(colorR, colorG, colorB);
Serial.begin(9600);
while (!sunlightSensor.Begin()) {
Serial.println("Sunlight Error");
delay(10);
}
if (!bme280.init()) {
Serial.println("BME Error");
}

button.attachClick(buttonClick);
}

void loop() {
button.tick();

if (screen) {
displayTemp(TOP);
displayHumidity(BOTTOM);
} else {
displayUV(TOP);
displayPressure(BOTTOM);
}
}

void buttonClick() {
screen = !screen;
}

void displayHumidity(int line) {
clearLine(line);
lcd.setCursor(0, line);
lcd.print("Humidity = ");
lcd.setCursor(11, line);
lcd.print(bme280.getHumidity());
lcd.setCursor(13, line);
lcd.print("%");
}

void displayTemp(int line) {
float Dtemp;
Dtemp = bme280.getTemperature();
Dtemp = Dtemp * 1.8 + 32;

clearLine(line);
lcd.setCursor(0, line);
lcd.print("Temp = ");
lcd.setCursor(7, line);
lcd.print(Dtemp);
lcd.setCursor(12, line);
lcd.print("F");
}

void displayPressure(int line) {
clearLine(line);
lcd.setCursor(0, line);
lcd.print("Press = ");
lcd.setCursor(8, line);
lcd.print(bme280.getPressure());
lcd.setCursor(13, line);
lcd.print("Pa");
}

void displayUV(int line) {
clearLine(line);
lcd.setCursor(0, line);
lcd.print("UV = ");
lcd.setCursor(5, line);
}

void clearLine(int toClear) {
lcd.setCursor(0, toClear);
lcd.print("                ");
}


#### Observe

Now pressing the button will change which measurements are displayed.

UV and Pressure Data
UV and Pressure Data
Press
Temp and Humidity

#### Modify

Try making your own functions for Ambient and Infrared light measurements.

#### Experiment

The OneButton library supports a few actions. Such as double clicks and long presses. See if you can figure out a better way to scroll through all this data.

### End

You have finished the Main Project for this kit. You can keep it running to monitor the weather conditions in your area. We recommend you keep going and try out a few of the other projects that you're now able to do with the modules in this kit along with the Creator Set modules.