Meteo Data#
Weather data is essential for energy data analysis — outdoor temperature drives heating demand, solar radiation affects PV production, and humidity influences cooling loads. In Switzerland, two main open data sources provide free weather station data:
Provider |
Description |
Data Access |
Resolution |
|---|---|---|---|
MeteoSwiss |
Federal Office of Meteorology and Climatology, official network |
Station lookup + data download (open data) |
10 min, hourly, daily |
Agrometeo |
Agricultural weather network |
Station lookup + data download |
Hourly |
The pyedautils package provides a unified interface to both providers. This chapter shows how to:
Find the nearest weather station to any Swiss location
Download hourly weather data
Compare both station networks
Note
Both providers require an internet connection. All API calls go to public endpoints — no API key needed.
import pandas as pd
Station Lookup#
Both providers let you find the nearest weather station to a given location. The typical workflow is:
Convert a postal code (PLZ) to GPS coordinates
Find the nearest station that has the sensor you need
Helper: PLZ to Coordinates#
The geopy module converts any Swiss postal code to latitude/longitude and altitude.
from pyedautils.geopy import get_coordindates_ch_plz, get_altitude_lat_long
plz = 6048 # Horw
coord = get_coordindates_ch_plz(plz)
altitude = get_altitude_lat_long(coord[0], coord[1])
print(f"PLZ {plz}: lat={coord[0]:.4f}, lon={coord[1]:.4f}, altitude={altitude:.0f} m")
PLZ 6048: lat=47.0108, lon=8.3039, altitude=455 m
MeteoSwiss#
MeteoSwiss operates Switzerland’s official automatic weather stations. The find_nearest_station() function returns the station abbreviation (e.g. "LUZ" for Luzern) of the closest station that has the requested sensor and is within ±150 m altitude.
from pyedautils.weather.meteo_swiss import find_nearest_station as find_meteoswiss
station_ms = find_meteoswiss(coord[0], coord[1], altitude, sensor="temp")
print(f"Nearest MeteoSwiss station for temperature: {station_ms}")
Nearest MeteoSwiss station for temperature: LUZ
You can search for different sensor types: "temp", "globrad" (global radiation), "relhum" (relative humidity), "rain".
for sensor in ["temp", "globrad", "relhum", "rain"]:
station = find_meteoswiss(coord[0], coord[1], altitude, sensor=sensor)
print(f" {sensor:8s} → {station}")
temp → LUZ
globrad → LUZ
relhum → LUZ
rain → LUZ
Agrometeo#
Agrometeo is a Swiss agricultural weather network with a public API for station lookup and data download.
from pyedautils.weather.agroweather import find_nearest_station as find_agro
station_agro = find_agro(coord[0], coord[1], sensor="temp")
print(f"Nearest Agrometeo station for temperature: {station_agro}")
Nearest Agrometeo station for temperature: 239
Station Networks#
Both providers expose a function to list all available stations. This is useful for understanding coverage and available sensors.
from pyedautils.weather.meteo_swiss import get_current_station_data
stations_ms = get_current_station_data()
print(f"MeteoSwiss: {len(stations_ms)} stations")
stations_ms[["Abk.", "Station", "Stationshöhe m ü. M."]].head()
MeteoSwiss: 300 stations
| Abk. | Station | Stationshöhe m ü. M. | |
|---|---|---|---|
| 0 | TAE | Aadorf / Tänikon | 539.0 |
| 1 | ABE | Aarberg | 444.0 |
| 2 | COM | Acquarossa / Comprovasco | 575.0 |
| 3 | ABO | Adelboden | 1321.0 |
| 4 | AIE | Affoltern i. E. | 755.0 |
from pyedautils.weather.agroweather import get_station_data
stations_agro = get_station_data()
print(f"Agrometeo: {len(stations_agro)} stations")
stations_agro[["id", "name", "lat", "lon", "altitude"]].head()
Agrometeo: 218 stations
| id | name | lat | lon | altitude | |
|---|---|---|---|---|---|
| 0 | 189 | AESCH-BL | 47.466863 | 7.575196 | 382 |
| 1 | 360 | AGNO-Progetto ViSo-KS | 45.997000 | 8.893944 | 364 |
| 2 | 94 | AIGLE | 46.314537 | 6.979451 | 442 |
| 3 | 78 | AMBURNEX | 46.536925 | 6.215849 | 1321 |
| 4 | 79 | AMBURNEX-COMBE | 46.535419 | 6.218099 | 1285 |
Downloading Weather Data#
Both providers offer hourly weather data through public interfaces. MeteoSwiss publishes its measurements as open data; download_data() takes the station abbreviation and returns the data in UTC (or the time zone given with tz).
The examples use fixed stations and a fixed past week, so the results stay the same even if a new station opens closer to Horw. Here: MeteoSwiss station Luzern (LUZ) and Agrometeo station Meggen (ID 239).
from pyedautils.weather import meteo_swiss
df_luz = meteo_swiss.download_data("LUZ", "2026-06-01", "2026-06-07", tz="Europe/Zurich")
df_luz.head()
| temp | globrad | relhum | rain | |
|---|---|---|---|---|
| datetime | ||||
| 2026-06-01 00:00:00+02:00 | 16.1 | 0.0 | 91.4 | 0.0 |
| 2026-06-01 01:00:00+02:00 | 15.6 | 0.0 | 94.6 | 0.0 |
| 2026-06-01 02:00:00+02:00 | 15.2 | 0.0 | 95.8 | 0.0 |
| 2026-06-01 03:00:00+02:00 | 15.2 | 0.0 | 95.8 | 0.0 |
| 2026-06-01 04:00:00+02:00 | 15.5 | 0.0 | 93.7 | 0.0 |
Agrometeo can be queried in two ways:
By station ID — if you already know the station
By postal code (PLZ) — automatically finds the nearest station(s)
Download by Station ID#
Use download_data() when you know the station ID, e.g. from find_nearest_station() above or from get_station_data().
from pyedautils.weather.agroweather import download_data
df_agro = download_data(
station_id=239, # Meggen, nearest Agrometeo station to Horw
start_date="2026-06-01",
end_date="2026-06-07",
sensors=["temp", "globrad", "relhum", "rain"]
)
print(f"Shape: {df_agro.shape}")
print(f"Period: {df_agro.index.min()} to {df_agro.index.max()}")
df_agro.head()
Shape: (168, 4)
Period: 2026-06-01 00:00:00 to 2026-06-07 23:00:00
| temp | globrad | relhum | rain | |
|---|---|---|---|---|
| datetime | ||||
| 2026-06-01 00:00:00 | 17.1 | 0.1 | 84.0 | 0.1 |
| 2026-06-01 01:00:00 | 16.9 | 0.4 | 82.0 | 0.0 |
| 2026-06-01 02:00:00 | 16.9 | NaN | 83.0 | 0.0 |
| 2026-06-01 03:00:00 | 16.9 | NaN | 84.0 | 0.0 |
| 2026-06-01 04:00:00 | 17.2 | NaN | 83.0 | 0.0 |
Download by Postal Code#
The convenience function download_data_by_plz() handles the full workflow: PLZ → coordinates → nearest station(s) → download. If different sensors are closest to different stations, it automatically merges the results. Because the nearest station can change over time, use it for quick looks and pin the station ID for reproducible analyses:
from pyedautils.weather.agroweather import download_data_by_plz
df_plz = download_data_by_plz(plz=6048, start_date="2026-06-01", end_date="2026-06-07")
df_agro.describe()
| temp | globrad | relhum | rain | |
|---|---|---|---|---|
| count | 168.000000 | 125.000000 | 168.000000 | 168.000000 |
| mean | 17.729167 | 273.253600 | 67.273810 | 0.244643 |
| std | 3.573344 | 272.144148 | 12.144688 | 0.779664 |
| min | 11.400000 | 0.000000 | 44.000000 | 0.000000 |
| 25% | 15.100000 | 25.500000 | 56.000000 | 0.000000 |
| 50% | 17.250000 | 189.600000 | 69.000000 | 0.000000 |
| 75% | 20.375000 | 474.700000 | 77.250000 | 0.000000 |
| max | 25.100000 | 931.600000 | 85.000000 | 4.600000 |
Quick Visualization#
Let’s plot the downloaded data to verify it looks reasonable.
from pyedautils.plots import plot_timeseries
fig = plot_timeseries(
df_agro,
columns=["temp"],
title="Outdoor Temperature — Meggen (Agrometeo 239)",
ylab="Temperature [°C]",
)
fig.show()
fig = plot_timeseries(
df_agro,
columns=["globrad"],
title="Global Radiation — Meggen (Agrometeo 239)",
ylab="Radiation [W/m²]",
)
fig.show()
Available Sensors#
Both providers support the same four sensor types:
Sensor key |
Description |
Unit |
|---|---|---|
|
Air temperature |
°C |
|
Global radiation |
W/m² |
|
Relative humidity |
% |
|
Precipitation |
mm |
Which provider should I use?
Criteria |
MeteoSwiss |
Agrometeo |
|---|---|---|
Data download |
Yes, open data (10 min, hourly, daily, back to the start of the measurements) |
Yes, via API (hourly) |
Altitude matching |
Yes (±150 m filter) |
No |
Best for |
Official reference data, long time series |
A station close to rural sites |
Recommendation: Start with the nearest MeteoSwiss station at a similar altitude; use Agrometeo when it is much closer to your building.
Summary#
Task |
MeteoSwiss |
Agrometeo |
|---|---|---|
Find nearest station |
|
|
List all stations |
|
|
Download data by station |
|
|
Download data by PLZ |
|
|
PLZ → coordinates |
|
(built into |
Get altitude |
|
— |