Complete modernization of the Zwift integration: YAML-only sensor: platform config → UI config flow with per-player devices, expanded entities, and zero-touch migration for existing users. Huge thanks to @Maddimax for the lions share of the work here.
Architecture
- Replaced YAML-only setup with a full config-entry/config-flow integration — UI flow fetches your Zwift followees for player selection instead of manually entering IDs.
- Replaced the single shared polling loop with a DataUpdateCoordinator per tracked player — independent intervals (15s default for yourself, 60s for others), auto-speeds to 2s only for players actually online.
- Each tracked player is now a proper HA device (profile link, full-name naming).
New entities
- 17 new diagnostic sensors: total distance, distance climbed, total time, drops, streaks, racing score/category, FTP, weight, height, DOB, age, account creation date, power zone (+name), sport.
- New light (power zone color), number (per-player poll interval), switch (per-player poll on/off), and image (profile picture) entities.
- zwift_ride_on is now available as a device trigger in the automation UI, not just the raw event bus.
Migration
- Existing YAML users migrate automatically on upgrade — no manual config edits needed, for both the original sensor: - platform: zwift format and the newer zwift: format.
- A Repairs notice appears after import so users know the now-inert YAML block can be removed.
- Entity IDs and history are preserved across upgrade (matched by unique ID), including for custom name: configs.
Bug fixes found and fixed during review/testing
- Config flow showed "cannot connect" instead of "already configured" when re-adding an existing account.
- Gradient sensor's unit had regressed from % to an invalid °, breaking long-term statistics on upgrade.
- A legacy update_interval YAML key took down the entire integration (not just the import), silently, on restart.
- Sensor units followed each tracked player's own metric/imperial preference instead of the account owner's — verified against raw API data and the companion app's own behavior that this was wrong.
- Total Distance Climbed was missing a metric suggested-unit, leaving it unconverted for metric users.
- Orphaned "Update" button entities weren't cleaned up for players no longer tracked.
- name: config was silently ignored when generating entity unique IDs, orphaning upgrading users' entity history and creating duplicate devices.