Extract WSLink add-on probe and treat expected network errors and
NoURLAvailableError as "offline" instead of raising. Log unexpected
errors and avoid raising ConfigEntryNotReady from diagnostics probes.
Add tests for probe robustness, add additional sensitive purge keys,
and fix config_flow host fallback handling.
The health model only knew "wu"/"wslink", so with an Ecowitt setup the
active_protocol / integration_status fell back to "PWS/WU" even while Ecowitt data
was flowing.
- Replace _protocol_name() with _configured_protocol() which returns
wu / wslink / ecowitt (legacy endpoint takes precedence; ecowitt-only -> ecowitt).
- _refresh_summary: treat "ecowitt" as a real accepted protocol (active_protocol and
online_<proto> now track it); the WU-vs-WSLink mismatch -> degraded check is scoped
to the legacy pair so coexisting Ecowitt is never falsely degraded.
- Add the "ecowitt" / "online_ecowitt" entity states to strings/en/cs.
310 passing, 100% coverage; ruff + basedpyright clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- manifest: add single_config_entry, integration_type "device", loggers
["aioecowitt"]; drop empty homekit/ssdp/zeroconf placeholders.
- Q10: raise ConfigEntryNotReady (not PlatformNotReady) when route registration
fails in async_setup_entry; drop the now-unused import.
- Q11: delete the ~105-line commented-out sqlite3 statistics-migration block in
utils.py (would have been blocking I/O in the event loop) and its dead import.
Deferred (with reason): quality_scale (needs a rule audit + quality_scale.yaml),
device-identifier 2-tuple and suggested_entity_id (entity-naming/identity changes,
to land with the planned integration rename), CoordinatorEntity generics in
sensor.py (would introduce a circular import - intentionally untyped).
Note: the health-probe protocol gate was reverted - the proxy add-on can front
WU/WSLink/Ecowitt, so polling must stay unconditional.
308 passing, 100% coverage; ruff clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Security (from the deep audit):
- S1: health "integration_health" sensor no longer dumps the full snapshot in
extra_state_attributes (readable by any HA user). public_health_snapshot()
strips internal network details (source IP, internal URLs, raw add-on status);
full data stays on the authenticated endpoint and admin-only diagnostics.
- S2: anonymize() now masks the Ecowitt passkey/PASSKEY.
- S3: Windy station id masked before logging the dataset.
- S4: diagnostics redacts internal network fields (source IP, URLs, raw_status).
i18n (Q1/Q2):
- Sync strings.json + en.json with the actual flow: add wslink_port_setup step,
the ecowitt/pocasi/wslink_port_setup menu entries, the pocasi_* and
windy_key_required error keys, the stale_sensors_detected issue; fix wrong data
keys (WSLINK->wslink + legacy_enabled, POCASI_CZ_SEND_INTERVAL->POCASI_SEND_INTERVAL,
pocasi_enabled_checkbox->pocasi_enabled_chcekbox); translate the English ecowitt
options step (was Czech); de-duplicate the legacy-battery issue description.
- Q2: rename wbgt_index -> wbgt_temp to match the entity translation_key.
- cs.json: add windy_key_required and fix the pocasi data/data_description keys.
Tests: 300 passing, 100% coverage maintained; basedpyright clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The /station/health route is registered directly on the aiohttp router, so HA's
auth middleware only flags requests without blocking them - the endpoint was
reachable unauthenticated and returned the full health snapshot.
- health_status now requires HA authentication (bearer token or signed request)
via KEY_AUTHENTICATED and returns 401 otherwise.
- Mask the Ecowitt webhook id (the endpoint's only credential) in last_ingress
paths via _sanitize_path, so it never enters the snapshot exposed by the health
endpoint or the diagnostics download.
- Redact ECOWITT_WEBHOOK_ID in diagnostics.
- Compare the Ecowitt webhook id in constant time (hmac.compare_digest), matching
the WU/WSLink credential checks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pass config_entry explicitly to super().__init__() in both
WeatherDataUpdateCoordinator and HealthCoordinator instead of relying on the
implicit ContextVar (deprecated, breaks in HA 2026.8 for core and was breaking
async_config_entry_first_refresh outside the setup context).
Also resolve each discovered sensor's display name once in received_data
(the previous comprehension awaited translations() twice per key).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Reuse existing `WeatherDataUpdateCoordinator` instance across reloads instead of
creating a new one; routes keep pointing to the same coordinator, so entities
stay subscribed and updates never silently drop
- `update_listener` now skips full reload when only `SENSORS_TO_LOAD` changes
(auto-discovery); avoids the "frozen UI" window caused by temporary platform unload
- Replaced direct `route._handler` mutation with a proper `Routes` dispatcher;
all aiohttp routes are registered once and an internal dispatcher decides which
handler is active — safe to switch at runtime without touching the router
- Fixed `self.config_entry` / `self.config` inconsistency in coordinator
- `BatteryBinarySensor` now carries correct `device_info` (same identifiers as
`WeatherSensor`) → single device card in UI instead of two
- Translations for binary sensors must live under `entity.binary_sensor.*`,
not `entity.sensor.*`
- Fixed all tests broken by new `register_path(hass, coordinator, coordinator_h, entry)` signature
- Updated `_RouterStub` to accept `name=` kwargs and return objects with `.method`
- Added `async post()` to `_RequestStub` stubs
- Aligned `Routes` tests with new `method:path` dispatch key format and `show_enabled()` output
- Replaced `WindyApiKeyError` with `WindyPasswordMissing` to match actual exceptions
- Updated `_FakeResponse` to use HTTP status codes instead of response text strings
- Patched `persistent_notification.create` in Windy push tests to avoid `SimpleNamespace` errors
- Integrate aioecowitt to parse incoming weather station payloads and map sensors to the SWS pipeline.
- Add a new webhook endpoint at /weatherhub/{webhook_id} with support for dynamic route resolution.
- Expand battery binary sensor definitions and implement logic for dynamic entity creation.
- Bump version to 2.0.0-pre1.