With the growing pile of unused SBCs and various sensors on my workbench, I pondered about how I could put some of these to good use. And then it hit me:"Aha! I will make a Raspberry Pi based weather station! Surely no one has done that before!"
This idea has been quite literally beaten to death.
Anyways, the main idea here is that I wanted my weather station to first take a temperature, pressure and humidity reading, using a BME280 sensor and then send that off to a webserver. This weather data would then be accessible to anyone who wishes to view it! Pretty neato if I do say so ( ▀ ͜͞ʖ▀).
Thankfully (or unfortunately, depends what kind of person you are), most of the work in this project relies on code to make it work. Therefore, the wiring is extremely straight forward. Please see below for a very simple wiring diagram.
First and foremost, we need to install some boilerplate code and libraries so that our Raspberry Pi can properly talk to the
BME280. Instead of simply regurgitating the very clear instructions that have already been created, you can head over to this Github page to find the installation instructions. Do not forget to enable I2C on your Pi
or you will not be able to use the BME280 at all!. Once the library is installed, you should be able to locate some example code for the BME280 at
[wherever_you_installed_your_library]/bme280-python/examples/, specifically, the all-values.py file. In order to get up and
running with
the sensor as fast as possible, I found that it was very convienient to simply modify this file instead of starting from scratch (A.K.A I'm lazy
¯\_(ツ)_/¯). To give you a quick look at what the all-values.py file looks like, here it is below.
1. #!/usr/bin/env python
2.
3. import time
4.
5. from smbus2 import SMBus
6.
7. from bme280 import BME280
8.
9. print(
10. """all-values.py - Read temperature, pressure, and humidity
11.
12. Press Ctrl+C to exit!
13.
14. """
15. )
16.
17. # Initialise the BME280
18. bus = SMBus(1)
19. bme280 = BME280(i2c_dev=bus)
20.
21. while True:
22. temperature = bme280.get_temperature()
23. pressure = bme280.get_pressure()
24. humidity = bme280.get_humidity()
25. print(f"{temperature:05.2f}°C {pressure:05.2f}hPa {humidity:05.2f}%")
26. time.sleep(1)
This is now an excellent time to run this example code and see if you are able to get any values! If everything works, you should see a temperature, pressure and humidity reading once every second. If Murphy's Law has a firm grasp on you, there was most likely an issue with the Python virtual environment somewhere or I2C was not enabled on the Pi.
Assuming everything is working now, we can start adding our own code to this example code to make it a little more interesting. Let's first take a look at the changes that I made an I will explain them as we move through them.
1. #!/usr/bin/env python
2.
3. import time
4.
5. import requests
6.
7. import json
8.
9. from smbus2 import SMBus
10.
11. from bme280 import BME280
12.
13. print(
14. """all-values.py - Read temperature, pressure, and humidity
15.
16. Press Ctrl+C to exit!
17.
18. """
19. )
20.
21. # Initialise the BME280
22. bus = SMBus(1)
23. bme280 = BME280(i2c_dev=bus)
24.
25. # initialize weather data dict and weather data averages
26. data = {"temperature": 0.0, "pressure": 0.0, "humidity": 0.0, "time": 0}
27. temperature_avg = 0.0
28. pressure_avg = 0.0
29. humidity_avg = 0.0
30.
31. # get 20 readings for each parameter then calculate their average
32. # save average to data dict
33. for i in range(1, 21):
34. temperature = bme280.get_temperature()
35. pressure = bme280.get_pressure()
36. humidity = bme280.get_humidity()
37.
38. temperature_avg += temperature
39. pressure_avg += pressure
40. humidity_avg += humidity
41.
42. time.sleep(1)
43.
44. temperature_final = temperature_avg / 20.0
45. pressure_final = pressure_avg / 20.0
46. humidity_final = humidity_avg / 20.0
47. unix_time = time.time()
48.
49. data["temperature"] = temperature_final
50. data["pressure"] = pressure_final
51. data["humidity"] = humidity_final
52. data["time"] = unix_time
53.
54. print(f"{temperature_final:05.2f}C, {pressure_final:05.2f}hPa, {humidity_final:05.2f}%, {unix_time:05.2f}s")
55.
56. # POST JSON data dict to windsorweather.xyz
57. response = requests.post(url="https://windsorweather.xyz/receiveData.php", json=data)
58. print(f"Status code for POST request: {response.status_code}")
Starting on lines 25-29, we initialize a new array which will contain our BME280 sensor readings as well as our averages for temperature, pressure and humidity which we will calculate later. On lines
31-46, we take 20 readings from the BME280 for all three metrics (temperature, pressure and humidity), then calculate their averages. The reason for this averaging is that the BME280 may not always give
us an accurate reading, so by averaging 20 readings, we have a sort of buffer that can be used to avoid these errors (that's the idea anyways). From lines 47-58, we simply store all of our readings
(including a unix time value) into our data dictionary and use the Python Request library (super cool library with crystal clear documentation,
definitely check it out) to create a POST request to our weather data server, speicifically the receiveData.php page (more on this later).
Now that's a wrap for the client-side code! All that is left to do now is work out the server-side code to receive the data from the Pi, parse it and then display it on a webpage. For the sake of this demo (and because I am lazy ( ゚ヮ゚)), I am demonstrating code that is slightly above the bare minimum to give you an idea of what this would look like.