# Configuration Reference ## Config File `weatherfeeder` reads exactly one YAML file named `config.yml` from the current working directory. There is no config path flag and no search path. YAML decoding is strict for config struct fields: misspelled fields such as `sources[].drviver` fail startup. Driver-specific `params` maps are validated by the source or sink constructor that consumes them. The top-level file contains: ```yaml sources: - name: NWSObservationKSTL mode: poll driver: nws_observation every: 10m kinds: ["observation"] params: url: "https://api.weather.gov/stations/KSTL/observations/latest" user_agent: "Example weatherfeeder operator (ops@example.com)" sinks: - name: stdout driver: stdout params: {} routes: - sink: stdout kinds: ["observation"] ``` `sources` and `sinks` must each contain at least one entry. `routes` is optional. When `routes` is omitted, every configured sink receives every event kind. Maintained copyable configs are available under [`examples/`](../examples/). ## Production-Oriented Shape A typical deployment uses multiple polling sources and sends the same canonical event stream to a broker or database: ```yaml sources: - name: NWSAlertsLocal mode: poll driver: nws_alerts every: 1m kinds: ["alert"] params: url: "https://api.weather.gov/alerts?point=38.6239,-90.3571&limit=20" user_agent: "Example weatherfeeder operator (ops@example.com)" - name: SPCConvectiveOutlookLocal mode: poll driver: spc_convective_outlook every: 30m kinds: ["outlook"] params: latitude: 38.6239 longitude: -90.3571 location_id: "local" location_name: "Configured point" user_agent: "Example weatherfeeder operator (ops@example.com)" sinks: - name: nats_weather driver: nats params: url: nats://nats:4222 subject: weatherfeeder - name: pg_weather driver: postgres params: uri: postgres://weatherdb:5432/weatherdb?sslmode=disable username: weatherdb password: prune: 3d routes: - sink: nats_weather kinds: ["observation", "forecast", "forecast_discussion", "weather_story", "alert", "outlook"] - sink: pg_weather kinds: ["observation", "forecast", "forecast_discussion", "weather_story", "alert", "outlook"] ``` Do not commit real API keys, database passwords, or personal contact addresses in copyable configs. ## Top-Level Fields | Field | Required | Description | |---|:---:|---| | `sources` | yes | List of configured input sources. | | `sinks` | yes | List of configured output sinks. | | `routes` | no | List of sink routing rules. If omitted, all sinks receive all kinds. | ## Source Fields | Field | Required | Description | |---|:---:|---| | `name` | yes | Unique source name. Used as the event source identifier. | | `driver` | yes | Source driver name. | | `mode` | no | `poll`, `stream`, or omitted for auto. Current weatherfeeder drivers are polling drivers. | | `every` | yes | Poll interval for current weatherfeeder source drivers. | | `kinds` | no | Expected event kinds. If present, startup verifies they match the source driver. | | `params` | driver-specific | Driver parameters. See the source-specific sections below. | Current event kinds are `observation`, `forecast`, `forecast_discussion`, `weather_story`, `alert`, and `outlook`. ## Source Drivers | Driver | Kind | Upstream product | |---|---|---| | `nws_observation` | `observation` | NWS station latest observation. | | `nws_alerts` | `alert` | NWS alerts collection. | | `nws_forecast_hourly` | `forecast` | NWS hourly gridpoint forecast. | | `nws_forecast_narrative` | `forecast` | NWS narrative gridpoint forecast. | | `nws_forecast_discussion` | `forecast_discussion` | NWS forecast discussion HTML product. | | `nws_weatherstories` | `weather_story` | NWS office weather stories. | | `openmeteo_observation` | `observation` | Open-Meteo current conditions. | | `openmeteo_forecast` | `forecast` | Open-Meteo hourly forecast. | | `openweather_observation` | `observation` | OpenWeather current weather. | | `spc_convective_outlook` | `outlook` | SPC Day 1-3 convective outlooks. | ## HTTP Source Params Most source drivers use the shared HTTP polling helper. | Param | Required | Description | |---|:---:|---| | `url` | yes | Full upstream request URL. `URL` is also accepted by the helper. | | `user_agent` | yes | User-Agent sent to the upstream provider. `userAgent` is also accepted by the helper. | | `conditional` | no | Boolean. Defaults to `true`; enables ETag and Last-Modified conditional requests. | | `http_timeout` | no | Positive duration for the HTTP client timeout. | | `http_response_body_limit_bytes` | no | Positive integer response body limit in bytes. | When `conditional` is enabled and the upstream returns `304 Not Modified`, the source emits no events for that poll. OpenWeather observation URLs must include `units=metric`. Startup fails if the URL omits it or sets another unit system. ## SPC Convective Outlook Params `spc_convective_outlook` fetches the nine required Day 1-3 GeoJSON outlook products and the three required Day 1-3 print pages as one atomic bundle. | Param | Required | Description | |---|:---:|---| | `latitude` | yes | Location latitude in decimal degrees. | | `longitude` | yes | Location longitude in decimal degrees. | | `user_agent` | yes | User-Agent sent to SPC. `userAgent` is also accepted. | | `location_id` | no | Operator-defined location identifier copied into canonical outlook runs. | | `location_name` | no | Human location label copied into canonical outlook runs. | | `geojson_urls` | no | Map of product key to override URL. Used for tests and upstream URL changes. | | `discussion_urls` | no | Map of day key to override print-page URL. Used for tests and upstream URL changes. | | `rss_url` | no | Optional RSS URL. RSS is not fetched unless this is configured. | | `http_timeout` | no | Positive duration for the HTTP client timeout. | | `http_response_body_limit_bytes` | no | Positive integer response body limit in bytes. | GeoJSON product keys are `day1_categorical`, `day1_tornado`, `day1_hail`, `day1_wind`, `day2_categorical`, `day2_tornado`, `day2_hail`, `day2_wind`, and `day3_categorical`. SPC does not provide Day 3 tornado, hail, or wind GeoJSON products. Discussion keys are `day1`, `day2`, and `day3`. ```yaml sources: - name: SPCConvectiveOutlookSTL mode: poll kinds: ["outlook"] driver: spc_convective_outlook every: 30m params: latitude: 38.6239 longitude: -90.3571 location_id: "stl" location_name: "St. Louis, MO" user_agent: "Example weatherfeeder operator (ops@example.com)" ``` ## Sink Fields | Field | Required | Description | |---|:---:|---| | `name` | yes | Unique sink name. Routes refer to this value. | | `driver` | yes | Sink driver name. | | `params` | driver-specific | Sink parameters. | ## Sink Drivers ### `stdout` Prints each event as JSON to stdout. ```yaml sinks: - name: stdout driver: stdout params: {} ``` ### `nats` Publishes each event as JSON to a NATS subject. | Param | Required | Description | |---|:---:|---| | `url` | yes | NATS server URL, such as `nats://localhost:4222`. | | `subject` | yes | Subject to publish events to. | ### `postgres` Writes supported canonical weather events to Postgres using weatherfeeder's registered schema mapping. The table contract is documented in [Postgres integration](integrations/postgres.md). | Param | Required | Description | |---|:---:|---| | `uri` | yes | PostgreSQL connection URI. | | `username` | yes | Database username. | | `password` | yes | Database password. | | `prune` | no | Retention window. If set, rows older than the window are pruned on each write transaction. | `prune` accepts Go duration strings such as `72h`, plus day and week suffixes such as `3d` and `2w`. ## Routes Routes connect event kinds to sinks: ```yaml routes: - sink: stdout kinds: ["observation", "alert"] ``` | Field | Required | Description | |---|:---:|---| | `sink` | yes | Name of a configured sink. | | `kinds` | no | Event kinds to send to that sink. Omit or use an empty list to match all kinds. | Route `kinds` values are trimmed and lowercased by the dispatcher. Blank entries are rejected. ## Duration Formats Top-level source `every` accepts: - Go duration strings such as `30s`, `10m`, or `1h`; - integer values, interpreted as minutes; - numeric strings such as `"15"`, also interpreted as minutes. HTTP param durations such as `http_timeout` accept Go duration strings. Numeric values and numeric strings are interpreted as seconds. Postgres `prune` must be a string duration. ## Secrets The config file is read directly from disk and has no built-in secret expansion. Keep real credentials out of repository-tracked configs. Use deployment tooling to render `config.yml` with the needed secret values before starting the daemon. ## Maintained Examples - [Minimal stdout config](../examples/config.minimal.yml) - [NATS publishing config](../examples/config.nats.yml) - [Postgres persistence config](../examples/config.postgres.yml)