Skip to content

Entity cleanup, rain-forecast device_class fix, and PM ET0 / nowcast diagnostics - #157

Merged
kmich merged 1 commit into
mainfrom
feat/entity-cleanup-nowcast-diagnostics
Sep 26, 2026
Merged

kmich merged 1 commit into
mainfrom
feat/entity-cleanup-nowcast-diagnostics

Conversation

@kmich

@kmich kmich commented Sep 26, 2026

Copy link
Copy Markdown
Owner

Six independent fixes/improvements verified against a live v2.8.1 instance on 2026-09-26. Each section below can be reviewed and reverted independently even though they ship as one PR. Checked open issues/PRs before opening this (twice: 2026-09-26 at task start and again just before opening) - nothing overlapping.

1. Remove orphaned local-forecaster entities

switch.ws_enable_local_forecaster and number.ws_forecaster_learning_rate show up on some live instances as restored: true / unavailable. A full-tree grep (switch.py, number.py, const.py, coordinator.py, learning_state.py, __init__.py) confirms zero current references.

Note on provenance: these unique IDs don't appear anywhere in this repo's git history either (427 commits, not shallow) - not even in 5cefe8d ("remove v2.0 AI/LLM code from public release"), the commit that stripped the closest related feature (WSAIProviderSelect, AI refresh-hours/token-budget numbers). They're leftovers of a pre-release build of the still-unreleased v2.0 AI/local-forecaster branch that a few instances briefly ran. Confirmed dead either way.

Cleanup runs on every setup/reload (not tied to a config-version bump, since affected instances are already on the latest schema) and only touches these two unique IDs for the current config entry - it does not touch any other restored/unavailable entity a user may have legitimately disabled.

2. Fix device_class on the rain-expected sensor

WSRainExpected1h (binary_sensor.ws_rain_expected_1h) used BinarySensorDeviceClass.MOISTURE, which Home Assistant reserves for a current wetness/leak reading, not a forecast flag. No binary sensor device_class fits a forecast prediction, so it's now unset.

3. Make PM ET₀ absence diagnosable

sensor.ws_et0_penman_monteith is gated on enable_solar_forecast but silently never appeared when the sources config had no solar_radiation key. A Repairs issue (et0_pm_unavailable) now explains this and points at the fix (map a solar radiation sensor, or enable the new illuminance fallback from #4).

4. Add a lux -> W/m² fallback source for PM ET₀

New optional "illuminance fallback" toggle (Solar Forecast step of the config/options flow, CONF_ET0_ILLUMINANCE_FALLBACK): when no solar_radiation source is mapped but an illuminance sensor is, derives an approximate solar radiation using the standard ~0.0079 W/m² per lux daylight conversion factor. The resulting sensor.ws_et0_penman_monteith value is tagged with a radiation_source attribute (sensor vs illuminance_estimate) so downstream consumers know it's lower-confidence than a real pyranometer reading. The conversion's real-world error margin (roughly ±25%, varying with sky conditions and sun elevation) is documented in const.py and the README FAQ.

5. Make nowcast staleness visible

binary_sensor.ws_rain_expected_1h depends on _async_fetch_nowcast() (Open-Meteo minutely_15). The coordinator's internal _nowcast_fetched_at is now exposed as nowcast_fetched_at / nowcast_stale attributes on the entity, and the nowcast cache is considered stale once older than 2x the fetch interval.

6. Add a local-only nowcast fallback

When the Open-Meteo nowcast has failed or gone stale (per #5's threshold), binary_sensor.ws_rain_expected_1h now falls back to a rain-expected signal derived from the existing local pressure-trend/Zambretti path (sensor.ws_zambretti_forecast's Z-number -> implied rain probability) instead of just going unavailable. This is coarser than the 15-minute NWP nowcast, so the entity's source attribute is tagged nowcast or local_fallback accordingly. The entity only goes explicitly unavailable when neither a fresh nowcast nor a Zambretti reading exists at all.

Testing

  • tests/test_migration.py::TestOrphanedForecasterCleanup (item 1)
  • tests/test_binary_sensor.py (items 2, 5, 6 - device_class, availability, source/staleness attributes)
  • tests/test_coordinator.py::TestEt0PmUnavailableIssue, TestSolarRadiationForEt0 (items 3, 4)
  • tests/test_coordinator.py::TestComputeNowcast (items 5, 6 - fresh/stale/never-fetched/no-fallback paths)
  • Extracted the inline nowcast block in _compute() into _compute_nowcast() for direct unit testing.
  • Full suite: 454 passed. ruff check / ruff format --check clean.

🤖 Generated with Claude Code

…and add PM ET0 / nowcast diagnostics

- Remove switch.ws_enable_local_forecaster and number.ws_forecaster_learning_rate
  from the entity registry on every setup: leftovers of the unreleased v2.0
  AI/local-forecaster work, confirmed dead (zero code references, no trace in
  git history under those unique_ids either).
- Drop the moisture device_class from binary_sensor.ws_rain_expected_1h; that
  class is reserved for a current wetness/leak reading, not a forecast flag.
- Add a Repairs issue explaining when sensor.ws_et0_penman_monteith silently
  never appears because no solar_radiation source is configured.
- Add an optional illuminance-derived solar radiation fallback for PM ET0,
  tagged via a radiation_source attribute so consumers know it's an estimate.
- Expose nowcast staleness (nowcast_fetched_at / nowcast_stale attributes) on
  binary_sensor.ws_rain_expected_1h, and fall back to a local Zambretti-derived
  rain-expected signal (tagged source: local_fallback) when the Open-Meteo
  nowcast has failed or gone stale, rather than holding a stale value or
  always going unavailable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@kmich
kmich merged commit 6df21fe into main Sep 26, 2026
7 checks passed
@kmich kmich mentioned this pull request Sep 26, 2026
@kmich
kmich deleted the feat/entity-cleanup-nowcast-diagnostics branch October 3, 2026 12:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant