SWS-12500-custom-component/custom_components/sws12500
SchiZzA 0400a9cdee feat(migration): adopt predecessor integration entities, keeping history
The integration is moving to a new repository under a new domain. Home Assistant
keys recorder history and long-term statistics on entity_id, not on the domain,
so the move is free provided the registry entries are carried over instead of
recreated. A recreated entity gets a fresh entity_id and its history is orphaned.

predecessor.py does the carry-over with async_update_entity_platform, which
rewrites platform and config_entry_id and leaves entity_id alone. Everything the
user set by hand rides along, because the registry row itself survives: renames,
icons, areas, labels, categories, hidden and disabled state.

Guards, each one covered by a test that fails when it is removed:

- The startup placeholder state (unavailable + ATTR_RESTORED) is cleared first,
  because async_update_entity_platform accepts only a missing or unknown state.
- A state that is not a placeholder means an integration is still driving the
  entity, so it is refused rather than moved out from under a live platform.
- A unique_id already taken under our own domain is refused. Home Assistant does
  not check this itself: the duplicate guard in _async_update_entity only runs
  when new_unique_id is passed.
- Devices are repointed before the old entry is removed. A device that loses its
  last config entry is deleted, and that takes its entities with it.
- The old config entry is removed only when every entity made it across.
  Otherwise it stays, a retry stays possible, and nothing is lost.

Options are inherited in a separate, earlier pass. Adopting the registry alone
is not enough: SENSORS_TO_LOAD decides which entities the platform creates, so
an empty one leaves every adopted entry showing "no longer provided" until a
payload arrives, and derived sensors are never in a payload at all. The merge is
predecessor-fills-gaps, so anything just entered in the config flow wins. The
version 1 spelling of the Pocasi Meteo flag is translated on the way in, since
async_migrate_entry runs against this entry's own version and would never look
at a key copied in afterwards.

The two passes run at different points in async_setup_entry. Options first,
before the coordinator and routes read them, or an inherited WSLINK flag would
leave the entry listening on the wrong endpoint until a reload. Adoption after
the routes are proven but before async_forward_entry_setups, so the one
destructive step cannot run in a setup that then fails, and so our platforms
bind to the adopted registry entries rather than to freshly created ones.

Two problems the migration surfaced, fixed here as well:

- register_path now catches ValueError alongside RuntimeError and raises
  ConfigEntryNotReady with a message naming HACS. aiohttp rejects a duplicate
  route name with ValueError, and the route names are fixed rather than
  domain-scoped, so a user who has not yet removed the old version hit an
  unhandled traceback.
- add_new_sensors applies the derived-sensor expansion that async_setup_entry
  already applied. Derived sensors are computed, never sent, so discovery can
  only offer their inputs; the azimut unlocked by a newly discovered wind
  direction went missing until the next restart. Only the sensors this batch
  unlocks are added, so nothing is created twice.

PREDECESSOR_DOMAIN equals DOMAIN for now, which short-circuits the whole pass.
It stays correct until the day the domain changes.
2026-07-26 22:08:01 +02:00
..
translations fix(review): persist WSLink probe types and harden flag parsing 2026-07-26 15:41:30 +02:00
__init__.py feat(migration): adopt predecessor integration entities, keeping history 2026-07-26 22:08:01 +02:00
battery_sensors.py fix(review): persist WSLink probe types and harden flag parsing 2026-07-26 15:41:30 +02:00
battery_sensors_def.py feat(wslink): implement every sensor the WSLink API v0.6 defines 2026-07-26 15:20:07 +02:00
binary_sensor.py fix(document): Drop stale WSLink TODO preamble, refresh binary sensor docs 2026-07-26 16:28:05 +02:00
config_flow.py fix(review): parse battery flags via to_int, release routes on removal 2026-07-26 15:53:03 +02:00
conflicts.py fix: block enabling legacy and Ecowitt protocols together 2026-07-25 21:47:53 +02:00
const.py feat(migration): adopt predecessor integration entities, keeping history 2026-07-26 22:08:01 +02:00
coordinator.py fix(review): persist WSLink probe types and harden flag parsing 2026-07-26 15:41:30 +02:00
data.py fix(review): persist WSLink probe types and harden flag parsing 2026-07-26 15:41:30 +02:00
diagnostics.py fix(security)+i18n: stop health-attribute leak, mask secrets in logs, sync translations 2026-07-25 21:47:52 +02:00
ecowitt.py fix: address remaining review findings across forwarders and utils 2026-07-25 21:47:54 +02:00
health_coordinator.py fix(document): Refresh runtime route docs 2026-07-26 12:03:37 +02:00
health_sensor.py feat(device): merge all entities into one shared device with station-type model 2026-07-25 21:47:53 +02:00
icons.json Refactor SWS12500 integration for push-based updates 2026-07-25 21:45:07 +02:00
legacy.py fix: address remaining review findings across forwarders and utils 2026-07-25 21:47:54 +02:00
manifest.json chore(quality): manifest keys, ConfigEntryNotReady, remove dead sqlite code 2026-07-25 21:47:52 +02:00
pocasti_cz.py fix(review): parse battery flags via to_int, release routes on removal 2026-07-26 15:53:03 +02:00
predecessor.py feat(migration): adopt predecessor integration entities, keeping history 2026-07-26 22:08:01 +02:00
routes.py fix(review): parse battery flags via to_int, release routes on removal 2026-07-26 15:53:03 +02:00
sensor.py feat(migration): adopt predecessor integration entities, keeping history 2026-07-26 22:08:01 +02:00
sensors_common.py feat(wslink): implement every sensor the WSLink API v0.6 defines 2026-07-26 15:20:07 +02:00
sensors_weather.py fix: address review findings across forwarders and helpers 2026-07-25 21:47:51 +02:00
sensors_wslink.py feat(wslink): implement every sensor the WSLink API v0.6 defines 2026-07-26 15:20:07 +02:00
staleness.py Add stall sensor detection. 2026-07-25 21:47:50 +02:00
strings.json fix(review): persist WSLink probe types and harden flag parsing 2026-07-26 15:41:30 +02:00
utils.py fix(review): parse battery flags via to_int, release routes on removal 2026-07-26 15:53:03 +02:00
windy_func.py fix(review): stop counting timeouts, notify on disable, drop WSLink indoor 2026-07-26 13:25:39 +02:00