Implements SDK support for the **"weather" integration type** shipped in Gladys …core by GladysAssistant/Gladys#2738 (spec **B.18**): a weather provider (Météo France, Open-Meteo…) installs from the store and feeds the dashboard weather widget, the assistant and the weather-alert scene triggers, with no provider-specific code in the core.
## What the SDK adds
- **`WEATHER_GET` WebSocket message type** (`external-integration.weather.get`), routed like every command and auto-acked.
- **`gladys.onWeatherGet(callback)`** — `(options) => Promise<pivot weather>` with `options = { latitude, longitude, language, units }`. The resolved object is acked back as `data.weather` (the core awaits it under **15 s**, the same exception to the 5 s rule as `camera.get-image`); throwing acks the command as failed so the core's provider loop falls through to the next provider. This is exactly the SDK surface the B.18 spec documents in its contract C.8 table.
- **`gladys.onWeatherGetImage(callback)`** — `(key) => Promise<string>` (B.18 point 6, provider images: vigilance map, rain radar…). The pivot payload only declares **metadata** (`images`, ≤ 3 entries of `{ key, label? }`); the bytes travel on demand over `external-integration.weather.get-image`: resolve the raw base64 (no data-URI prefix) of a PNG/JPEG ≤ 500 KB decoded, acked as `data.image` under 15 s — validated (magic numbers + size) and cached 10 min by the core, served to the browser from the Gladys origin.
- **`gladys.requestWeatherRefresh()`** — fire-and-forget freshness nudge (B.18 point 5, "trigger, not data") over `external-integration.weather.refresh`: "re-pull me now and re-evaluate the weather-alert scene triggers". No payload, no ack; rate-limited core-side (1/min per integration, silently dropped beyond) and dropped silently while disconnected.
- **Constants** exported from CJS and ESM entry points:
- `WEATHER_CONDITIONS` — the pivot condition enum (`clear` | `partly-cloudy` | `cloud` | `fog` | `drizzle` | `rain` | `pouring` | `sleet` | `hail` | `snow` | `thunderstorm` | `wind` | `night` | `unknown`; anything else is coerced to `unknown` by the core; `night` is deprecated for providers — send the real condition plus `is_day: false`);
- `WEATHER_ALERT_SEVERITIES` — the CAP-style alert severities (`minor` | `moderate` | `severe` | `extreme`);
- `WEATHER_ALERT_TYPES` — the alert phenomenon types (`wind` | `rain` | `flood` | `thunderstorm` | `snow` | `heat` | `cold` | `avalanche` | `coastal` | `fog`; optional metadata — an invalid type is dropped by the core, the alert is kept);
- internal mirror of the core-side bounds (≤ 24 hours, ≤ 8 days, ≤ 10 alerts, ≤ 3 images, event ≤ 100 chars, description ≤ 5000 chars, image ≤ 500 KB decoded, label ≤ 50 chars).
- **TypeScript typings** of the whole pivot format: `WeatherGetOptions`, `WeatherUnits` (`'metric' | 'us'`), `WeatherCondition`, `WeatherPayload` (including the `is_day` strict boolean on the current conditions and each `hours` entry, and the `images` metadata), `WeatherHourForecast`, `WeatherDayForecast`, `WeatherAlert` (with the optional `type`), `WeatherAlertSeverity`, `WeatherAlertType`, `WeatherImage`, plus the `onWeatherGet`/`onWeatherGetImage`/`requestWeatherRefresh` members and the `WEATHER_GET`/`WEATHER_GET_IMAGE`/`WEATHER_REFRESH` message types.
- **README**: `onWeatherGet(cb)`/`onWeatherGetImage(cb)` rows in the Handlers table, `requestWeatherRefresh()` row in the Methods table, and a dedicated **"Weather providers"** section (manifest `type: "weather"`, unit systems, condition mapping, `is_day` day/night signal, typed alerts, provider images, freshness nudge, 15 s ack, core-side normalization and bounds), mirroring the existing "Communication channels" section.
## Design notes
The SDK passes the resolved payloads through as-is (like `onGetImage`): per B.18 they are **never trusted** and are normalized/bounded by the Gladys core (`normalizeWeather`/`normalizeWeatherImage` — whitelisted fields, finite numbers, clamped percentages, capped arrays, strict-boolean `is_day`, magic-number image checks, `units` stamped from the request). The SDK documents the contract thoroughly (typings + README) instead of duplicating the normalization.
The weather-alert scene trigger of B.18 point 4 is **core-owned** (a gated 30-min scheduled diff on the normalized alerts) — the integration has nothing to implement for it; `requestWeatherRefresh()` is the optional cooperation path that beats the 30-min floor.
Kept in sync with the latest revision of the Gladys PR (extended condition enum with `partly-cloudy`/`pouring`/`hail`, `is_day` day/night signal, typed alerts, provider images, freshness nudge, alert description bound raised to 5000).
## Tests
- `test/weather.test.js` — WS command acks against the fake Gladys server: `weather.get` success with a full pivot payload (current + hours + days + typed alerts + `is_day` + `images` metadata), `us` unit system pass-through, handler failure → `success:false` with the error message, no handler → `"not implemented"`; `weather.get-image` success/failure/not-implemented acks; `weather.refresh` emission (empty payload) and silent drop while disconnected; plus the exported constants and message types.
- `test/types/api.test-d.ts` — compile-time check of the new typings.
- Full suite: **193 tests pass**, ESLint, `tsc` and Prettier clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01BPXiFG8AQAUprvrRNCtaKF
## Summary by CodeRabbit
* **New Features**
* Added weather data and weather image retrieval handlers.
* Added refresh requests for updating weather information.
* Added standardized forecasts, alerts, conditions, units, day/night details, and normalized responses.
* Added weather messaging and exported condition, alert severity, and alert type constants.
* Added TypeScript definitions for weather requests, forecasts, alerts, images, and responses.
* **Documentation**
* Documented provider fallback, validation, payload limits, errors, timeouts, image handling, caching, and supported versions.