Accessing Met Office DataHub forecasts from a Raspberry Pi
Introduction
As the Met Office is discontinuing their DataPoint service in late 2025, we’ve recently been converting our weather forecasts page to use DataHub, the replacement service. This provides forecasts in GeoJSON format, and gives much more information and better global coverage than DataPoint did. Here we’ll describe how to access the forecasts from a Raspberry Pi, using Python.
Registering
Like DataPoint, DataHub is mostly free for non-commercial and non-bulk usage. Various types of data are available, and we’re using the global spot 3-hour site-specific forecast. This is free providing you access it fewer than 360 times per day.
DataHub requires you to register, whereupon you’ll be given an api-key. This is a string of characters, and is very long! Over 1600 characters, in our case. Store this somewhere secure and safe.
Getting some data
The Met Office provides sample Python code to access the forecasts. This works without modification on a Raspberry Pi.
First grab the ss_download.py file and save it in a new directory. From this directory’s filer window, click on “Tools>Open Current Folder in Terminal”.
In the terminal window, type this:
python ss_download.py -t three-hourly -x -1.5387 -y 53.8230 -k api-key
You’ll need to replace api-key with your key, of course! Copy and paste it (using the terminal’s “Edit” menu entry — you can’t use Ctrl-V).
This should output the data for Potternewton in Leeds, UK: the predicted weather conditions every three hours for the next seven days, starting with “{”type”:”FeatureCollection”, …”. The -x and -y values are the longitude/latitude coordinates; if you’re looking up the co-ordinates for somewhere else, they should be decimal values (not degrees and minutes), and longitude “W” values are negative.
To make life easier, modify the code so that your api-key is the default (remembering that including this type of data is less secure! Don’t let this code be publicly available). Find the following code fragment, about line 95:
parser.add_argument( ”-k”, ”–apikey”, action=”store”, dest=”apikey”, default=”", help=”REQUIRED: Your WDH API Credentials.”
Copy and paste your api-key into the ‘default=”my-api-key“,’ string, and save the file. Now you don’t need to include it when you get a forecast.
You can do similar things with the “parser.add_argument( -t …” parameter, changing the default from “hourly” to “three-hourly”, and the latitude/longitude values.
Decoding the data
The output thus far isn’t very readable — just an enormously long one-line string printed in the terminal window. We can tidy things up by converting the JSON data into Python-usable form with the json.loads function. Add the following line in the import section at the top of the file:
import json
And at around line 48, comment out the print(req.text) line, and add these:
#print(req.text) jdata = json.loads(req.text) jpretty = json.dumps(jdata, indent=2) print(jpretty)
Remember that Python indenting is syntactically important, and this file uses spaces, not tabs.
Save, and run again. The output is much clearer:
{
”type”: ”FeatureCollection”,
”features”: [
{
”geometry”: {
”type”: ”Point”,
”coordinates”: [
-1.5428000000000002,
53.8209,
100.0
]
},
”type”: ”Feature”,
”properties”: {
”requestPointDistance”: 356.3973,
”timeSeries”: [
{
”feelsLikeTemp”: 15.55,
”probOfRain”: 5,
”minScreenAirTemp”: 11.31,
”max10mWindGust”: 3.79,
”probOfSnow”: 0,
”probOfPrecipitation”: 5,
”screenRelativeHumidity”: 73.64,
”windDirectionFrom10m”: 85,
”windGustSpeed10m”: 3.6,
”probOfHeavySnow”: 0,
”visibility”: 18496,
”totalPrecipAmount”: 0,
”maxScreenAirTemp”: 16.3,
”probOfHeavyRain”: 0,
”mslp”: 102680,
”probOfHail”: 0,
”totalSnowAmount”: 0,
”significantWeatherCode”: 7,
”windSpeed10m”: 2.73,
”probOfSferics”: 0,
”time”: ”2025-08-17T09:00Z”,
”uvIndex”: 3
}, … etc
Much abridged, of course. You can see that the important data is in the “timeseries” sequence, with an entry for each time period consisting of various weather parameter values. (In Python terms, the timeseries is an array of dictionaries.) If you look at the bottom of the output, each parameter has an entry giving a fuller description and any units used. So we learn, for example, that the “max10mWindGust” parameter means “Maximum 10m Wind Gust Speed Over Previous Three Hours”, and is reported in “m/sec”.
Displaying the forecast
Every time you run this file, you’re using up one of your 360 daily accesses. So while you’re experimenting, it’s better to save the data and work on the saved file. Remove the ‘import json’ line, and replace the three added lines with:
#print(req.text) with open(’path-to-folder/myforecast.json’, ’w') as f: f.write(req.text)
…replacing path-to-folder with your created folder path.
Now create a new file in your favoured editor, and save it as showforecast.py in the folder you created:
# showforecast.py – display a forecast import json from datetime import datetime infile = ’path-to-folder/myforecast.json’ with open(infile, mode=”r”) as read_file: jdata = json.load(read_file) print(json.dumps(jdata, indent=2))
Again replacing path-to-folder.
Important: Run this with:
python3 showforecast.py
…as we’ll be using a Python 3 facility to print things. This should give the same output as previously.
We can access the timeseries as follows:
timeseries=jdata[”features”][0][”properties”][”timeSeries”]
And as the timeseries is an array, we can easily loop through every entry like this:
for tdata in timeseries:
So now we’ll access a couple of the parameters. First we need the entry’s date and time. The variable json_date_format:
json_date_format=”%Y-%m-%dT%H:%MZ”
…is used to convert the entry’s time string to a Python date/time object (using the imported datetime library):
entrytime=datetime.strptime(tdata[”time”],json_date_format)
You can see that accessing parameters is easy — use tdata[”parameter_name”].
And now we can output the date/time nicely with:
print(entrytime.strftime(’Forecast for %H:%M on %a %-d %b %Y:’))
Get some temperature data:
tmax = tdata[”maxScreenAirTemp”]; tmin = tdata[”minScreenAirTemp”]
…and display it:
print(F’ Min/max temperature (deg C): {tmin:.1f} / {tmax:.1f}’)
After adding in another couple of values, the full program looks like this (replacing the file path as above):
# showforecast.py
# Display a forecast
import json
from datetime import datetime
infile = ’path-to-folder/myforecast.json’
with open(infile, mode=”r”) as read_file:
jdata = json.load(read_file)
json_date_format=”%Y-%m-%dT%H:%MZ”
timeseries=jdata[”features”][0][”properties”][”timeSeries”]
for tdata in timeseries:
entrytime=datetime.strptime(tdata[”time”],json_date_format)
print(entrytime.strftime(’Forecast for %H:%M on %a %-d %b %Y:’))
tmax = tdata[”maxScreenAirTemp”]; tmin = tdata[”minScreenAirTemp”]
print(F’ Min/max temperature (deg C): {tmin:.1f} / {tmax:.1f}’)
rain = tdata[”probOfPrecipitation”]
print(F’ Probability of rain: {rain}%’)
wind = round(tdata[”windSpeed10m”] * 2.237)
print(F’ Average wind speed: {wind}mph’)
When you’re printing things, Python 3 introduced the print(F’Item {value}’) facility, where you can include values in {} braces and also format them, as in the temperatures. The wind value is converted from m/sec to mph.
Running
python3 showforecast.py
should get some output like this:
Forecast for 12:00 on Sun 17 Aug 2025: Min/max temperature (deg C): 16.3 / 18.3 Probability of rain: 8% Average wind speed: 7mph Forecast for 15:00 on Sun 17 Aug 2025: Min/max temperature (deg C): 18.3 / 22.3 Probability of rain: 4% Average wind speed: 7mph Forecast for 18:00 on Sun 17 Aug 2025: Min/max temperature (deg C): 21.5 / 23.1 Probability of rain: 0% Average wind speed: 10mph Forecast for 21:00 on Sun 17 Aug 2025: Min/max temperature (deg C): 16.7 / 21.5 Probability of rain: 4% Average wind speed: 8mph …etc
This should be enough to get you started. Other parameters of interest include:
- “significantWeatherCode”: an integer in the range 0..30 giving the weather type — details here
- “mslp”: means “mean sea-level pressure”
- “probOfSferics”: probability of lightning strikes
- “windDirectionFrom10m”: this is in degrees. To convert to a cardinal point, use the value of the expression
round(tdata[”windDirectionFrom10m”]/22.5) % 16
to index into an array of directions:
[’N',’NNE’,'NE’, etc]
For our site, we grab forecasts for a few different locations every hour, generate web page inserts for each and upload them, all automatically scheduled using crontab. It’s all done on a Raspberry Pi 400 running Raspbian Buster.
Add comment
Fill out the form below to add your own comments