As you know, whatever you do under the Raspberry Pi, you’ll end up with either a media player or a weather station. This fate befell me as well, when, after another rainstorm, the weather station sensor was flooded, it was time to either buy a new one, or do it myself.
From the weather station needed the following functions:
- temperature display
- atmospheric pressure graph display
- rain forecast
- time synchronization (in case of a usual meteorological station, according to DCF77, if there are hours on the device, they should show the exact time)
From the purchased ones, by the combination of “design-price-functions”, neither one liked - either there is no one, or another, or it is too cumbersome and expensive. As a result, it was decided to use the Raspberry Pi with a TFT-screen, and make the functions that are needed.
')
It turned out like this:

Details of the implementation and the finished project under the cut.
Getting weather data
The first thing you had to decide on was getting the weather data. There are 2 options, either use your sensors, or take the weather from the Internet. The first is more interesting, but there are several "but":
- It’s easy to make a sensor “anyhow”, but it’s good to make the sensor work for example for a year with one set of batteries, the task is not so trivial. Of course, there are now low-consuming processes and radio modules, but it would be too lazy to spend on this month.
- It is necessary to bother with the case, moisture protection and other trifles (I don’t have a 3d printer).
- The balcony faces the sunny side, so that the error in measuring the temperature in the first half of the day would be too big.
An alternative option was to buy a ready weather module with sensors for the Raspberry Pi.
Alas, the search showed that there are only 2 options available:
-
Raspberry Pi sense hat
The board has a thermometer, a barometer, a humidity sensor, a gyroscope and an accelerometer “on board” - but what the developers thought when putting such a “screen” of 8x8 LEDs is unclear - nothing intelligible can be drawn on it. I wish the developers of this module all my life UI to write under the 8x8 matrix :)
-
Raspberry Pi weather hat
Nothing but LEDs are not here at all.
In general, oddly enough, but no one did a normal finished shield for a weather station with a good screen and a good set of sensors. Crowsourcers, ay - the market niche disappears :)
As a result, we do not steam and do it in a simple way - we take the weather from the Internet and output it to a regular TFT. As Google suggested, the most advanced API is now
https://openweathermap.org/api , and we will use it.
In the comments there was a question about the accuracy of Internet data. As can be seen in the code below, a request for
current (current weather data) rather than predicted data is used to display temperature and atmospheric pressure. Their accuracy can be considered quite sufficient for domestic purposes, moreover, most likely it is even higher than the accuracy of an outdoor thermometer / sensor located outside a window or on a balcony.
check in
To retrieve weather data with openweathermap, you need a key, you can get it for free by registering on the above site. The key looks something like this “dadef5765xxxxxxxxxxxxxx6dc8”. Most of the functions are available for free, we will not need paid APIs. For free features there is a limit of
60 requests per minute , that's enough for us.
Reading data
Reading data is quite simple thanks to the pyowm library.
Getting the weather at the moment (Python):
import pyowm owm = pyowm.OWM(apiKey) observation = owm.weather_at_coords(lat, lon) w = observation.get_weather() dtRef = w.get_reference_time(timeformat='date') t = w.get_temperature('celsius') temperatureVal = int(t['temp']) p = w.get_pressure() pVal = int(p['press'])
Getting a weather forecast for precipitation:
fc = owm.three_hours_forecast_at_coords(lat, lon) rain = fc.will_have_rain() snow = fc.will_have_snow() rains = fc.when_rain()
At the output we get an array of data with a list of rains and their intensity. Despite the name of the function three_hours_forecast_at_coords, the rains are registered for 2-3 days ahead.
You can use GET requests directly, for
example . This can be useful, for example, when porting code to MicroPython under ESP.
Getting user coordinates
As can be seen above, latitude and longitude are needed to obtain data. Getting the coordinates is also quite simple, and is done in 3 lines of code:
import geocoder g = geocoder.ip('me') lat = g.latlng[0] lon = g.latlng[1]
Ui
Actually, the most difficult part. The Raspberry Pi uses Adafruit's TFT display, which supports the ILI9340 command system. Libraries under it are easy to find, but debugging the code on the Raspberry Pi is not very convenient. As a result, it was decided to write a high-level set of controls, which needed only 3 - images, text and lines. When launched on the Raspberry Pi, the control will draw itself on the TFT, when launched on the desktop, the built-in Python library tkinter will be used. As a result, the code will work everywhere - on both the Raspberry Pi, and on Windows, and on OSX.
The code for one control looks like this:
class UIImage: def __init__(self, image = None, x = 0, y = 0, cId = 0): self.x = x self.y = y self.width = 0 self.height = 0 self.cId = cId self.tkID = None self.tftImage = None self.tkImage = None self.useTk = utils.isRaspberryPi() is False if image is not None: self.setImage(image) def setImage(self, image): width, height = image.size if self.useTk: self.tkImage = ImageTk.PhotoImage(image) self.tftImage = image self.width = width self.height = height def draw(self, canvas = None, tft = None): if tft != None: tft.draw_img(self.tftImage, self.x, self.y, self.width, self.height) elif canvas != None and self.tkImage != None: if self.tkID == None or len(canvas.find_withtag(self.tkID)) == 0: self.tkID = canvas.create_image(self.x, self.y, image=self.tkImage , anchor=tkinter.NW) else: canvas.itemconfigure(self.tkID, image=self.tkImage)
The “FakeTFT” class creates a normal program window:
class FakeTFT: def __init__(self): self.tkRoot = tkinter.Tk() self.tkRoot.geometry("500x300") self.screenFrame = tkinter.Frame(self.tkRoot, width=330, height=250, bg="lightgray") self.screenFrame.place(x=250 - 330 / 2, y=5) self.tkScreenCanvas = tkinter.Canvas(self.tkRoot, bg = 'white', width = 320, height = 240, highlightthickness=0) self.tkScreenCanvas.focus_set() self.tkScreenCanvas.place(x=250 - 320 / 2, y=10) self.controls = [] def draw(self): for c in self.controls: c.draw(self.tkScreenCanvas)
The “LCDTFT” class uses the “real” display (code fragment):
class LCDTFT: def __init__(self, spidev, dc_pin, rst_pin=0, led_pin=0, spi_speed=16000000):
At initialization, the necessary display is automatically selected, depending on where the program is launched:
def lcdInit(): if utils.isRaspberryPi(): GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) DC = 25 LED = 18 RST = 0 return LCDTFT(spidev.SpiDev(), DC, RST, LED) else: return FakeTFT()
All this allows you to completely abstract from the "iron", and write code like this:
self.labelPressure = libTFT.UILabel("Pressure", 18,126, textColor=self.tft.BLACK, backColor=self.tft.WHITE, fontS = 7) self.tft.controls.append(self.labelPressure) self.labelRain = libTFT.UILabel("Rain", 270,126, textColor=self.tft.BLUE, backColor=self.tft.WHITE, fontS = 7) self.tft.controls.append(self.labelRain)
Actually, the UI looks like this:

The screen displays the current temperature, the graph of atmospheric pressure for today (in the next version a temperature graph will be added), also in the case of a rain forecast, its time is marked on the graph with a vertical blue line (there are no rains in this picture). It also displays the time of the last data update and the IP address if you need to connect to the device.
Those who want to get acquainted with the source in more detail, can look at it
on guthub .
Installation on Raspberry Pi
For those who do not want to bother described above, a short installation guide under the spoiler.
Instruction- Download source from github:
git clone
github.com/dmitryelj/RPi-Weather-Station.git- If Python3 is not installed, set:
sudo apt-get install python3
- We put additional libraries (they are needed to work with the display):
sudo pip3 install numpy pillow spidev
- Add to autorun (sudo nano /etc/rc.local)
python3 /home/pi/Documents/RPi-Weather-Station/weather.py &
- We try to launch
python3 weather.py
If everything works, then reboot (sudo reboot) and use.
In terms of adding something else useful, for example, displaying a cloud map, there is an API on openweathermap for this.
To be continued.