Building a DIY Home Weather Station with Advanced Features Monitoring Wind Speed Rainfall and UV Index
DIY Weather Station With ESP32
But now we have all the electronics, which will be in this junction box. To make the connections easier, I bought this board that carries the ESP32 pins on terminals. I don't know why, but my ESP32 doesn't fit on this board. So I had to make adapters with a perfboard to move the pins. I screwed the ESP32 in the box, and on the underside I put the antenna for the WiFi connection.
I almost forgot about the atmospheric pressure sensor, which is the BMP180. I put it here in the box, and to let the air pass through I made this grid on the underside. This sensor communicates via i2c, so it needs two wires to connect to the ESP32, other than 3,3v and GND.
Now we have all the other sensors coming in here with their wires. The temperature sensor has only one signal wire, and it connects directly to an ESP32's pin. The problem are the hall sensors of the anemometer, rain gauge and wind vane, which operate at 5v, while the ESP32 operates at 3.3v. So to convert the signal from 5v to 3.3v I will use some level converters, like these. To make everything neater, I soldered them onto perfboards. To make the connections between the boards and the ESP32 I used JST connectors, which are more solid than classic jumpers. Finally, I joined together the wires for gnd, 5v and 3.3v, and tidied up the wires with cable ties.
Above you can find the schematics for all the electrical connections for the sensors.
Make Your Own Arduino Weather Station!
Program
In order for this program to work, you will need to install the U8glib library. This library controls graphics on the LCD screen. It can be foundhere.
When the library is installed, copy this code in to Arduino IDE and upload it to the microcontroller.
If you feel adventurous and want to improve your Arduino C skills, try copying it out line by line.
/***************************************************
DFRobot
SEN0186 Weather Station
Weather Station + DFRobot LCD Shield
***************************************************
This example outputs data from the DFRobot Weather Station kit (SEN0186) to a DFRobot LCD12864 shield (DFR0287)
Updated 2016-01-18
By Matt GNU Lesser
General Public License.
See for details.
All above must be included in any redistribution
****************************************************/
/***********Notice and Troubleshooting***************
For help and info visit the wiki:
http://www.dfrobot.com/wiki/index.php?title=Weath...
http://www.dfrobot.com/wiki/index.php?title=LCD12...
For any other problems, post on the DFRobot forum or email [email protected] ****************************************************/
#include "U8glib.h" //invoke library
//LCD
U8GLIB_NHD_C12864 u8g(13, 11, 10, 9, 8); // SPI Com: SCK = 13, MOSI = 11, CS = 10, CD = 9, RST = 8
void draw(void) {
// graphic commands to redraw the complete screen should be placed here
u8g.setFont(u8g_font_trixel_square);
//line pixel references
#define line1 05
#define line2 12
#define line3 19
#define line4 26
#define line5 33
#define line6 40
#define line7 47
#define line8 55
//column pixel references
#define cola 0
#define colb 85
#define colc 110
//Temperature
u8g.drawStr(cola, line1, "Temperature:");
u8g.setPrintPos(colb, line1);
u8g.print(Temperature());
u8g.setPrintPos(colc, line1);
u8g.print("C");
//Humidity
u8g.drawStr(cola, line2, "Humidity:" );
u8g.setPrintPos(colb, line2);
u8g.print(Humidity());
u8g.setPrintPos(colc, line2);
u8g.print("%");
//Wind Direction
u8g.drawStr(cola, line3, "Wind direction:");
//compass directions
if (WindDirection() == 0) {
u8g.setPrintPos(colb, line3);
u8g.print("North");
}
else if (WindDirection() == 45) {
u8g.setPrintPos(colb, line3);
u8g.print("North East");
}
else if (WindDirection() == 90) {
u8g.setPrintPos(colb, line3);
u8g.print("East");
}
else if (WindDirection() == 135) {
u8g.setPrintPos(colb, line3);
u8g.print("South East");
}
else if (WindDirection() == 180) {
u8g.setPrintPos(colb, line3);
u8g.print("South");
}
else if (WindDirection() == 225) {
u8g.setPrintPos(colb, line3);
u8g.print("South West");
}
else if (WindDirection() == 270) {
u8g.setPrintPos(colb, line3);
u8g.print("West");
}
else if (WindDirection() == 315) {
u8g.setPrintPos(colb, line3);
u8g.print("North West");
}
//Wind Speed Average/min
u8g.drawStr(cola, line4, "Average wind speed/min:");
u8g.setPrintPos(colb, line4);
u8g.print(WindSpeedAverage());
u8g.setPrintPos(colc, line4);
u8g.print("m/s");
//max wind speed 5 mins
u8g.drawStr(cola, line5, "Max wind speed (5 min):");
u8g.setPrintPos(colb, line5);
u8g.print(WindSpeedMax());
u8g.setPrintPos(colc, line5);
u8g.print("m/s");
//rainfall (one hour)
u8g.drawStr(cola, line6, "Rainfall (1 hour):");
u8g.setPrintPos(colb, line6);
u8g.print(RainfallOneHour());
u8g.setPrintPos(colc, line6);
u8g.print("mm");
//rainfall (24 hours)
u8g.drawStr(cola, line7, "Rainfall (24 hours):");
u8g.setPrintPos(colb, line7);
u8g.print(RainfallOneDay());
u8g.setPrintPos(colc, line7);
u8g.print("mm");
//barometric pressure
u8g.drawStr(cola, line8, "Barometric pressure:");
u8g.setPrintPos(colb, line8);
u8g.print(BarPressure());
u8g.setPrintPos(colc, line8);
u8g.print("hPa");
}
char databuffer[35];
double temp;
void getBuffer() //Get weather status data
{
int index;
for (index = 0; index < 35; index ++)
{
if (Serial.available())
{
databuffer[index] = Serial.read();
if (databuffer[0] != 'c')
{
index = -1;
}
}
else
{
index --;
}
}
}
int transCharToInt(char *_buffer, int _start, int _stop) //char to int?
{
int _index;
int result = 0;
int num = _stop - _start + 1;
int _temp[num];
for (_index = _start; _index <= _stop; _index ++)
{
_temp[_index - _start] = _buffer[_index] - '0';
result = 10 * result + _temp[_index - _start];
}
return result;
}
int WindDirection() //Wind Direction
{
return transCharToInt(databuffer, 1, 3);
}
float WindSpeedAverage() //air Speed (1 minute) { temp = 0.44704 * transCharToInt(databuffer, 5, 7); return temp; }
float WindSpeedMax() //Max air speed (5 minutes) { temp = 0.44704 * transCharToInt(databuffer, 9, 11); return temp; }
float Temperature() //Temperature ("C")
{
temp = (transCharToInt(databuffer, 13, 15) - 32.00) * 5.00 / 9.00;
return temp;
}
float RainfallOneHour() //Rainfall (1 hour)
{
temp = transCharToInt(databuffer, 17, 19) * 25.40 * 0.01;
return temp;
}
float RainfallOneDay() //Rainfall (24 hours)
{
temp = transCharToInt(databuffer, 21, 23) * 25.40 * 0.01;
return temp;
}
int Humidity() //Humidity
{
return transCharToInt(databuffer, 25, 26);
}
float BarPressure() //Barometric Pressure
{
temp = transCharToInt(databuffer, 28, 32);
return temp / 10.00;
}
void setup()
{
Serial.begin(9600);
u8g.setContrast(0); // Config the contrast to the best effect
u8g.setRot180();// rotate screen, if required
// set SPI backup if required
//u8g.setHardwareBackup(u8g_backup_avr_spi);
// assign default color value
if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
u8g.setColorIndex(255); // white
}
else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
u8g.setColorIndex(3); // max intensity
}
else if ( u8g.getMode() == U8G_MODE_BW ) {
u8g.setColorIndex(1); // pixel on
}
else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
u8g.setHiColorByRGB(255, 255, 255);
}
}
void loop() {
getBuffer(); //Begin!
Serial.print("Wind Direction: ");
Serial.print(WindDirection());
Serial.println(" ");
Serial.print("Average Wind Speed (One Minute): ");
Serial.print(WindSpeedAverage());
Serial.println("m/s ");
Serial.print("Max Wind Speed (Five Minutes): ");
Serial.print(WindSpeedMax());
Serial.println("m/s");
Serial.print("Rain Fall (One Hour): ");
Serial.print(RainfallOneHour());
Serial.println("mm ");
Serial.print("Rain Fall (24 Hour): ");
Serial.print(RainfallOneDay());
Serial.println("mm");
Serial.print("Temperature: ");
Serial.print(Temperature());
Serial.println("C ");
Serial.print("Humidity: ");
Serial.print(Humidity());
Serial.println("% ");
Serial.print("Barometric Pressure: ");
Serial.print(BarPressure());
Serial.println("hPa");
Serial.println("");
Serial.println("");
//LCD output
u8g.firstPage();
do {
draw();
}
while ( u8g.nextPage() );
// rebuild the picture after some delay
delay(500);
}
Code Analysis
#include "U8glib.h" //invoke library
First we need to include the library to control graphics
//LCD
U8GLIB_NHD_C12864 u8g(13, 11, 10, 9, 8); // SPI Com: SCK = 13, MOSI = 11, CS = 10, CD = 9, RST = 8
In this line pins are declared that will drive the LCD screen
void draw(void) {
// graphic commands to redraw the complete screen should be placed here u8g.setFont(u8g_font_trixel_square);
These lines of code set the font used by the LCD. We have selected the smallest possible one so as to fit all the data on one page of the screen. If you want you may change it. A useful reference guide can be found here: https://code.google.com/p/u8glib/
//line pixel references
#define line1 05
#define line2 12
#define line3 19
#define line4 26
#define line5 33
#define line6 40
#define line7 47
#define line8 55
//column pixel references
#define cola 0
#define colb 85
#define colc 110
In order to place the information on the screen neatly, I have set up pixel references for lines and columns in code. We have 8 lines of text going down the page for each sensor reading, and 3 columns going across the page: column a (cola) for the reading label, column b (colb) for the reading itself, and column c (colc) for the unit of measurement.
The reason I have done this here is that it saves me having to write the pixel number in each line of code, and can instead substitute these. You will see each appear in the next lines of code.
//Temperature
u8g.drawStr(cola, line1, "Temperature:");
u8g.setPrintPos(colb, line1);
u8g.print(Temperature());
u8g.setPrintPos(colc, line1);
u8g.print("C");
This section of code prints the readout for the temperature sensor. The sensor calculations occur later in the code and are referenced.
The drawStr line of code sets the position of text, and then prints the text in inverted commas (Temperature:)
The next line sets the positioning again (colb, line1) for the following line of code.
The next line calls the function Temperature() and prints the output in this space.
The next line prints the unit (C) in column c of line 1.
All of the other readouts behave in much the same way. The only one that varies is the wind direction module:
//Wind Direction
u8g.drawStr(cola, line3, "Wind direction:");
//compass directions
if (WindDirection() == 0) {
u8g.setPrintPos(colb, line3);
u8g.print("North");
}
else if (WindDirection() == 45) {
u8g.setPrintPos(colb, line3);
u8g.print("North East");
}
else if (WindDirection() == 90) {
u8g.setPrintPos(colb, line3);
u8g.print("East");
}
else if (WindDirection() == 135) {
u8g.setPrintPos(colb, line3);
u8g.print("South East");
}
else if (WindDirection() == 180) {
u8g.setPrintPos(colb, line3);
u8g.print("South");
}
else if (WindDirection() == 225) {
u8g.setPrintPos(colb, line3);
u8g.print("South West");
}
else if (WindDirection() == 270) {
u8g.setPrintPos(colb, line3);
u8g.print("West");
}
else if (WindDirection() == 315) {
u8g.setPrintPos(colb, line3);
u8g.print("North West");
}
The wind direction displays depending on the angle of the wind vane. If we think of the wind vanes rotational path as a circle of 360 degrees, we can attribute compass directions to these values. North is 0 degrees, East is 90 degrees, South is 180 degrees and West is 270 degrees.
For a greater resolution of directions I have also added North East (45 degrees), South East (135 degrees), South West (225 degrees) and North West (315 degrees). If the vanes rotation is equal to these values, the LCD will serial print the corresponding compass bearing.
This part of the code manages the data calculations:
char databuffer[35];
double temp;
void getBuffer() //Get weather status data
{
int index;
for (index = 0; index < 35; index ++)
{
if (Serial.available())
{
databuffer[index] = Serial.read();
if (databuffer[0] != 'c')
{
index = -1;
}
}
else
{
index --;
}
}
}
int transCharToInt(char *_buffer, int _start, int _stop) //char to int?
{
int _index;
int result = 0;
int num = _stop - _start + 1;
int _temp[num];
for (_index = _start; _index <= _stop; _index ++) {
_temp[_index - _start] = _buffer[_index] - '0';
result = 10 * result + _temp[_index - _start];
}
return result;
}
int WindDirection() //Wind Direction
{
return transCharToInt(databuffer, 1, 3);
}
float WindSpeedAverage() //air Speed (1 minute)
{
temp = 0.44704 * transCharToInt(databuffer, 5, 7);
return temp;
}
float WindSpeedMax() //Max air speed (5 minutes) {
temp = 0.44704 * transCharToInt(databuffer, 9, 11);
return temp;
}
float Temperature() //Temperature ("C") {
temp = (transCharToInt(databuffer, 13, 15) - 32.00) * 5.00 / 9.00;
return temp;
}
float RainfallOneHour() //Rainfall (1 hour) {
temp = transCharToInt(databuffer, 17, 19) * 25.40 * 0.01;
return temp;
}
float RainfallOneDay() //Rainfall (24 hours) {
temp = transCharToInt(databuffer, 21, 23) * 25.40 * 0.01;
return temp;
}
int Humidity() //Humidity
{
return transCharToInt(databuffer, 25, 26);
}
float BarPressure() //Barometric Pressure {
temp = transCharToInt(databuffer, 28, 32);
return temp / 10.00;
}
The setup function runs once when the program initializes:
void setup()
{
The baud rate is set. This is used for serial communication:
Serial.begin(9600);
Then the LCD settings are declared, such as the constrast, default colour value, etc.:
u8g.setContrast(0); // Config the contrast to the best effect
u8g.setRot180();// rotate screen, if required
// set SPI backup if required
//u8g.setHardwareBackup(u8g_backup_avr_spi);
// assign default color value
if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
u8g.setColorIndex(255); // white
}
else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
u8g.setColorIndex(3); // max intensity
}
else if (
u8g.getMode() == U8G_MODE_BW )
{
u8g.setColorIndex(1); // pixel on
}
else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
u8g.setHiColorByRGB(255, 255, 255);
}
}
The loop function runs infinitely, or until the microcontroller is powered off or a component fails.
In this program the loop mainly handles printing data to the Arduino IDE using the Serial.print function. It also refreshes the LCD every half second (500 milliseconds):
void loop() {
getBuffer(); //Begin!
Serial.print("Wind Direction: ");
Serial.print(WindDirection());
Serial.println(" ");
Serial.print("Average Wind Speed (One Minute): ");
Serial.print(WindSpeedAverage());
Serial.println("m/s ");
Serial.print("Max Wind Speed (Five Minutes): ");
Serial.print(WindSpeedMax());
Serial.println("m/s");
Serial.print("Rain Fall (One Hour): ");
Serial.print(RainfallOneHour());
Serial.println("mm ");
Serial.print("Rain Fall (24 Hour): ");
Serial.print(RainfallOneDay());
Serial.println("mm");
Serial.print("Temperature: ");
Serial.print(Temperature());
Serial.println("C ");
Serial.print("Humidity: ");
Serial.print(Humidity());
Serial.println("% ");
Serial.print("Barometric Pressure: ");
Serial.print(BarPressure());
Serial.println("hPa");
Serial.println("");
Serial.println("");
//LCD output
u8g.firstPage();
do {
draw();
}
while ( u8g.nextPage() );
// rebuild the picture after some delay
delay(500);
}
This is the end of the code!
Conclusion
This tutorial has covered basic operation of the weather station kit. By using this kit and recording the data you can learn a lot about weather patterns and meteorology, but there is plenty of scope for improvement: how about adding a PM2.5 sensor to the array of sensors to monitor air pollution? How about setting up an RF receiver so that the weather station can transmit data wirelessly via the RF transmitter? How about adding a data logger module to the microcontroller so that you can log weather patterns over time?
Here are some Taobao links if you would like to try and implement your own RF receiver module for wireless transmission of data:APRS interfaces
https://item.taobao.com/item.htm?spm=a1z10.5-c.w40...
https://item.taobao.com/item.htm?spm=a1z10.5-c.w40...
If you have enjoyed this arduino weather station kit or if you have any suggestions for improvements, why not drop us a message on the DFRobot forum?http://www.dfrobot.com/forum/
Here you can showcase your projects and gain exposure to a worldwide community of engineers and hobbyists who can offer help and advice to improve your projects.
We hope you enjoyed this tutorial.
read original artical:https://www.dfrobot.com/blog-465.html