Weather Station with BME280 and Wind Speed and Direction Sensors.
This Arduino project is a fully functional weather station that measures temperature, humidity, air pressure, wind speed, and wind direction. It also records high and low values for temperature and pressure over the past 24 hours. Two 20x4 LCD screens are used: one for temperature, humidity, and pressure, and the other for wind speed and wind direction.
Components and supplies
1
ZTS-3000-FSJT Wind Speed Sensor
1
Arduino UNO
1
BME280/BMP280
1
10kOhm potentiometer
1
Breadboard - 840 contacts
1
40 colored male-female jumper wires
1
PR-3000-FXJT Wind Direction Sensor
2
20x4 LCD
1
12V adapter
Tools and machines
1
Arduino IDE
Apps and platforms
1
Arduino IDE 2.0 (beta)
Project description
Code
Whether Stations
cpp
1#include <LiquidCrystal.h> // for LCD 2#include <Wire.h> 3#include <Adafruit_Sensor.h> 4#include <Adafruit_BME280.h> 5#include <string.h> 6 7// Temperature sensor LCD pins 8#define LCD_RS_PIN 2 9#define LCD_E_PIN 3 10#define LCD_D4_PIN 4 11#define LCD_D5_PIN 6 12#define LCD_D6_PIN 7 13#define LCD_D7_PIN 8 14 15// Wind data LCD pins 16#define LCD_RS_PIN_wind 13 17#define LCD_E_PIN_wind 11 18#define LCD_D4_PIN_wind 12 19#define LCD_D5_PIN_wind 10 20#define LCD_D6_PIN_wind 9 21#define LCD_D7_PIN_wind A3 22 23// Wind sensors pins 24#define windPin A0 25#define dirPin A1 26 27 28unsigned long previous_time_temp_check = 0; 29unsigned long previous_time_wind_check = 0; 30 31 32unsigned int temp_array_count = 0; 33char temp_array[96]; 34 35unsigned int pres_array_count = 0; 36int pres_array[96]; 37 38unsigned int wind_speed_array_count = 0; 39char wind_speed_array[300]; 40 41unsigned int wind_direction_array_count = 0; 42int wind_direction_array[60]; 43 44// This is the amount that we will subtract from the voltage 45float voltage_offset = 0.14; 46 47 48// Create BME280 object for I2C 49Adafruit_BME280 bme; 50 51// Create LCD object 52LiquidCrystal lcd(LCD_RS_PIN, LCD_E_PIN, LCD_D4_PIN, LCD_D5_PIN, LCD_D6_PIN, LCD_D7_PIN); 53LiquidCrystal lcd_wind(LCD_RS_PIN_wind, LCD_E_PIN_wind, LCD_D4_PIN_wind, LCD_D5_PIN_wind, LCD_D6_PIN_wind, LCD_D7_PIN_wind); 54 55 56 57void setup() { 58 Serial.begin(9600); 59 60 lcd.begin(20, 4); 61 lcd_wind.begin(20, 4); 62 63 64 Serial.println(F("BME280 I2C Test")); 65 66// Filling the array with values that are less than what could be in the temp. 67// This is so when the computer calculates the high and low it won’t use garbage 68// values that are automatically put into the array. That’s why I used -100. 69 for(int i = 0; i < 96; i++){ 70 temp_array[i] = -50; 71 } 72 73 // same as for the temp array 74 for(int i = 0; i < 96; i++){ 75 pres_array[i] = 100; 76 } 77 78 for(int i = 0; i < 300; i++){ 79 wind_speed_array[i] = 0; 80 } 81 82 // test to initialize the sensor 83 if (!bme.begin(0x76)) { // Use 0x76 (most modules) or 0x77 if needed 84 Serial.println(F("Could not find a valid BME280 sensor, check wiring!")); 85 while (1); // Stop here 86 } 87 88 // initial setup 89 lcd.setCursor(0, 0); 90 lcd.print(F("The temperature will show in 30 seconds")); 91 delay(30000); // to let the sensor stabilize before reading 92//---------------------------------------------------------------------------------------------------------------------- 93 int temp = bme.readTemperature(); 94 lcd.setCursor(0, 0); 95 lcd.print(F(" ")); 96 lcd.setCursor(0, 0); 97 lcd.print(F("Temp = ")); 98 lcd.print(temp); 99 lcd.print((char)223); 100//-------------------------------------------------------------------------------------------------------------------------- 101 float stationPressure = bme.readPressure() / 100.0; // BME280 gives Pa, convert to hPa 102 int altitude = 410; // meters 103 // I'm using int because I don't want the decimal place. 104 unsigned int seaLevelPressure = stationPressure * pow((1 - (altitude / 44330.0)), -5.255); 105 lcd.setCursor(0, 1); 106 lcd.print(F(" ")); 107 lcd.setCursor(0, 1); 108 lcd.print(F("Pres = ")); 109 lcd.print(seaLevelPressure); 110 lcd.print(F(" hPa")); 111 112//------------------------------------------------------------------------------------------------------------------------- 113 114 unsigned int humidity = bme.readHumidity(); 115 lcd.setCursor(0, 2); 116 lcd.print(F(" ")); 117 lcd.setCursor(0, 2); 118 lcd.print(F("Humidity = ")); 119 lcd.print(humidity); 120 lcd.print(F("%")); 121 122} 123 124void loop() { 125 unsigned long time_now = millis(); // Get the current time 126 127 if(time_now - previous_time_wind_check > 1000){ 128 129 // ===== Wind speed ===== 130 int analog_from_speed = analogRead(windPin); // 0–1023 131 float voltage_from_speed = analog_from_speed / 204.6 - voltage_offset; // 1023/5 ≈ 204.6 for each volt 132 // voltage_offset is an amount you want to subtract from the raw volts, because the sensor is not 0 when it is 133 // not moving and you want it to be 0. To fix that you use the offset. 134 135 int wind_kmph = voltage_from_speed * 12 * 3.6; // 5V -> 60 m/s => 12 m/s per volt then * 3.6 -> km/h 136 137 // Puts the wind speed value in the right array slot 138 int array_wind_place = wind_speed_array_count % 300; 139 wind_speed_array[array_wind_place] = wind_kmph; 140 wind_speed_array_count++; 141 142 // // this is only for testing the array place 143 // Serial.println("array place wind"); 144 // Serial.println(array_wind_place); 145 146 // This will only be accurate 5 minutes after start 147 148 int wind_average = 0; 149 150 for(int i = 0; i < 300; i++){ 151 wind_average += wind_speed_array[i]; 152 } 153 wind_average /= 300; 154 155 // //for testing 156 // Serial.println("wind average"); 157 // Serial.println(wind_average); 158 159 if(wind_kmph < 5){ 160 lcd_wind.setCursor(0, 0); 161 lcd_wind.print(F(" ")); 162 lcd_wind.setCursor(0, 0); 163 lcd_wind.print(F("Wind is light")); 164 }else{ 165 lcd_wind.setCursor(0, 0); 166 lcd_wind.print(F(" ")); 167 lcd_wind.setCursor(0, 0); 168 lcd_wind.print(F("Wind Speed: ")); 169 lcd_wind.print(wind_kmph); 170 lcd_wind.print(F("km")); 171 } 172 lcd_wind.setCursor(0, 1); 173 lcd_wind.print(F(" ")); 174 lcd_wind.setCursor(0, 1); 175 lcd_wind.print(F("5M wind avg: ")); 176 lcd_wind.print(wind_average); 177 lcd_wind.print(F("km")); 178 179 lcd_wind.setCursor(0, 3); 180 lcd_wind.print(F("V:")); 181 lcd_wind.print(voltage_from_speed, 2); 182 183 184 // Print results on serial for testing 185 // Serial.print("Raw ADC: "); 186 // Serial.print(rawSpeed); 187 // Serial.print(" | Voltage: "); 188 // Serial.print(voltSpeed, 2); 189 //Serial.print(F("Wind Speed: ")); 190 // Serial.print(windMs, 2); 191 // Serial.print(" m/s ("); 192 //Serial.print(wind_kmph); 193 //Serial.print(F(" km/h)")); 194 195 196 // ===== Wind direction ===== 197 int analog_from_direction = analogRead(dirPin); // 0–1023 198 float volts_from_direction = analog_from_direction / 204.6; 199 int wind_direction = (volts_from_direction / 5.0) * 360.0; 200 201 int North = 0; 202 int Northeast = 0; 203 int East = 0; 204 int Southeast = 0; 205 int South = 0; 206 int Southwest = 0; 207 int West = 0; 208 int Northwest = 0; 209 210 int array_place_direction = wind_direction_array_count % 60; 211 wind_direction_array[array_place_direction] = wind_direction; 212 wind_direction_array_count++; 213 214 for(int i = 0; i < 60; i++){ 215 int test = wind_direction_array[i]; 216 if(test > 341){ 217 North++; 218 } 219 else if(test < 30){ 220 Northeast++; 221 } 222 else if(test < 70){ 223 East++; 224 } 225 else if(test < 130){ 226 Southeast++; 227 } 228 else if(test < 180){ 229 South++; 230 } 231 else if(test < 230){ 232 Southwest++; 233 } 234 else if(test < 280){ 235 West++; 236 } 237 else if(test < 340){ 238 Northwest++; 239 } 240 } 241 242char direction[3] = "--"; // 2 letters max + null terminator 243 244// Checking which is the biggest. 245if (North > Northeast && North > East && North > Southeast && North > South && North > Southwest && North > West && North > Northwest) { 246 strcpy(direction, "N"); 247} 248else if (Northeast > North && Northeast > East && Northeast > Southeast && Northeast > South && Northeast > Southwest && Northeast > West && Northeast > Northwest) { 249 strcpy(direction, "NE"); 250} 251else if (East > North && East > Northeast && East > Southeast && East > South && East > Southwest && East > West && East > Northwest) { 252 strcpy(direction, "E"); 253} 254else if (Southeast > North && Southeast > Northeast && Southeast > East && Southeast > South && Southeast > Southwest && Southeast > West && Southeast > Northwest) { 255 strcpy(direction, "SE"); 256} 257else if (South > North && South > Northeast && South > East && South > Southeast && South > Southwest && South > West && South > Northwest) { 258 strcpy(direction, "S"); 259} 260else if (Southwest > North && Southwest > Northeast && Southwest > East && Southwest > Southeast && Southwest > South && Southwest > West && Southwest > Northwest) { 261 strcpy(direction, "SW"); 262} 263else if (West > North && West > Northeast && West > East && West > Southeast && West > South && West > Southwest && West > Northwest) { 264 strcpy(direction, "W"); 265} 266else if (Northwest > North && Northwest > Northeast && Northwest > East && Northwest > Southeast && Northwest > South && Northwest > Southwest && Northwest > West) { 267 strcpy(direction, "NW"); 268} 269 270 lcd_wind.setCursor(0, 2); 271 lcd_wind.print(F(" ")); 272 lcd_wind.setCursor(0, 2); 273 lcd_wind.print(F("wind direction: ")); 274 lcd_wind.print(direction); 275 276 277 // // This is just for testing 278 // Serial.print(" || Dir Raw: "); 279 // Serial.print(rawDir); 280 // Serial.print(" | Dir Volt: "); 281 // Serial.print(voltDir, 2); 282 // Serial.print(F("Wind Direction: ")); 283 // Serial.print(wind_direction); 284 // Serial.println(F(" deg")); 285 286 287 previous_time_wind_check += 1000; 288 } 289 290 291 if (time_now - previous_time_temp_check > 900000){ 292 293 294// ------------------------------------------------------------------------------------------------------------------------ 295 int temp = bme.readTemperature(); 296 297 lcd.setCursor(0, 0); 298 lcd.print(F(" ")); 299 lcd.setCursor(0, 0); 300 lcd.print(F("Temp = ")); 301 lcd.print(temp); 302 lcd.print((char)223); 303 304 // // Testing to see that the count works in serial 305 // Serial.println(F("temp array count")); 306 // Serial.println(temp_array_count); 307 308 // places the temp value in the right array slot 309 int array_place = temp_array_count % 96; 310 temp_array[array_place] = temp; 311 temp_array_count++; 312 313 // // this is only for testing the array place 314 // Serial.println(F("array place temp")); 315 // Serial.println(array_place); 316 317 // This whole chunk is for the high and low function 318 int high_temp = temp_array[0]; 319 int low_temp = temp_array[0]; 320 321 for(int i = 0; i < 96; i++){ 322 323 if(temp_array[i] < low_temp && temp_array[i] != -50){ 324 low_temp = temp_array[i]; 325 } 326 else if(temp_array[i] > high_temp){ 327 high_temp = temp_array[i]; 328 } 329 } 330 331 lcd.setCursor(12, 0); 332 lcd.print(F("H")); 333 lcd.print(high_temp); 334 lcd.print(F(" L")); 335 lcd.print(low_temp); 336 337//-------------------------------------------------------------------------------------------------------------------------- 338 339 // This gets the pressure and turns the station pressure into sea level pressure 340 float station_pressure = bme.readPressure() / 100.0; // BME280 gives Pa, convert to hPa 341 int altitude = 410; // meters 342 // I'm using int because I don't want the decimal place. 343 unsigned int sea_level_pressure = station_pressure * pow((1 - (altitude / 44330.0)), -5.255); 344 345 lcd.setCursor(0, 1); 346 lcd.print(F("Pres = ")); 347 lcd.print(sea_level_pressure); 348 lcd.print(F(" hPa")); 349 350 // Array placement 351 unsigned char array_place_pres = pres_array_count % 96; 352 pres_array[array_place_pres] = sea_level_pressure; 353 pres_array_count++; 354 355 // // This is just for testing 356 // Serial.println(F("pressure array place")); 357 // Serial.println(pres_array_count); 358 // Serial.println(F("array place presser")); 359 // Serial.println(F("array place pressure")); 360 361 362 unsigned int high_pres = pres_array[0]; 363 unsigned int low_pres = pres_array[0]; 364 365 for(int i = 0; i < 96; i++){ 366 if(pres_array[i] < low_pres && pres_array[i] != 100){ 367 low_pres = pres_array[i]; 368 } 369 else if(pres_array[i] > high_pres){ 370 high_pres = pres_array[i]; 371 } 372 } 373 374 lcd.setCursor(0, 2); 375 lcd.print(F(" ")); 376 lcd.setCursor(0, 2); 377 lcd.print(F("HP")); 378 lcd.print(high_pres); 379 lcd.print(F(" LP")); 380 lcd.print(low_pres); 381 382//------------------------------------------------------------------------------------------------------------------------ 383 // humidity check 384 // the int is so there should be no decimal 385 int humidity = bme.readHumidity(); 386 lcd.setCursor(0, 3); 387 lcd.print(F("Humidity = ")); 388 lcd.print(humidity); 389 lcd.print(F("%")); 390 391// ----------------------------------------------------------------------------------------------------------------------- 392 previous_time_temp_check += 900000; 393 } 394} 395 396 397 // lcd.setCursor(0, 3); 398 // lcd.print("Altitude = "); 399 // lcd.print(bme.readAltitude(SEALEVELPRESSURE_HPA)); 400 // lcd.print(" m");
Comments
Only logged in users can leave comments