open-meteo
Integrate Open-Meteo Weather Forecast, Air Quality, and Geocoding APIs: query design, variable selection, timezone/timeformat/units, multi-location batching, and robust error handling. Keywords: Open-Meteo, /v1/forecast, /v1/air-quality, geocoding-api, hourly, daily, current, timezone=auto, timeformat=unixtime, models, WMO weather_code, CAMS, GeoNames, httpx, FastAPI, pytest.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install itechmeat-llm-code-open-meteo
Repository
Skill path: skills/open-meteo
Integrate Open-Meteo Weather Forecast, Air Quality, and Geocoding APIs: query design, variable selection, timezone/timeformat/units, multi-location batching, and robust error handling. Keywords: Open-Meteo, /v1/forecast, /v1/air-quality, geocoding-api, hourly, daily, current, timezone=auto, timeformat=unixtime, models, WMO weather_code, CAMS, GeoNames, httpx, FastAPI, pytest.
Open repositoryBest for
Primary workflow: Ship Full Stack.
Technical facets: Full Stack, Backend, Designer, Integration.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: itechmeat.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install open-meteo into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/itechmeat/llm-code before adding open-meteo to shared team environments
- Use open-meteo for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: open-meteo
description: "Integrate Open-Meteo Weather Forecast, Air Quality, and Geocoding APIs: query design, variable selection, timezone/timeformat/units, multi-location batching, and robust error handling. Keywords: Open-Meteo, /v1/forecast, /v1/air-quality, geocoding-api, hourly, daily, current, timezone=auto, timeformat=unixtime, models, WMO weather_code, CAMS, GeoNames, httpx, FastAPI, pytest."
version: "1.4.0"
release_date: "2024-12-31"
---
# Open Meteo
## When to use
- You need weather forecasts (hourly/daily/current) for coordinates.
- You need air quality / pollen forecasts (hourly/current) for coordinates.
- You need to resolve a user-provided place name to coordinates and timezone (geocoding).
- You need to support multi-location batching (comma-separated lat/lon lists).
- You need a deterministic checklist for Open-Meteo query parameters, response parsing, and error handling.
## Goal
Provide a reliable, production-friendly way to call Open-Meteo APIs (Forecast, Air Quality, Geocoding), choose variables, control time/units/timezone, and parse responses consistently.
## Steps
1. Pick the correct API and base URL
- Forecast: `https://api.open-meteo.com/v1/forecast`
- Air Quality: `https://air-quality-api.open-meteo.com/v1/air-quality`
- Geocoding: `https://geocoding-api.open-meteo.com/v1/search`
2. Resolve coordinates (if you only have a name)
- Call Geocoding with `name` and optional `language`, `countryCode`, `count`.
- Use the returned `latitude`, `longitude`, and `timezone` for subsequent calls.
3. Design your time axis (timezone, timeformat, and range)
- Prefer `timezone=auto` when results must align to local midnight.
- If you request `daily=...`, set `timezone` (docs: daily requires timezone).
- Choose `timeformat=iso8601` for readability, or `timeformat=unixtime` for compactness.
- If using `unixtime`, remember timestamps are GMT+0 and you must apply `utc_offset_seconds` for correct local dates.
- Choose range controls:
- `forecast_days` and optional `past_days`, or
- explicit `start_date`/`end_date` (YYYY-MM-DD), and for sub-daily `start_hour`/`end_hour`.
4. Choose variables minimally (avoid "download everything")
- Forecast: request only the variables you need via `hourly=...`, `daily=...`, `current=...`.
- Air Quality: request only the variables you need via `hourly=...`, `current=...`.
- Keep variable names exact; typos return a JSON error with `error: true`.
5. Choose units and model selection deliberately
- Forecast units:
- `temperature_unit` (`celsius` / `fahrenheit`)
- `wind_speed_unit` (`kmh` / `ms` / `mph` / `kn`)
- `precipitation_unit` (`mm` / `inch`)
- Forecast model selection:
- default `models=auto` / “Best match” combines the best models.
- you can explicitly request models via `models=...`.
- provider-specific forecast endpoints also exist (provider implied by path). See `references/models.md` (section "Endpoints vs `models=`") for examples and doc links.
- for provider/model-specific selection tradeoffs, see `references/models.md`.
- Air Quality domain selection:
- `domains=auto` (default) or `cams_europe` / `cams_global`.
6. Implement robust request/response handling
- Treat HTTP errors and JSON-level errors separately.
- JSON error format is:
- `{"error": true, "reason": "..."}`
- When requesting multiple locations (comma-separated coordinates), expect the JSON output shape to change to a list of structures.
- Optionally use `format=csv` or `format=xlsx` when you need data export.
7. Validate correctness with a “known city” check
- Geocode “Berlin” → Forecast `hourly=temperature_2m` for 1–2 days → verify timezone and array lengths.
- Air Quality `hourly=pm10,pm2_5,european_aqi` → verify units and presence of `hourly_units`.
## Critical prohibitions
- Do not include out-of-scope APIs in this skill’s implementation guidance: Historical Weather, Ensemble Models, Seasonal Forecast, Climate Change, Marine, Satellite Radiation, Elevation, Flood.
- Do not omit `timezone` when requesting `daily` variables (per docs).
- Do not assume `unixtime` timestamps are local time; they are GMT+0 and require `utc_offset_seconds` adjustment.
- Do not silently ignore `{"error": true}` responses; fail fast with the provided `reason`.
- Do not request huge variable sets by default; keep queries minimal to reduce payload and avoid accidental overuse.
## Definition of done
- You can geocode a place name and obtain coordinates/timezone.
- You can fetch Forecast data with at least one `hourly`, one `daily` (with timezone), and one `current` variable.
- You can fetch Air Quality data for at least one pollutant and one AQI metric.
- Your client code handles both HTTP-level failures and JSON-level `error: true` with clear messages.
- Attribution requirements from the docs are captured for Air Quality (CAMS) and Geocoding (GeoNames).
## Links
- Official docs (in-scope):
- https://open-meteo.com/en/docs
- https://open-meteo.com/en/docs/air-quality-api
- https://open-meteo.com/en/docs/geocoding-api
- Skill references:
- `references/forecast-api.md`
- `references/models.md`
- `references/weather-codes.md`
- `references/air-quality-api.md`
- `references/geocoding-api.md`
- `references/examples.md`
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### references/models.md
```markdown
# Forecast `models=` selection guide
Source: Official Open-Meteo provider documentation pages.
**Scope:** Weather Forecast API only. Does not cover Historical, Ensemble, Seasonal, Climate, Marine, Satellite Radiation, Elevation, or Flood APIs.
## How model selection works
- `models=auto` (default) — "Best match" combines optimal models automatically
- Explicit `models=<key>` — select specific provider/model
- Provider-specific endpoints — some providers have dedicated endpoints (e.g., `/v1/ecmwf`)
## Endpoints vs `models=`
**Generic Forecast endpoint (recommended):**
- URL: `https://api.open-meteo.com/v1/forecast`
- Use `models=auto` or `models=<provider_key>`
- Most flexible, supports switching providers per request
**Provider-specific endpoints:**
- `/v1/dwd-icon` — DWD ICON
- `/v1/gfs` — NOAA GFS/HRRR
- `/v1/ecmwf` — ECMWF IFS/AIFS
- `/v1/bom` — Australia BOM
- `/v1/cma` — China CMA
Start with the generic endpoint + `models=auto` unless you have specific requirements.
## Model selection rules
1. **Default to `models=auto`** — works globally, picks best available
2. **Use "seamless" models** when you want:
- High-resolution short-range (2–3 days) + automatic extension with global models
3. **Use regional models** when you need:
- Higher spatial resolution
- Only care about short horizons (nowcast / 0–72h)
4. **Variable availability varies:**
- Not all providers have direct solar radiation (some derive it)
- Cloud cover at 2m (fog indicator) — only KMA, UKMO UKV, DMI
- Probability data — only NBM (NOAA), ARPEGE (Météo-France)
5. **Licensing:**
- UKMO: CC BY-SA 4.0 (derived products must stay compatible)
6. **Operational notes:**
- BOM: temporary suspension due to platform upgrades
- CMA: recent overload/reliability issues
## Provider quick reference
| Provider | Region | Resolution | Horizon | Seamless key |
|----------|--------|------------|---------|--------------|
| DWD ICON | Germany/Europe | 2–11 km | 2–7.5d | `icon_seamless` |
| NOAA GFS | Global/US | 3–13 km | 16d | `gfs_seamless` |
| Météo-France | France/Europe | 1.5–25 km | 2–4d | `meteofrance_seamless` |
| ECMWF | Global | 9–25 km | 15d | `ecmwf_ifs` |
| UKMO | UK/Global | 2–10 km | 2–7d | `ukmo_seamless` |
| KMA | Korea/Global | 1.5–12 km | 2–12d | `kma_seamless` |
| JMA | Japan/Global | 5–55 km | 4–11d | `jma_seamless` |
| MeteoSwiss | Central Europe | 1–2 km | 33h–5d | `meteoswiss_icon_ch1` |
| MET Norway | Nordic | 1 km | 2.5d | `metno_seamless` |
| GEM | Canada/Global | 2.5–15 km | 2–10d | `gem_seamless` |
| BOM | Australia | 15 km | 10d | `bom_access_global` |
| CMA | China/Global | 15 km | 10d | `cma_grapes_global` |
| KNMI | Netherlands | 2–5.5 km | 2.5–10d | `knmi_seamless` |
| DMI | Denmark | 2 km | 2.5–10d | `dmi_seamless` |
| ItaliaMeteo | Southern Europe | 2 km | 3d | `italia_meteo_arpae_icon_2i` |
## Finding specific model keys
If you need a specific sub-model (not seamless):
1. Go to the provider's docs page
2. Use "Preview → URL" generator
3. Copy `models=...` values from the generated URL
Provider docs:
- https://open-meteo.com/en/docs/dwd-api
- https://open-meteo.com/en/docs/gfs-api
- https://open-meteo.com/en/docs/ecmwf-api
- https://open-meteo.com/en/docs/meteofrance-api
- https://open-meteo.com/en/docs/ukmo-api
- https://open-meteo.com/en/docs/kma-api
- https://open-meteo.com/en/docs/jma-api
- https://open-meteo.com/en/docs/meteoswiss-api
- https://open-meteo.com/en/docs/metno-api
- https://open-meteo.com/en/docs/gem-api
- https://open-meteo.com/en/docs/bom-api
- https://open-meteo.com/en/docs/cma-api
- https://open-meteo.com/en/docs/knmi-api
- https://open-meteo.com/en/docs/dmi-api
- https://open-meteo.com/en/docs/italia-meteo-arpae-api
```
### references/forecast-api.md
```markdown
# Open-Meteo Weather Forecast API (in-scope)
Source of truth: https://open-meteo.com/en/docs
## Base URL
- `https://api.open-meteo.com/v1/forecast`
## Request shape
- HTTP method: `GET`
- Query parameters are URL-encoded.
### Multi-location batching
- `latitude` and `longitude` accept **comma-separated lists**.
- When multiple locations are requested, the **JSON output shape changes** (docs note this explicitly).
- CSV/XLSX export adds a `location_id` column.
## Core query parameters
### Required
- `latitude` (float)
- `longitude` (float)
### Variable selection
- `hourly` (string array): comma-separated or repeated `&hourly=` parameters.
- `daily` (string array): comma-separated or repeated `&daily=` parameters.
- **Important:** If `daily` variables are specified, `timezone` is required.
- `current` (string array): current-condition variables.
### Time controls
- `timezone` (string, default `GMT`)
- Use a TZ database name (e.g., `Europe/Berlin`).
- `timezone=auto` resolves coordinates to the local timezone.
- If timezone is set, timestamps are returned in local time and data starts at 00:00 local-time.
- `timeformat` (string, default `iso8601`)
- `iso8601` or `unixtime`.
- **If `unixtime`:** timestamps are returned in GMT+0; apply `utc_offset_seconds` to get correct local dates.
- `forecast_days` (int 0–16, default 7)
- `past_days` (int 0–92, default 0)
- Fine-grained timestep control:
- `forecast_hours`, `past_hours`
- For 15-minutely data: `forecast_minutely_15`, `past_minutely_15`
- Explicit time interval:
- `start_date`, `end_date` (YYYY-MM-DD)
- For hourly/15-minutely: `start_hour`, `end_hour`, `start_minutely_15`, `end_minutely_15` (YYYY-MM-DDThh:mm)
### Units
- `temperature_unit` (default `celsius`): set to `fahrenheit` to convert.
- `wind_speed_unit` (default `kmh`): alternatives `ms`, `mph`, `kn`.
- `precipitation_unit` (default `mm`): alternative `inch`.
### Models
- `models` (string array, default `auto`)
- Docs note: “Best match” provides the best forecast worldwide.
- “Seamless” combines models from a provider into a seamless prediction.
### Elevation and grid-cell selection
- `elevation` (float)
- Default: uses a 90m digital elevation model.
- `elevation=nan` disables downscaling.
- `cell_selection` (string, default `land`)
- `land`: prefers a land grid-cell with similar elevation.
- `sea`: prefers sea grid-cells.
- `nearest`: nearest possible grid-cell.
### Export formats
- `format=csv` or `format=xlsx` to export.
### Commercial usage
- `apikey` is optional and described as required only for commercial use to access reserved resources.
- Docs note the **server URL requires the prefix `customer-`** for commercial usage.
## Variables (high-level map)
The docs provide extensive variable lists. These are common, high-signal variables to start with:
- Forecast `hourly`:
- `temperature_2m`, `relative_humidity_2m`, `apparent_temperature`
- `precipitation`, `rain`, `showers`, `snowfall`, `precipitation_probability`
- `wind_speed_10m`, `wind_direction_10m`, `wind_gusts_10m`
- `weather_code`, `cloud_cover`, `pressure_msl`, `visibility`
- Forecast `daily`:
- `temperature_2m_max`, `temperature_2m_min`
- `precipitation_sum`, `rain_sum`, `snowfall_sum`
- `sunrise`, `sunset`, `daylight_duration`, `sunshine_duration`
- `wind_speed_10m_max`, `wind_gusts_10m_max`
- Forecast `current`:
- any hourly variable can be requested as current; docs mention current values are based on 15-minutely data.
## Response structure (single-location)
The docs show the canonical response shape:
- Top-level metadata:
- `latitude`, `longitude`, `elevation`
- `generationtime_ms`
- `utc_offset_seconds`
- `timezone`, `timezone_abbreviation`
- Variable blocks:
- `current` (object): values for requested current variables + `time` and `interval` (seconds)
- `hourly` (object): `time[]` + arrays for each requested hourly variable
- `hourly_units` (object): unit per hourly variable
- `daily` / `daily_units` analogous
## WMO weather codes
- `weather_code` uses WMO interpretation codes.
- See: `references/weather-codes.md`.
## Error handling
If URL parameters are invalid or variable names are misspelled, the API returns HTTP 400 with a JSON object:
```json
{
"error": true,
"reason": "Cannot initialize WeatherVariable from invalid String value ..."
}
```
```
### references/weather-codes.md
```markdown
# WMO Weather interpretation codes (WW)
Source of truth: https://open-meteo.com/en/docs
Open-Meteo’s `weather_code` uses WMO interpretation codes.
| Code | Description |
| --- | --- |
| 0 | Clear sky |
| 1, 2, 3 | Mainly clear, partly cloudy, and overcast |
| 45, 48 | Fog and depositing rime fog |
| 51, 53, 55 | Drizzle: Light, moderate, and dense intensity |
| 56, 57 | Freezing Drizzle: Light and dense intensity |
| 61, 63, 65 | Rain: Slight, moderate and heavy intensity |
| 66, 67 | Freezing Rain: Light and heavy intensity |
| 71, 73, 75 | Snow fall: Slight, moderate, and heavy intensity |
| 77 | Snow grains |
| 80, 81, 82 | Rain showers: Slight, moderate, and violent |
| 85, 86 | Snow showers slight and heavy |
| 95* | Thunderstorm: Slight or moderate |
| 96, 99* | Thunderstorm with slight and heavy hail |
\* Thunderstorm forecast with hail is only available in Central Europe (per docs).
```
### references/air-quality-api.md
```markdown
# Open-Meteo Air Quality API (in-scope)
Source of truth: https://open-meteo.com/en/docs/air-quality-api
## Base URL
- `https://air-quality-api.open-meteo.com/v1/air-quality`
## Core query parameters
### Required
- `latitude` (float)
- `longitude` (float)
### Variable selection
- `hourly` (string array): comma-separated or repeated `&hourly=` parameters.
- `current` (string array): current-condition air-quality variables.
### Domain selection
- `domains` (string, default `auto`)
- `auto`: combine both domains automatically.
- `cams_europe`: European domain.
- `cams_global`: global domain.
Docs note: European and global domains are not coupled and may show different forecasts.
### Time controls
- `timezone` (string, default `GMT`)
- Supports TZ database names.
- `timezone=auto` resolves coordinates to local timezone.
- `timeformat` (string, default `iso8601`)
- `iso8601` or `unixtime`.
- If `unixtime`: timestamps are GMT+0; apply `utc_offset_seconds` to derive correct local dates.
- `forecast_days` (int 0–7, default 5)
- `past_days` (int 0–92, default 0)
- Alternative timestep control:
- `forecast_hours`, `past_hours`
- Explicit time interval:
- `start_date`, `end_date` (YYYY-MM-DD)
- `start_hour`, `end_hour` (YYYY-MM-DDThh:mm)
### Grid cell selection
- `cell_selection` (string, default `nearest`)
- `nearest`, `land`, `sea`.
### Export formats
- `format=csv` or `format=xlsx` to export.
### Commercial usage
- `apikey` is optional; docs describe it as required only for commercial use to access reserved resources.
- Docs note the server URL requires the prefix `customer-` for commercial usage.
## Hourly variables (docs list)
Common pollutants and indices:
- Particulate matter: `pm10`, `pm2_5`
- Gases: `carbon_monoxide`, `nitrogen_dioxide`, `sulphur_dioxide`, `ozone`
- AQI (European):
- `european_aqi` (consolidated max)
- `european_aqi_pm2_5`, `european_aqi_pm10`, `european_aqi_nitrogen_dioxide`, `european_aqi_ozone`, `european_aqi_sulphur_dioxide`
- AQI (United States):
- `us_aqi` (consolidated max)
- `us_aqi_pm2_5`, `us_aqi_pm10`, `us_aqi_nitrogen_dioxide`, `us_aqi_ozone`, `us_aqi_sulphur_dioxide`, `us_aqi_carbon_monoxide`
Pollen variables (Europe only, during pollen season with 4 days forecast):
- `alder_pollen`, `birch_pollen`, `grass_pollen`, `mugwort_pollen`, `olive_pollen`, `ragweed_pollen`
Other hourly variables called out in the docs UI include:
- `carbon_dioxide`, `aerosol_optical_depth`, `dust`, `uv_index`, `uv_index_clear_sky`, `ammonia`, `methane`
## European AQI scale (docs)
- 0–20: good
- 20–40: fair
- 40–60: moderate
- 60–80: poor
- 80–100: very poor
- >100: extremely poor
Docs note: PM uses a 24-hour rolling average; gases use hourly values.
### EU thresholds table (from docs)
| Pollutant (μg/m³) | Timespan | Good | Fair | Moderate | Poor | Very poor | Extremely poor |
| --- | --- | --- | --- | --- | --- | --- | --- |
| PM2.5 | 24h | 0-10 | 10-20 | 20-25 | 25-50 | 50-75 | 75-800 |
| PM10 | 24h | 0-20 | 20-40 | 40-50 | 50-100 | 100-150 | 150-1200 |
| NO2 | 1h | 0-40 | 40-90 | 90-120 | 120-230 | 230-340 | 340-1000 |
| O3 | 1h | 0-50 | 50-100 | 100-130 | 130-240 | 240-380 | 380-800 |
| SO2 | 1h | 0-100 | 100-200 | 200-350 | 350-500 | 500-750 | 750-1250 |
## US AQI scale (docs)
- 0–50: good
- 51–100: moderate
- 101–150: unhealthy for sensitive groups
- 151–200: unhealthy
- 201–300: very unhealthy
- 301–500: hazardous
### US thresholds table (from docs)
| Pollutant | Timespan | Good | Moderate | Unhealthy for Sensitive Groups | Unhealthy | Very Unhealthy | Hazardous | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| O3 (ppb) | 8h | 0-55 | 55-70 | 70-85 | 85-105 | 105-200 | - | - |
| O3 (ppb) | 1h | - | - | 125-165 | 165-205 | 205-405 | 405-505 | 505-605 |
| PM2.5 (μg/m³) | 24h | 0-12 | 12-35.5 | 35.5-55.5 | 55.5-150.5 | 150.5-250.5 | 250.5-350.5 | 350.5-500.5 |
| PM10 (μg/m³) | 24h | 0-55 | 55-155 | 155-255 | 255-355 | 355-425 | 425-505 | 505-605 |
| CO (ppm) | 8h | 0-4.5 | 4.5-9.5 | 9.5-12.5 | 12.5-15.5 | 15.5-30.5 | 30.5-40.5 | 40.5-50.5 |
| SO2 (ppb) | 1h | 0-35 | 35-75 | 75-185 | 185-305 | - | - | - |
| SO2 (ppb) | 24h | - | - | - | - | 305-605 | 605-805 | 805-1005 |
| NO2 (ppb) | 1h | 0-54 | 54-100 | 100-360 | 360-650 | 650-1250 | 1250-1650 | 1650-2050 |
## Response structure (single-location)
The docs show the canonical response shape:
- `latitude`, `longitude`, `elevation`
- `generationtime_ms`
- `utc_offset_seconds`
- `timezone`, `timezone_abbreviation`
- `hourly` (object): `time[]` + arrays for each requested hourly variable
- `hourly_units` (object): unit per hourly variable
(If `current` was requested, a `current` object is included.)
## Error handling
The docs show JSON error objects returned with HTTP 400:
```json
{
"error": true,
"reason": "Cannot initialize WeatherVariable from invalid String value ..."
}
```
## Attribution / acknowledgement (docs)
Docs require users to provide attribution to:
- CAMS ENSEMBLE data provider, and
- Open-Meteo
See the “Citation & Acknowledgement” section on the Air Quality docs page.
```
### references/geocoding-api.md
```markdown
# Open-Meteo Geocoding API (in-scope)
Source of truth: https://open-meteo.com/en/docs/geocoding-api
## Base URL
- Search: `https://geocoding-api.open-meteo.com/v1/search`
Docs also mention IDs can be resolved via:
- Get by ID: `https://geocoding-api.open-meteo.com/v1/get?id=<id>`
## Search parameters
| Parameter | Required | Default | Notes |
| --- | --- | --- | --- |
| `name` | yes | | Search string: location name or postal code |
| `count` | no | 10 | 1–100 allowed |
| `language` | no | `en` | Lower-cased; returns translated results if available |
| `format` | no | `json` | `json` or `protobuf` |
| `countryCode` | no | | ISO-3166-1 alpha2 filter |
| `apikey` | no | | Docs describe it as required only for commercial use (reserved resources) |
### Matching behavior (docs)
- empty string or 1 character → empty result
- 2 characters → exact matching only
- 3+ characters → fuzzy matching
## Response
On success, returns:
```json
{
"results": [
{
"id": 2950159,
"name": "Berlin",
"latitude": 52.52437,
"longitude": 13.41053,
"elevation": 74.0,
"feature_code": "PPLC",
"country_code": "DE",
"timezone": "Europe/Berlin",
"population": 3426354,
"postcodes": ["10967", "13347"],
"country": "Deutschland",
"admin1": "Berlin"
}
]
}
```
Docs note:
- Empty fields are not returned (e.g., `admin4` may be missing).
- The schema includes administrative levels (`admin1..admin4`) and corresponding IDs.
## Error handling
Docs show HTTP 400 with a JSON error object, e.g.:
```json
{
"error": true,
"reason": "Parameter count must be between 1 and 100."
}
```
## Attribution (docs)
- Location data based on GeoNames
- Country flags from HatScripts/circle-flags
```
### references/examples.md
```markdown
# Examples (Geocoding → Forecast / Air Quality)
All examples are derived from the official docs pages:
- https://open-meteo.com/en/docs
- https://open-meteo.com/en/docs/air-quality-api
- https://open-meteo.com/en/docs/geocoding-api
## Python (httpx) — geocode then forecast
```python
from __future__ import annotations
from typing import Any
import httpx
def _raise_if_open_meteo_error(payload: dict[str, Any]) -> None:
if payload.get("error") is True:
reason = payload.get("reason")
raise RuntimeError(f"Open-Meteo error: {reason}")
def geocode(name: str, *, language: str = "en", count: int = 1) -> dict[str, Any]:
url = "https://geocoding-api.open-meteo.com/v1/search"
params = {"name": name, "language": language, "count": count, "format": "json"}
with httpx.Client(timeout=10.0) as client:
resp = client.get(url, params=params)
resp.raise_for_status()
data = resp.json()
_raise_if_open_meteo_error(data)
results = data.get("results")
if not results:
raise ValueError(f"No geocoding results for: {name}")
return results[0]
def forecast(latitude: float, longitude: float, timezone: str) -> dict[str, Any]:
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": latitude,
"longitude": longitude,
"hourly": "temperature_2m,precipitation,weather_code",
"daily": "temperature_2m_max,temperature_2m_min,precipitation_sum",
"current": "temperature_2m,wind_speed_10m",
"timezone": timezone, # daily requires timezone per docs
"forecast_days": 2,
}
with httpx.Client(timeout=10.0) as client:
resp = client.get(url, params=params)
resp.raise_for_status()
data = resp.json()
_raise_if_open_meteo_error(data)
return data
place = geocode("Berlin", language="en", count=1)
lat = float(place["latitude"])
lon = float(place["longitude"])
tz = str(place.get("timezone") or "GMT")
payload = forecast(lat, lon, tz)
print(payload["timezone"], payload["hourly_units"].get("temperature_2m"))
print(payload["hourly"]["time"][0], payload["hourly"]["temperature_2m"][0])
```
## Python (httpx) — air quality for the same point
```python
from __future__ import annotations
from typing import Any
import httpx
def _raise_if_open_meteo_error(payload: dict[str, Any]) -> None:
if payload.get("error") is True:
raise RuntimeError(f"Open-Meteo error: {payload.get('reason')}")
def air_quality(latitude: float, longitude: float, timezone: str) -> dict[str, Any]:
url = "https://air-quality-api.open-meteo.com/v1/air-quality"
params = {
"latitude": latitude,
"longitude": longitude,
"hourly": "pm10,pm2_5,european_aqi,us_aqi",
"current": "pm10,pm2_5,european_aqi",
"timezone": timezone,
"forecast_days": 2,
"domains": "auto",
}
with httpx.Client(timeout=10.0) as client:
resp = client.get(url, params=params)
resp.raise_for_status()
data = resp.json()
_raise_if_open_meteo_error(data)
return data
```
## Notes
- Variable names must match the docs exactly: e.g., `pm2_5` (not `pm2.5`).
- If you set `timeformat=unixtime`, timestamps are in GMT+0; use `utc_offset_seconds` to derive local dates.
- If you request `daily=...` on the Forecast API, you must set `timezone` (per docs).
```