# OpenWeather Integration Notes ## Purpose This document describes the OpenWeather current-weather usage implemented by `weatherfeeder`. It is for developers and operators maintaining OpenWeather 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 Driver | Driver | Kind | Raw schema | Canonical schema | | --- | --- | --- | --- | | `openweather_observation` | `observation` | `raw.openweather.current.v1` | `weather.observation.v1` | Only current-weather observation polling is registered for OpenWeather. ## Config Requirements The driver requires 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. The configured URL must include: ```text units=metric ``` Startup fails if `units` is omitted or set to another value. Keep OpenWeather API keys out of committed configs. Use local config management or deployment secrets for the `appid` query parameter. ## Upstream Shape Used The source emits the full current-weather JSON payload as a raw event. The normalizer uses: - `coord.lat`, `coord.lon`; - primary `weather[0]` condition ID, description, and icon; - `main.temp`, `main.feels_like`, `main.pressure`, `main.humidity`, and optional `main.sea_level`; - `visibility`; - `wind.speed`, `wind.deg`, and `wind.gust`; - `dt`; - `sys.sunrise` and `sys.sunset`; - `id` and `name`. ## Accept Header OpenWeather sources request: ```text application/json ``` ## Time Handling Source events set `effective_at` from `dt` when it is present and positive. The normalizer also uses `dt` as the canonical observation timestamp and normalized effective time. ## Mapping Notes Metric units are required so canonical unit conversion is deterministic: - `main.temp` and `main.feels_like` are treated as Celsius; - `wind.speed` and `wind.gust` are treated as meters per second and converted to kilometers per hour; - pressure values are treated as hPa and converted to Pa. The primary condition is `weather[0]`. OpenWeather condition IDs are mapped into the canonical WMO code vocabulary. The human text description is preserved from the provider description. Day/night is inferred from the OpenWeather icon suffix when available, otherwise from sunrise and sunset bounds. The station ID uses the OpenWeather city ID when present. If no city ID is present, weatherfeeder synthesizes an ID from coordinates. The station name uses the provider `name`, falling back to `OpenWeatherMap` when blank. ## Failure Behavior Constructor validation failures stop daemon startup. Polling also re-checks the metric-unit requirement before fetching. HTTP failures are returned to the scheduler. Metadata decoding failures in the source still allow raw payload emission when the HTTP response itself succeeded. ## Tests To Inspect - `internal/sources/openweather/source_test.go` - `internal/normalizers/openweather/*_test.go` - `internal/providers/openweather/*_test.go`