This Weather Station with Arduino was designed for the South Australia Catholic Education STEM Weather Station Challenge. We were lucky enough to be asked to build one of the basic kits provided to schools across South Australia for entry into this challenge! Anyone can build this weather station though, and we will walk you through step by step!
We will be building the minimum viable product for this challenge, but there is so much more that you can do with this weather station! Measure wind speed, rainfall, dust particles in the air, UV light, and so much more! This project is meant to be a launching pad to experiment and develop on your own weather station!
The basic weather station measures the temperature and humidity over time and saves all that data to an SD card for easy analysis!
Collect the Parts
The parts required to build this project are:
- An Arduino Uno
- A ProtoShield Mini Breadboard
- A DHT22 Temperature and Humidity Sensor
- A DS1307 RTC (real time clock)
- A Coin Cell Battery (CR1220)
- An SD Card Module
- An SD Card
- M-M Jumper wires
- M-F Jumper wires
- A USB cord
- A Housing to put it in (model attached)
There is a lot more room to add more to this project! Here are some recommended parts if you are looking to add some elements to your weather station!
Wiring it up
There are a few different components in this project. We found that the best way to assemble it is to first put the ProtoShield on top of the Arduino, and then stick the mini breadboard to the top of the ProtoShield, then wire up the different parts one at a time. We will break down the wiring of the different parts separately for clarity.
Connect the DHT22
This is the temperature sensor and humidity sensor of the weather station. The pins on it aren’t marked, see the below photo for the pinout.
We will first plug the DHT22 into the mini breadboard. Make sure that you orient the sensor the correct way in the breadboard. For a refresher on how breadboards work, check out our How To Use Breadboards Tutorial.
If you're unsure, just make it line up like is shown in the diagram. Remember, the breadboard will be in the center of the ProtoBoard, we have it to the side in this picture so its easier to see where the wires go.
Connect the power and ground to the 5V and GND rails on the ProtoShield. The data line on the DHT22 will connect to Digital Pin 2 on the shield.
Connect the RTC
The Real Time Clock keeps accurate time. The Arduino cannot keep precise time on its own and would quickly be reporting incorrect times with your readings.
This diagram shows just the RTC and Arduino:
Connect the 5V and GND to the respective rails on the ProtoShield, connect the SDA pin to Analog pin 4, SCL to Analog Pin 5.
Connect the SD Card Module
This is how we will store all the readings for later use.
Connect the SD Card Module as shown:
- Arduino 13 > SCK
- Arduino 12 > MISO
- Arduino 11 > MOSI
- Arduino 4 > SDCS
- Arduino 5V > 5V
- Arduino GND > GND
All Together
Here is everything shown hooked up at the same time:
Insert your SD card into the SD card Module and we are ready for the next step!
Setup the IDE
Now its time to load some code onto the newly built weather station! We will be programming with the Arduino IDE (see our Arduino IDE Tutorial). For this code to work we will need to install a few libraries. Here is a full explanation of how to add libraries to Arduino.
The libraries that we need to install are the DHT library, RTC library, and Adafruit Unified Sensor library. Using the ‘manage libraries’ option in the IDE search for “DHT” to find the DHT sensor library shown below, then select install.
Search for “RTClib” to find the below library for the real-time clock.
Search for “Adafruit Unified Sensor” to find the final required library. For us, this was all the way at the bottom of the list.
The Code
Here is the code that we will be using for the weather station. We’ll take a look at the whole thing, then break it down into parts and explain how it all works.
/*CESA Weather Station 2019 */ //include relevant libraries for the Arduino, sensor and Real time clock (RTC) #include "DHT.h" #include "DHT_U.h" #include "SD.h" #include "Wire.h" #include "RTClib.h" //define DHT pin #define DHTPIN 2 // pin the sensor is connected to on arduino (can be any number from 2 - 13) #define DHTTYPE DHT22 // DHT22 is the type of temperature sensor we are using File myFile; // initialize DHT sensor for normal 16mhz Arduino DHT dht(DHTPIN, DHTTYPE); RTC_DS1307 RTC; void setup () { // setup function runs once Serial.begin(9600); //opens serial connection, sets the data rate to 9600 bps (bitspersecond) and waits for the port to open while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Serial.print("Initializing SD card..."); if (!SD.begin(4)) { Serial.println("initialization failed!"); while (1); } Serial.println("initialization done."); // creates a new data file if one does not already exist if (not SD.exists("DATA.txt")) { myFile = SD.open("DATA.txt", FILE_WRITE); myFile.print("DATE, TIME, TEMP *C, HUMIDITY"); myFile.println(); myFile.close(); } //initializing the DHT and RTC dht.begin(); Wire.begin(); RTC.begin(); // Check to see if the RTC is keeping time. if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); // Sets the RTC to the time that this sketch was compiled RTC.adjust(DateTime(F(__DATE__), F(__TIME__))); } } void loop () { DateTime now = RTC.now(); //query the RTC for the current time //read and store the temperature and humidity float t = dht.readTemperature(); float h = dht.readHumidity(); if (isnan(t)) { Serial.println("Failed to read from DHT sensor!"); return; } //writes the current date, time, temperature, hummidity to SD card myFile = SD.open("DATA.txt", FILE_WRITE); myFile.print(now.day(), DEC); myFile.print('/'); myFile.print(now.month(), DEC); myFile.print('/'); myFile.print(now.year(), DEC); myFile.print(','); myFile.print(' '); myFile.print(now.hour(), DEC); myFile.print(':'); //inserts a 0 before minutes from 1-9 so that the time displays correctly, ie 12:05 instead of 12:5 if (now.minute()<10) { myFile.print('0'); myFile.print(now.minute(), DEC); } else { myFile.print(now.minute(), DEC); } myFile.print(','); myFile.print(' '); myFile.print(t); myFile.print(','); myFile.print(' '); myFile.print(h); myFile.println(); myFile.close(); //writes the current date, time, temperature, hummidity to the serial monitor Serial.print(now.day(), DEC); Serial.print('/'); Serial.print(now.month(), DEC); Serial.print('/'); Serial.print(now.year(), DEC); Serial.print(','); Serial.print(' '); Serial.print(now.hour(), DEC); Serial.print(':'); //inserts a 0 before minutes from 1-9 so that the time displays correctly, ie 12:05 instead of 12:5 if (now.minute()<10) { Serial.print('0'); Serial.print(now.minute(), DEC); } else { Serial.print(now.minute(), DEC); } Serial.print(','); Serial.print(' '); Serial.print("Temp: "); Serial.print(t); Serial.print(" *C"); Serial.print(','); Serial.print(' '); Serial.print("Hum: "); Serial.print(h); Serial.println(); delay(10000); //wait time until the device reads the temperature again }
In this first section of code we include the libraries that we are using, and tell the program what sensors we are using.
//include relevant libraries for the Arduino, sensor and Real time clock (RTC) #include "DHT.h" #include "DHT_U.h" #include "SD.h" #include "Wire.h" #include "RTClib.h" //define DHT pin #define DHTPIN 2 // pin the sensor is connected to on arduino (can be any number from 2 - 13) #define DHTTYPE DHT22 // DHT22 is the type of temperature sensor we are using File myFile; // initialize DHT sensor for normal 16mhz Arduino DHT dht(DHTPIN, DHTTYPE); RTC_DS1307 RTC;
The setup part of the code runs once each time the Arduino is powered on. Here we open our serial port, initialize the SD card, DHT22, and RTC. There are a couple of unique parts to this section of code.
First of all, we create a new data file if none exists. We want to store all our data in a text file on the SD card so we can easily read it later. In this section, we check to see if there is already a file on the SD card. If there is already a file then any readings are added to the file. If there is not a file then a new file is created with a header that labels the values. This makes it really easy to read the data later on, but more on that later.
We also check to see that the RTC is running. If it's not yet running then we set the time on the RTC to whenever the code was compiled. This only works the first time that the code is loaded. The RTC will stay running for about 5 years on a single battery (wow!).
void setup () { // setup function runs once Serial.begin(9600); //opens serial connection, sets the data rate to 9600 bps (bitspersecond) and waits for the port to open while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Serial.print("Initializing SD card..."); if (!SD.begin(4)) { Serial.println("initialization failed!"); while (1); } Serial.println("initialization done."); // creates a new data file if one does not already exist if (not SD.exists("DATA.txt")) { myFile = SD.open("DATA.txt", FILE_WRITE); myFile.print("DATE, TIME, TEMP *C, HUMIDITY"); myFile.println(); myFile.close(); } //initializing the DHT and RTC dht.begin(); Wire.begin(); RTC.begin(); // Check to see if the RTC is keeping time. if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); // Sets the RTC to the time that this sketch was compiled RTC.adjust(DateTime(F(__DATE__), F(__TIME__))); } }
The next part of the code is the main loop. This part of the code runs continuously whenever the Arduino is powered. We read the RTC, the temperature and humidity and save them as variables to be used later.
We then open the file on the SD card and “print” our recorded data to it once every 10 seconds. It’s important to “close” the file at the end of each writing. This is what saves the file!
We then print the same data to the serial monitor. This allows you to see what is being recorded on your computer in real time. We added labels in here so it is easier to read.
At the very end of the loop, we have a delay. This pauses the program for a bit so we don’t have constant readings. An Arduino runs very fast and can take many readings every second. This slows the program down to save data and to make the data more meaningful. The temperature does not change every minute, let alone every second, there is no need to take superfast measurements.
void loop () { DateTime now = RTC.now(); //query the RTC for the current time //read and store the temperature and humidity float t = dht.readTemperature(); float h = dht.readHumidity(); if (isnan(t)) { Serial.println("Failed to read from DHT sensor!"); return; } //writes the current date, time, temperature, hummidity to SD card myFile = SD.open("DATA.txt", FILE_WRITE); myFile.print(now.day(), DEC); myFile.print('/'); myFile.print(now.month(), DEC); myFile.print('/'); myFile.print(now.year(), DEC); myFile.print(','); myFile.print(' '); myFile.print(now.hour(), DEC); myFile.print(':'); //inserts a 0 before minutes from 1-9 so that the time displays correctly, ie 12:05 instead of 12:5 if (now.minute()<10) { myFile.print('0'); myFile.print(now.minute(), DEC); } else { myFile.print(now.minute(), DEC); } myFile.print(','); myFile.print(' '); myFile.print(t); myFile.print(','); myFile.print(' '); myFile.print(h); myFile.println(); myFile.close(); //writes the current date, time, temperature, hummidity to the serial monitor Serial.print(now.day(), DEC); Serial.print('/'); Serial.print(now.month(), DEC); Serial.print('/'); Serial.print(now.year(), DEC); Serial.print(','); Serial.print(' '); Serial.print(now.hour(), DEC); Serial.print(':'); //inserts a 0 before minutes from 1-9 so that the time displays correctly, ie 12:05 instead of 12:5 if (now.minute()<10) { Serial.print('0'); Serial.print(now.minute(), DEC); } else { Serial.print(now.minute(), DEC); } Serial.print(','); Serial.print(' '); Serial.print("Temp: "); Serial.print(t); Serial.print(" *C"); Serial.print(','); Serial.print(' '); Serial.print("Hum: "); Serial.print(h); Serial.println(); delay(10000); //wait time until the device reads the temperature again }
Once this loads you can upload the weather station code again, and your RTC should be reporting the correct time!
Working with Data
This program will take readings and save them to a file called DATA.txt whenever it is plugged in. The file is created with a header labelling the values separated by commas, and all the values are separated by commas. This makes it really easy to import into an excel spreadsheet! Just change the file name from “DATA.txt” to “DATA.csv” and open it and your computer will recognise it and open it in Excel properly formatted and everything!
Make a Housing
In order for the weather station to take readings, it needs to be out in the elements! We obviously need to keep it dry somehow though, so that’s where this 3D printed housing comes in handy. If you don’t have access to a 3D printer, a plastic or Tupperware container with vents cut in the sides will work just fine. Just make sure that air can flow freely through the housing but water cannot enter. This 3D printed example is not waterproof, so don’t put it outside somewhere where it can get rained on. It will keep all the electrical bits safe and a little protected though!
When 3d printing, remember to use supports and have the wire opening point up.
Going Further
Don’t stop there, add more to your weather station and contribute more data to your findings! To learn more about Arduino and how to use it. Check out our Arduino Online Workshop. For more information about 3D printing, check out our 3D Printing Online Workshop! If you run into any problems, have a question, or just want to say hi make a post on our Maker Forum!