Thimble Learning Platform
Back to full view

Weather Station 1

Introduction

This is the first in a series of weather themed kits. In this specific kit you'll be measuring and analyzing some fundamental units of weather.

Objectives

  • Learn about weather.
  • Create your weather station and display temperature, pressure, humidity, and UV index.
  • Have fun!
  • I've Never Used an Arduino

    Then this is a great place to start! If you're already familiar with setting up the Arduino and the IDE, you can skip to the next section.

    Terms 

    So when we talk about Arduino, the Arduino IDE, and coding, there are a lot of words being thrown around. This section will clear all of those up and get you ready to start building!

    Arduino 

    The Arduino is a electronics prototyping platform. That means it's a flexible platform for building, testing, and, of course, prototyping electronics. That could be simple LEDs that light up at night, or advanced robots. When we talk about the Arduino we are talking about the physical board itself. The one that comes in this kit is red, but they come in many different shapes and colors. The Arduino brand and original board were created by arduino.cc and you can read more about the details of its history here.

    Arduino IDE 

    The Arduino IDE, or Integrated Development Environment, is not hardware, but a piece of software. If you wanted to write an essay, you might use Microsoft Word or Google Docs. If you wanted to edit pictures, you'd probably use Photoshop or Paint.net. If you want to program code for the Arduino, you'd use the Arduino IDE. Its a computer program (tool) that let's you develop and test out code. Once written, the code can be upload to the physical Arduino where it will stay until you upload new code.

    Download

    Since it is a program, you'll need to install it.

    For Windows computers use this link Windows Installer

    For Mac computers use this link Mac Installer

    After following each link, press the Just Download button to begin downloading the Arduino IDE. The Mac version has a few more steps and we have a video just for that.

    Mac Installation
    For Mac users

    Installation

    Open the exe you downloaded. You'll see a screen asking you to agree to their license. You can press I Agree.

    LicenseLicense

    Next up are the installation options. The Install USB Drivers lets the Arduino board communicate with the IDE. We definitely want this. The Associate .ino files makes any Arduino file on your computer open up to the Arduino IDE. Very helpful, so we'll keep that too. Press Next >.

    OptionsOptions

    Now you are being asked where you'd like the Arduino IDE program installed. I don't mind it in the standard Program Files so I just press Install. You can change where it will be installed, just remember what you chose. I recommend not changing it.

    FolderFolder

    Now the IDE is installing. Let it complete then move on to the next section.

    InstallingInstalling

    Arduino IDE 101

    Open up the Arduino IDE for the first time. So, let's figure out what's what.

    Arduino IDEArduino IDE

    There is a mostly empty space in the middle that has this text:

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void setup() {
      // put your setup code here, to run once:
    
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
    
    }
    

    This is a simple Arduino Sketch. A Sketch is code you write that will later be uploaded to the Arduino board.

    There are few steps to go from code written in a sketch to code that runs on the Arduino board. Those are Verify > Compile > Upload.

    All of these you can get to by going under Sketch on the top bar of the program. Or but using the Checkmark and Arrow icons right below that. The Checkmark verifies your code will compile, and the arrow button uploads the code to the Arduino.

    Sketch
    Icons

    Verify - looks at your code and makes sure it can actually run. It checks that there are no errors or things out of place. If your code will work, it goes to the Compile stage.

    Compile - The code you've written is great for human. It is readable and hopefully understandable. But this isn't great for a machine ie the Arduino. The Compile stage takes your written code and translates into something that the Arduino can understand and run, called machine code. It saves that compiled file and tried to Upload it to the board.

    Upload - This takes the compiled files and tries to send it to a plugged in Arduino. The IDE doesn't know where you've plugged in your Arduino or what kind it is. You have to tell it. I'll show you how to set that up in the next section.

    Arduino Board Setup

    For this section make sure your Arduino Board that came with your kit is plugged in. Use the included micro USB cable to plug your Arduino into any free USB port on you computer.

    Navigate to the Tools section at the top of the Arduino IDE.

    ToolsTools

    You'll be greeted with a scary drop down. To setup your Arduino to accept uploads, do the following: Go to Board: and make sure Arduino/Genuino Uno is selected.

    Next is the Port. For Mac users refer to the video for these instructions. With your Arduino plugged in, you'll see some options. Mine says COM 15. This is the channel that the IDE will use to communicate with your Arduino. If you have a lot of COM # devices and don't know which is your Arduino, unplug your Arduino and take note of that numbers are there. Then plug it back in. Whichever is the new one in the list is your Arduino. Select that port.

    With the board and port selected and ready to go, let's upload our first sketch.

    Sketches

    We are going to upload a simple sketch to make an LED on the board blink. Head to File > Examples > Basics > Blink . You should see this sketch.

    Download file Copy to clipboard
    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
    /*
      Blink
    
      Turns an LED on for one second, then off for one second, repeatedly.
    
      Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
      it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
      the correct LED pin independent of which board is used.
      If you want to know what pin the on-board LED is connected to on your Arduino
      model, check the Technical Specs of your board at:
      https://www.arduino.cc/en/Main/Products
    
      modified 8 May 2014
      by Scott Fitzgerald
      modified 2 Sep 2016
      by Arturo Guadalupi
      modified 8 Sep 2016
      by Colby Newman
    
      This example code is in the public domain.
    
      http://www.arduino.cc/en/Tutorial/Blink
    */
    
    // the setup function runs once when you press reset or power the board
    void setup() {
      // initialize digital pin LED_BUILTIN as an output.
      pinMode(LED_BUILTIN, OUTPUT);
    }
    
    // the loop function runs over and over again forever
    void loop() {
      digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(1000);                       // wait for a second
      digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
      delay(1000);                       // wait for a second
    }
    

    Don't worry about the coding for now. Let's upload this sketch. You can press the Arrow icon, go to Sketch then Upload, or you can use the shortcut Ctrl+U in order to upload the code. Your sketch will auto-verify, compile, then upload to your Arduino board.

    You will see the message Done uploading and your board should now have a blinking light.

    Uploading Sketches and Code From Thimble 

    We provide example code for all our projects. To use those you'll need to copy them from our website. Then, go into the Arduino IDE, File > New. It's best to then delete all the code already there in the sketch before you paste our code in, as that will avoid any errors from copying over the old code.

    Serial Plotter

    You'll be asked to use the Serial Plotter on some projects. This reads any information coming from the Arduino and displays it on a graph. It can only be accessed after you've uploaded your code. It is in the Tools menu.

    Troubleshooting 

    The most common issues are solved by double checking your Board and Port settings.

    Libraries

    What are Libraries? 

    Libraries are a collection of code that has already been written. We use them when we want to add functionality without have to write everything from scratch. The advantage of using a library is code re-use.

    Some of the projects in this set need libraries so this section will show you how to install those.

    Libraries to be downloaded 

    Our libraries come in the form of zip files that need to be downloaded but NOT unzipped.

    BME 280 - This is for the BME280 sensor.

    Sunlight - This is for the sunlight sensor.

    LED Bar Graph - This is for the LED bar graph.

    Adding Them to the Arduino IDE 

    Open up the Arduino IDE and go to Sketch > Include Library > Add .ZIP Library.... After that navigate to the zip files and add them one by one. And that's it!

    Add a LibraryAdd a Library

    What Should I Have Received?

    Modules 

    Inside, you'll find 3 new modules. An all-in-one temperature, humidity, and pressure sensor called the BME280. A sunlight and UV sensor, which we'll call the Sunlight Sensor. And an LED bar graph.

    BME280
    Sunlight
    LED Bar Graph

    Additional Items 

    You'll also find an extra long connector spanning 50 centimeters, 5 plastic 'wrappers' (these are housings that the grove modules can click into), and a sheet of weather related stickers designed in-house at Thimble!

    What is Weather?

    Weather vs Climate 

    Weather is the state of the atmosphere in a minute-to-minute or day-to-day sense. Is it hot or cold? Wet or dry? Cloudy or clear? Climate is the trend of weather patterns over a long period of time. Arizona is a sunny place because we can look back at day by day weather data and see that trend. Weather can change in an instant, but climate takes years.

    Weather is composed of three major physical properties. They are temperature, moisture content, and air pressure. Changes in these three properties are responsible for all of the weather you experience.

    Temperature 

    Temperature is the measurement of heat energy. When something has a lot of heat energy,it will feel hot and measure at a higher number. When something doesn't have a lot of heat energy, it will feel cold and measure at a smaller number. Temperature is also related to motion. All molecules vibrate, but molecules with more heat energy will vibrate faster, which is what we are measuring when we measure temperature.

    Molecules at different heat levelsMolecules at different heat levels

    The most common units used to measure temperature are Celsius, Fahrenheit, and Kelvin. Although they all measure the same thing, they each represent different scales. The Celsius scale is based around the temperature of water. 0 degrees Celsius is the freezing point of liquid water, while 100 degrees Celsius is the boiling point. The origins of the Fahrenheit scale are still argued about today. Typically, the story goes that 0 degrees Fahrenheit was the temperature of a solution of ice, water, and salt, while 96 degrees was the temperature of the human body. The modern value of the human body is 98.6ºF. Finally there's Kelvin which is actually just a unit not a scale like the others and is defined by 0 K. The temperature where there is no motion or heat energy, also known as absolute zero.

    Moisture 

    Moisture or humidity refer to the amount of water vapor in the atmosphere. It takes a large amount of energy to heat up water so humidity plays a large role in temperature regulation. Areas that are close to a body of water, such as coastal cities, experience less intense temperature swings. The water acts like a heat buffer. It will soak up heat when it's warm and radiate heat when it turns cold. A desert with its low humidity will have very hot days and very cold nights. The desert has no buffer and the temperature is more reliant on whether the sun is shining or not.

    Humidity also plays a role in precipitation. Precipitation is when water vapor turns from gas to a liquid and falls from the atmosphere. Such as rain, sleet, snow, and hail. When the vapor condenses it falls to the ground. If the vapor passes through a cold section of air then it can freeze into snow or hail.

    How temperature and humidity cause precipitationHow temperature and humidity cause precipitation

    Humidity is measured in three ways: absolute, relative, and specific. Absolute humidity is a measurement of how much water by weight is in a volume of air, and is expressed in grams per cubic meter. Relative humidity measures the current absolute humidity and relates that to the maximum humidity. Since there can only be a certain amount of water in a portion of air. Once that saturation is reached you've hit the dewpoint and the vapor will condense and precipitate. Relative humidity is measured as a percent. So, 0% would mean there is no water vapor in the air and 100% means that the air has the most water vapor it can hold. How much vapor the air can hold is dependent on the temperature and pressure of the air. Warmer air is less dense so there is more room for vapor. Lower pressure air is also less dense so it too can hold more water vapor. Specific humidity is the ratio of the mass of water to the mass of air in a any given volume. It is different from absolute humidity in that it compares mass to mass and not mass to volume.

    Higher humidity makes it feel hotterHigher humidity makes it feel hotter

    Air Pressure 

    We can't see air but just like us, it too is affected by gravity. Air molecules are pulled towards the surface of the Earth. The force of this air being pulled down creates air pressure. How much pressure depends on the density of the air in question which depends on the temperature and altitude. Have you ever wondered why hot air rises and cold air sinks? When higher temperature air molecules vibrate faster, they push other molecules away, the hot air becomes more spread out and therefore less dense so it rises up into the atmosphere. You also might have wondered why air at higher altitudes is thinner. The higher up in the atmosphere you go, the more space the air has to fill. Since air will spread out to do this it becomes less dense.

    Altitude and pressureAltitude and pressure

    Pressure is measured in a few different units. The most common unit is in Pascals. A single Pascal is the weight of one kilogram across a square meter. So what does that feel like? Well 101,325 Pascals makes up a single Atmosphere, or atm, which is another unit of measurement. One atm is the normal pressure at sea level. When you blow up a balloon, you are pressurizing it to about 1 atm or 101,325 Pa. Another measurement you might have seen is PSI, or pounds per square inch. Which is the imperial version of the Pascal. So instead of kilograms per square meter, it's pounds per square inch. Tires, basketballs, and footballs will often use this unit for their measurement.

    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.

    Parts

    All Parts x Qty
    BME280 x 1
    Sunlight x 1
    Button x 1
    LCD Display x 1
    Cable x 3
    Wrapper 2x1 x 1
    Wrapper 1x1 x 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
    Take a cable...
    ... and unwrap it
    Plug one side into the BME280 socket
    ... and the other into any I2C socket

    Upload

    Upload the following code.

    Download file Copy to clipboard
    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=degreesCelsius1.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.

    Download file Copy to clipboard
    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.

    Upload

    Upload the following code.

    Download file Copy to clipboard
    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.

    Upload

    Upload the following code.

    Download file Copy to clipboard
    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.

    Download file Copy to clipboard
    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...
    ... and unwrap it
    Plug one side into the sunlight socket
    ... and the other into any I2C socket

    Upload

    Upload the following code.

    Download file Copy to clipboard
    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.println(sunlightSensor.ReadVisible());
      Serial.print("IR light: ");
      Serial.println(sunlightSensor.ReadIR());
      Serial.print("UV index: ");  
      Serial.println((float)sunlightSensor.ReadUV() / 100);
      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...
    ... and unwrap it
    Plug one side into the BME280 socket
    ... and the other into any I2C socket

    Upload

    Upload the following code.

    Download file Copy to clipboard
    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 DataTemp 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.

    Download file Copy to clipboard
    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);
      lcd.print((float)sunlightSensor.ReadUV() / 100);
    }
    
    void clearLine(int toClear) {
      lcd.setCursor(0, toClear);
      lcd.print("                ");
    }
    
    
    Temp and Humidity Data
    UV and Pressure Data

    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...
    ... and unwrap it
    Plug one side into the Button socket
    ... and the other into any Digital socket

    Upload

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

    Download file Copy to clipboard
    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);
      lcd.print((float)sunlightSensor.ReadUV() / 100);
    }
    
    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
    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.

    How to Use Wrappers

    What Are Wrappers? 

    Wrappers are plastic housings made for grove modules. There are two sizes that the wrappers come in. They are the 1x1 square and the 2x1 rectangle. The wrappers can connect to each other and can be used to add some structure or organization to your project. The bottom of the wrappers are compatible with standard Lego-type bricks.

    How-to 

    Here is a demonstration using 1x1 and 2x1 sized wrappers. There are tiny plastic nubs found on the wrapper that should match up with the holes found on the outside of the grove modules. Once you find the correct orientation, slide one side of the grove module under the two retention clips. Press down on the other side and you'll hear a click.

    All the parts for this how to
    Starting with the 2x1
    Slide in one side
    Press down to hear the click
    Correct orientation
    Now the 1x1
    Slide in one side
    Press down
    Installed

    Fitting Them Together 

    You can attach wrappers together by sliding them together on any side. To take a module out of the wrapper you'll need to pull back one side of the retention clips and remove. Do not put pressure on the grove connector itself.

    Connecting these two
    Line up the mounting slots
    Slide to connect
    Slide the other way
    To disconnect
    They can also be connected this way
    They can also be connected this way
    They can also be connected this way
    These are the retention clips
    These are the retention clips
    LED Bar Graph

    Start 

    The LED Bar Graph has 10 individually controllable LEDs. 1 red, 1 yellow, and 8 green.

    Modules 

    Gather the following parts to complete this project.

    Parts

    All Parts x Qty
    LED Bar Graph x 1
    Rotary Potentiometer x 1
    BME280 x 1
    Cable x 2

    LED Bar Graph Levels Demo 

    Take a cable and unwrap it. Plug one side into the LED Bar Graph socket and the other into the D8 socket.

    All the parts you'll need
    Take a cable...
    ... and unwrap it
    Plug one side into the LED Bar Graph socket
    ... and the other into the D8 socket

    Upload

    Upload the following code.

    Download file Copy to clipboard
    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
    /*
    Grove LED Bar - Level Example
    This example will show you how to use setLevel() function of this library.
    The setLevel() function illuminates the given number of LEDs from either side.
    Syntax setLevel(level)
    0  = all LEDs off
    5  = 5 LEDs on
    10 = all LEDs on
    */
    
    #include <Grove_LED_Bar.h>
    
    Grove_LED_Bar bar(9, 8, 0);  // Clock pin, Data pin, Orientation
    
    void setup()
    {
      // nothing to initialize
      bar.begin();
    }
    
    void loop()
    {
      // Walk through the levels
      for (int i = 0; i <= 10; i++)
      {
        bar.setLevel(i);
        delay(100);
      }
    }
    

    Observe

    Look at the LED Bar Graph as it cycles through all 10 levels.

    Bar Graph Levels
    Bar Graph Levels
    Bar Graph Levels

    LED Bar Graph Basic Control 

    Each individual LED on the bar graph is controllable. The following example code utilizes binary to turn off the individual LEDs.

    Upload

    Upload the following code.

    Download file Copy to clipboard
    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
    /*
    Grove LED Bar - Basic Control Example
    This example will show you how to use the setBits() function of this library.
    Set any combination of LEDs using 10 bits.
    Least significant bit controls the first LED.
    The setBits() function sets the current state, one bit for each LED.
    First 10 bits from the right control the 10 LEDs.
    eg. 0b00000jihgfedcba
    a = LED 1, b = LED 2, c = LED 3, etc.
    dec    hex     binary
    0    = 0x0   = 0b000000000000000 = all LEDs off
    5    = 0x05  = 0b000000000000101 = LEDs 1 and 3 on, all others off
    341  = 0x155 = 0b000000101010101 = LEDs 1,3,5,7,9 on, 2,4,6,8,10 off
    1023 = 0x3ff = 0b000001111111111 = all LEDs on
                          |        |
                          10       1
    The bits >10 are ignored, shown here as x: 0bxxxxx0000000000
    */
    
    #include <Grove_LED_Bar.h>
    
    Grove_LED_Bar bar(9, 8, 0);  // Clock pin, Data pin, Orientation
    
    void setup()
    {
      // nothing to initialize
      bar.begin();
    }
    
    void loop()
    {
      // Turn on all LEDs
      bar.setBits(0x3ff);
      delay(1000);
    
      // Turn off all LEDs
      bar.setBits(0x0);
      delay(1000);
    
      // Turn on LED 1
      // 0b000000000000001 can also be written as 0x1:
      bar.setBits(0b000000000000001);
      delay(1000);
    
      // Turn on LEDs 1 and 3
      // 0b000000000000101 can also be written as 0x5:
      bar.setBits(0b000000000000101);
      delay(1000);
    
      // Turn on LEDs 1, 3, 5, 7, 9
      bar.setBits(0x155);
      delay(1000);
    
      // Turn on LEDs 2, 4, 6, 8, 10
      bar.setBits(0x2AA);
      delay(1000);
    
      // Turn on LEDs 1, 2, 3, 4, 5
      // 0b000000000011111 == 0x1F
      bar.setBits(0b000000000011111);
      delay(1000);
    
      // Turn on LEDs 6, 7, 8, 9, 10
      // 0b000001111100000 == 0x3E0
      bar.setBits(0b000001111100000);
      delay(1000);
    }
    

    Observe

    Look at the LED Bar Graph as it cycles through controlling each of the LEDs.

    Experiment

    Modify the code to create your own patterns.

    Alternative

    You can also control the individual LEDs using the setLed() function. It takes two numbers as an argument. The first is the number of the led that you want to control and the second is whether you want it on or off (1 or 0). For example, the line bar.setLed(5, 1); turns the fifth led on and the line bar.setLed(8, 0); turns the eighth led off. Here is the previous example but using this function.

    Download file Copy to clipboard
    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
    #include <Grove_LED_Bar.h>
    
    Grove_LED_Bar bar(9, 8, 0);  // Clock pin, Data pin, Orientation
    
    void setup()
    {
      // nothing to initialize
      bar.begin();
    }
    
    void loop()
    {
      // Turn on all LEDs
      for (int i = 0; i <= 10; i++)
      {
        bar.setLed(i,1);
      }
      delay(1000);
    
      // Turn off all LEDs
      for (int i = 10; i >= 0; i--)
      {
        bar.setLed(i,0);
      }
      delay(1000);
    
      // Turn on LED 1
      bar.setLed(1,1);
      delay(1000);
    
      ledsOff();
    
      // Turn on LEDs 1 and 3
      bar.setLed(1,1);
      bar.setLed(3,1);
      delay(1000);
    
      ledsOff();
    
      // Turn on LEDs 1, 3, 5, 7, 9
      bar.setLed(1,1);
      bar.setLed(3,1);
      bar.setLed(5,1);
      bar.setLed(7,1);
      bar.setLed(9,1);
      delay(1000);
    
      ledsOff();
    
      // Turn on LEDs 2, 4, 6, 8, 10
      bar.setLed(2,1);
      bar.setLed(4,1);
      bar.setLed(6,1);
      bar.setLed(8,1);
      bar.setLed(10,1);
      delay(1000);
    
      ledsOff();
    
      // Turn on LEDs 1, 2, 3, 4, 5
      bar.setLed(1,1);
      bar.setLed(2,1);
      bar.setLed(3,1);
      bar.setLed(4,1);
      bar.setLed(5,1);
      delay(1000);
    
      ledsOff();
    
      // Turn on LEDs 6, 7, 8, 9, 10
      bar.setLed(6,1);
      bar.setLed(7,1);
      bar.setLed(8,1);
      bar.setLed(9,1);
      bar.setLed(10,1);
      delay(1000);
    }
    
    void ledsOff(){
        bar.setBits(0x0);
    }
    

    Displaying the Potentiometer Value 

    Take a cable and unwrap it. Plug one side into the rotary potentiometer socket and the other into the A0 socket.

    Take a cable...
    ... and unwrap it
    Plug one side into the rotary potentiometer socket
    ... and the other into the A0 socket

    Upload

    Upload the following code.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <Grove_LED_Bar.h>
    #define dialSocket A0
    
    Grove_LED_Bar bar(9, 8, 0);  // Clock pin, Data pin, Orientation
    
    void setup()
    {
      pinMode(dialSocket, INPUT);
    
      // nothing to initialize
      bar.begin();
    }
    
    void loop()
    {
      int dialValue = analogRead(dialSocket);
      int barGraphLevel = map(dialValue, 0, 1023, 0, 11);
      bar.setLevel(barGraphLevel);
    }
    

    Observe

    Rotate the potentiometer and see how the level of the LED Bar Graph changes.

    Dial one way
    Dial other way
    A connection

    Additional Information

    You might be wondering why we've set the range on the map function from 0 to 11 and not 0 to 10. That's because if you use the value 10 then you'll only be able to completely fill the bar if the potentiometer is turned to the max. If it's even a little bit short you won't reach it. Try this yourself: just change the 11 to a 10 and you'll see that you can barely fill the bar. You might not even be able to completely fill the bar at all (don't try to force it).

    Temperature Indicator 

    Let's modify the code to display temperature instead. This way we can know whether to dress for warm weather or cold weather by quickly glancing at the LED Bar Graph. Swap out the Rotary Potentiometer for the BME280.

    Unplug the rotary potentiometer from A0 socket
    Plug it in to any I2C socket
    Unplug the cable from the rotary potentiometer
    Plug in the BME280

    Upload

    Upload the following code.

    Download file Copy to clipboard
    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 <Grove_LED_Bar.h>
    #include "Seeed_BME280.h"
    #include <Wire.h>
    #include <math.h>
    
    BME280 bme280;
    
    float temperature;
    
    //These are in Celsius
    float highTemp = 30;
    float lowTemp = 15;
    
    
    Grove_LED_Bar bar(9, 8, 0);  // Clock pin, Data pin, Orientation
    
    void setup()
    {
      bar.begin();
      bme280.init();
    }
    
    void loop()
    {
      temperature = bme280.getTemperature();
      int barGraphLevel = map(temperature, lowTemp, highTemp, 1, 11);
      bar.setLevel(barGraphLevel);
    }
    

    Modify 

    Change the highTemp and lowTemp variables to temperatures that you find comfortable. lowTemp is the lowest you feel comfortable with. Any lower than your lowTemp and it will appear red on the LED Bar Graph.

    Finished
    It's warm in the studio
    Indoor Pressure Experiment

    Does this stuff really work? 

    I tested the BME280's air pressure reading inside Thimble HQ. We work in a 4 story building and there should be a presure difference between different floors.

    Hypothesis 

    The pressure inside a building should decrease as you go to higher floors. When you go higher there is less air pushing down on you and so you feel less pressure. You might notice this if you travel down a big hill or take an elevator in a tall building: you can feel the pressure difference in your ears, and you might even feel a pop when they adjust! With our pressure sensor we can detect much smaller changes in pressure than you can with your ears, and we should even be able to tell the difference between different floors just from the pressure.

    Testing 

    I uploaded the final code from the Main Project and used a 9 volt battery to take it mobile. Armed with a trusty pen and post-it I took records of the pressure starting at the ground floor. I would go up one flight of stairs and give the sensor 2 minutes to stabilize (a very generous amount of time) before I wrote down the pressure.

    Results 

    Here is a table of my results. All measurements were taken at ~55 degrees Fahrenheit at 47% relative humidity.

    Floor Pressure
    4th 97806 Pa
    3rd 97862 Pa
    2nd 97916 Pa
    1st 97975 Pa

    Pictorial Results 

    Datasheets