Commit Graph
2 Commits
Author SHA1 Message Date
James Mackay ef42682250 fix(media-player): ON means no power or playback fact reported (t58 UNIT 0)
The t59 F2 ruling, implemented. The ladder said ON was for "no source reported
anything at all" but tested for something looser — no transport data — so a
source that ANSWERED "not playing" still fell through to ON. A source that
answers is not a source that is silent, and `on` is the "we cannot know" state.

The ladder now tracks an explicit `reported` flag, set by every source that gave
us a power or playback fact, and the last tier is `IDLE if reported else ON`.
Each case the ruling names now lands on IDLE:

  * a configured Jellyfin entity in ANY state — idle, off, standby, unavailable,
    or even absent from the state machine. It reports "not playing" without an
    early return, so a silent Jellyfin still cannot mask a live media session
    below it (both directions pinned);
  * a live media session that carries no playback flag — the app publishes a
    session but is not playing, paused or buffering;
  * a bare foreground app: either transport's answer counts (the protocol's
    current_app push or the ADB mResumedActivity parse);
  * a configured power entity, whatever it currently says;
  * protocol is_on / ADB awake, plugged or not.

`on` survives only for an entry where none of those exists. The t55 rules are
untouched: an off power entity still outranks a playing session, and no source
may mask playing/paused/buffering.

The module docstring's tier 6, the `state` docstring and the README's ladder
(moving "no data" to the precise wording) all say the same thing now, and the
README's one-line state table was aligned with it.

RED PROOF (the new tests against the parent tree): five of the reporting cases
read `on` where they must read `idle` — `assert 'on' == 'idle'` — plus the
"ON is unreachable with any source configured" shape test.

SIMULATED vs EXECUTED: no real Shield was available, so these are the documented
source shapes, not captures; the state=6 → buffering mapping stays marked
inferred. No browser exists either, so the README pins are textual and the
production behaviour is exercised against real HA's state machine in
tests/test_ha_api_drift.py.
2026-10-12 08:04:06 +01:00
James Mackay 151c49a0da docs(readme): replacement guide + a verified seed example (t41)
The README now answers the question a migrator actually has: what do I delete,
and what covers it afterwards.

* a new "Replacing androidtv / androidtv_remote + the glue" section: the
  back-up → remove-the-platform-YAML → remove-mediasession2mqtt → delete the old
  integrations → add this one → update automations checklist, plus a table
  mapping every retired piece to what serves it now. It notes that Wholphin
  publishes no MediaSession of its own and gets its now-playing from the ADB
  media session, so no bridge is needed for it either;
* the setup steps describe the real flow (name + one address, both transports on
  by default, ADB pairing then PIN pairing, each with a skip);
* the YAML seed section carries a complete, copy-pasteable block. It documents
  ONLY the keys `_yaml_seed_blocks` honours (name, host, adb_port, adb_enabled,
  and the still-accepted protocol_host/adb_host) and says explicitly that the
  rest lives on the Configure page — an example that lists ignored keys is worse
  than no example;
* the state-ladder section, the discovery bullet and the options list follow the
  two-transport, one-address reality.

`tests/test_readme.py` pins the doc/code contract: the example's keys are a
subset of what the seed reads, the example uses the current `host` key, and the
guide keeps naming the retired integrations and glues.

Verified: 326 passed / 2 skipped, ruff clean.
2026-10-11 06:21:40 +01:00