# Open-Meteo Integration Notes ## Purpose This document describes the Open-Meteo API usage currently implemented by `weatherfeeder`. It is for developers and operators maintaining Open-Meteo source URLs, normalizers, fixtures, and tests. General config syntax belongs in [configuration](../config.md). Emitted JSON events are documented in [event wire contract](events.md). ## Implemented Drivers | Driver | Kind | Raw schema | Canonical schema | | --- | --- | --- | --- | | `openmeteo_observation` | `observation` | `raw.openmeteo.current.v1` | `weather.observation.v1` | | `openmeteo_forecast` | `forecast` | `raw.openmeteo.hourly.forecast.v1` | `weather.forecast.v1` | ## Config Requirements Both drivers require HTTP source params: - `url` - `user_agent` The shared HTTP helper also accepts `conditional`, `http_timeout`, and `http_response_body_limit_bytes`. Conditional requests are enabled by default; an upstream `304 Not Modified` response emits no event for that poll. ## Upstream Shapes Used `openmeteo_observation` expects a JSON response with top-level location/timezone metadata and a `current` object. The normalizer uses: - `latitude`, `longitude`, `timezone`, `utc_offset_seconds`; - `current.time`; - current temperature, apparent temperature, relative humidity, weather code, wind speed/direction/gusts, pressure, and `is_day`. `openmeteo_forecast` expects top-level location/timezone metadata and an array-oriented `hourly` object. The normalizer uses: - `hourly.time`; - hourly temperature, apparent temperature, dew point, relative humidity, precipitation probability, precipitation amount, snowfall, weather code, pressure, wind speed/direction/gusts, `is_day`, cloud cover, visibility, and UV index. Open-Meteo field presence is allowed to vary. Missing optional arrays produce nil canonical fields for the affected periods. ## Accept Header Open-Meteo sources request: ```text application/json ``` ## Time Handling Open-Meteo timestamps often omit an explicit offset. The provider helper parses times by using the returned `timezone` or `utc_offset_seconds` when needed. Observation source events set `effective_at` from `current.time` when it can be parsed. Hourly forecast source events prefer `current.time`, then the first non-empty `hourly.time` entry. The hourly forecast normalizer sets canonical `issuedAt` from the incoming event `emitted_at` when present, otherwise from the first hourly period start. Normalized forecast `effective_at` matches `issuedAt`. ## Mapping Notes Open-Meteo is not a station feed. Weatherfeeder synthesizes canonical station/location IDs from latitude and longitude when both are available. Open-Meteo weather codes are WMO codes and are treated as authoritative. Canonical text is derived from the WMO code and day/night hint. Wind speed and gust fields are treated as kilometers per hour. Pressure values are treated as hPa and converted to Pa. Snowfall values are treated as centimeters and converted to millimeters. Hourly forecast period end time is the next period start. The last period uses the previous interval length, or one hour when there is no previous interval. ## Failure Behavior Constructor validation failures stop daemon startup. Polling failures are returned to the scheduler. Metadata decoding failures in sources still allow raw payload emission when the HTTP response itself succeeded. Normalization fails when required time data is missing or invalid, such as an empty `hourly.time` array for hourly forecasts. ## Tests To Inspect - `internal/sources/openmeteo/source_test.go` - `internal/normalizers/openmeteo/*_test.go` - `internal/providers/openmeteo/*_test.go`