-
v2026.10.12.2 Stable
released this
2026-10-12 14:29:02 +01:00 | 0 commits to master since this releaseRelease v2026.10.12.2
- nMerge branch 'master' of https://git.notexpectedyet.com/notexpectedyet/ha-nvidia-shield
- test(adb-off audit): name the carve-outs, drive the paths the audit names (t25)
- fix(adb): ADB-off is asked by every device path, not inferred from a missing poller (t23)
- fix(intents): an ADB-off entry never scans, and a truncated detail is never believed (t21)
- fix(transport): no stale protocol error, no connect task outliving its entry, honest banners (t20)
- test(intents): the button's uninstalled-app press, with the device's own words (t17)
- test(intents): the real-HA action proof, the README pins and the raised drift floor (t17, part 3)
- feat(intents): the Intents options screen, the seed, the strings and the tests (t17, part 2)
- feat(intents): the registered-intent engine, the buttons and the send_intent action (t17, part 1)
- fix(media_player,config_flow): close the batch review's O2 and O3 (t17)
- feat(intents): discover an app's intents from its activity resolver table (t16)
- feat(remote): the app/activity picker, and a protocol transport that really connects (t15)
- feat(adb_command): selectable target, strict resolution, and a real response (t14)
- docs(intents): plan the intent catalogue and registered actions
- t66: app names on a device that exposes none
- feat(image): opt-in screen capture as an image entity, binary-safe over ADB
- feat(media-player): flatten now-playing into separate attributes and name the tier
- fix(options): edit apps one row per step in a multiline field, and report discovery
- fix(media-player): the browse root carries a real string id (t63)
- chore(release): v2026.10.12 [skip ci]
- docs(installed-apps): the -3 output shape is documented, not observed (t62 nit c)
- chore(ci): run the real-HA config-flow tests and fail on silent skips
- feat(media-player): a switch Receiver is ensured on, and apps leave the browser (t61)
- docs(discovery): the not-observed mark lands in the in-scope module (t62 nit c)
- docs(discovery): precise wording on the watchdog, the empty state, recovery
- docs(discovery): mark the command shapes documented, not observed (t62 nit c)
- test(drift): flag unreachable statements and raise the call-argument floor (t62 F2)
- fix(connection): delete the unreachable duplicated label-drain body (t62 F2)
- fix(discovery): a sweep that could not run is not an answer (t62 F1)
- fix(media-player): ON means no power or playback fact reported (t58 UNIT 0)
- fix(discovery): a cached negative is an answer, not a miss (t57)
- test(discovery): pin that the discovered list is a superset
- docs(readme): the setup menu's rows and the sweep's socket behaviour
- fix(config-flow): the setup menu was unreachable under real HA (t57 UNIT 0a)
- test(discovery): fixtures for the parsers, the bounded sweep and the surfaces
- feat(config-flow,sensor): the discovered apps reach the UI and dashboards (t57)
- feat(discovery): enumerate the apps installed on the Shield (t57)
- fix(connection): a label dump that returned nothing is a FAILED fetch (t57 UNIT 0)
- test(config-flow): drive the menus, pin the tables, probe real HA
- docs(readme): the configure menu, the apps table and the switch receiver
- feat(config-flow): menu of sub-screens on setup and options
- docs(readme): the t55 state ladder and the label tier's retry rule
- docs(sensor): name where the Current App name chain comes from (t55)
- fix(connection): a failed app-label fetch is retried, not cached as a miss (t55)
- fix(media_player): the state ladder is idle/playing/buffering/off; ON means no data (t55)
- feat(media_session): map Android PlaybackState 6 to buffering (t55)
Downloads
-
v2026.10.12 Stable
released this
2026-10-12 09:25:40 +01:00 | 20 commits to master since this releaseRelease v2026.10.12
- docs(installed-apps): the -3 output shape is documented, not observed (t62 nit c)
- chore(ci): run the real-HA config-flow tests and fail on silent skips
- feat(media-player): a switch Receiver is ensured on, and apps leave the browser (t61)
- docs(discovery): the not-observed mark lands in the in-scope module (t62 nit c)
- docs(discovery): precise wording on the watchdog, the empty state, recovery
- docs(discovery): mark the command shapes documented, not observed (t62 nit c)
- test(drift): flag unreachable statements and raise the call-argument floor (t62 F2)
- fix(connection): delete the unreachable duplicated label-drain body (t62 F2)
- fix(discovery): a sweep that could not run is not an answer (t62 F1)
- fix(media-player): ON means no power or playback fact reported (t58 UNIT 0)
- fix(discovery): a cached negative is an answer, not a miss (t57)
- test(discovery): pin that the discovered list is a superset
- docs(readme): the setup menu's rows and the sweep's socket behaviour
- fix(config-flow): the setup menu was unreachable under real HA (t57 UNIT 0a)
- test(discovery): fixtures for the parsers, the bounded sweep and the surfaces
- feat(config-flow,sensor): the discovered apps reach the UI and dashboards (t57)
- feat(discovery): enumerate the apps installed on the Shield (t57)
- fix(connection): a label dump that returned nothing is a FAILED fetch (t57 UNIT 0)
- test(config-flow): drive the menus, pin the tables, probe real HA
- docs(readme): the configure menu, the apps table and the switch receiver
- feat(config-flow): menu of sub-screens on setup and options
- docs(readme): the t55 state ladder and the label tier's retry rule
- docs(sensor): name where the Current App name chain comes from (t55)
- fix(connection): a failed app-label fetch is retried, not cached as a miss (t55)
- fix(media_player): the state ladder is idle/playing/buffering/off; ON means no data (t55)
- feat(media_session): map Android PlaybackState 6 to buffering (t55)
Downloads
-
v2026.10.11.2 Stable
released this
2026-10-11 08:11:36 +01:00 | 47 commits to master since this releaseRelease v2026.10.11.2
- fix(media_player): dedupe source_list case-insensitively (t53 F1)
- fix(media_player): normalize the app directory in one place (t51)
- fix(media_player): keep blank app names out of the source list (t49 F1)
- docs(readme): the app list as sources, the remote command script, current versioning (t47 D)
- feat(remote): optional command script for remote.send_command (t47 B)
- feat(media_player): source list + native select_source from the app list (t47 A)
- fix(config_flow): clearing an entity field no longer fails validation (t47 C)
- docs(readme): the release write-back and the command scripts (t44 3, R2)
- fix(release): notes must not open with the bot commit; guard matches the subject (t44 3b/3c)
- feat(media_player): per-command script overrides (t44)
- test(harness): make the stub scoping independent of file order (t44)
- docs: correct two stale claims about a tier and a red proof (t44 0b/0c)
- fix(config): degrade an unreachable Shield to the pairing form (t44 F1)
- feat(release): same-day versions + manifest write-back so HACS sees every release (t42)
- test(config): pin the Jellyfin name tiers and the address redaction (t41)
- test(ci): sweep every module for dangling imports (t41)
- docs(readme): replacement guide + a verified seed example (t41)
- feat(config): enable both native transports by default (t41)
- feat(config)!: migrate entries to v3 — one address, no androidtv key (t41)
- refactor(config): one Shield IP field for both transports (t41)
- refactor(config): drop the androidtv media_player entity path end-to-end (t41)
- fix(availability): F3 — any usable transport keeps the entities up (t40)
- fix(sensor): F2 — the Current App sensor shows the resolved app name (t40)
- test(ci): F4 — entity-contract pass in the drift sweep + real-HA state-write proof (t40)
- fix(media_player): F1 — extra_state_attributes must be a property (t40 blocker)
Downloads
-
v2026.10.11
Stablereleased this
2026-10-11 05:19:10 +01:00 | 73 commits to master since this releaseRelease v2026.10.11
- docs(readme): record the MAC-less discovery contract (t37 D3, t39)
- fix(drift): F1+F2 — the sweep refuses false greens, and CI provisions the real floor (t39)
- test(ci): D1/D2/D3 — repo-owned HA API-drift sweep with a CI job (t37)
- fix(config_flow): D3 — await the discovery-dedup coroutine (t37)
- fix(diagnostics): D2 — redact through homeassistant.helpers.redact (t37)
- fix(media_player): D1 — browse builds real BrowseMedia nodes, not BrowseMediaSource (t37)
- test(config_flow): prove a reconfigure entry really rebuilds the protocol transport (t35 F1)
- fix(config_flow): F1 — a discoverable later pairing path (Reconfigure) and truthful skip copy (t35 F1/F1b)
- fix(tests): F2 — the voluptuous mirror compares fields, not marker classes (t35)
- test(config_flow): the t33 UX suite — schema-level prefill, skip paths, copy contract, strings parity (t33)
- fix(strings): F-C — plain, self-consistent setup copy for the live-run feedback (t33)
- fix(config_flow): F-B — neither pairing step is a dead end (t33)
- fix(config_flow): F-A/F-A2/F-D — the discovered host and the 5555 port ride the schema KEY defaults (t33)
- ci: survive PEP 668 on externally managed runners — retry the test-tooling install with --break-system-packages, pin the gate tool versions
Downloads
-
v2026.10.10 Stable
released this
2026-10-10 08:31:32 +01:00 | 87 commits to master since this releaseRelease v2026.10.10
- Merge branch 'master' of https://git.notexpectedyet.com/notexpectedyet/ha-nvidia-shield
- fix(init,config_flow): F4 — seed blocks and the import prefill honor the block's shape: ADB only when the block carries an adb host, protocol-only blocks keep adb_enabled off; TestSeedBlockShapeF4 pins all three paths (t32)
- fix(config_flow): F2 — MAC-less zeroconf discovery calls the audited _async_handle_discovery_without_unique_id helper and guards against a same-host duplicate prefill, so re-discovery can't stack entries; the import guard reads entries via the base _async_current_entries helper; TestMacLessDiscoveryF2 pins helper call + one-entry outcome (t32)
- fix(poller): F1 — the poller factory re-reads entry.options at call time (audit-sanctioned option), so the next built poller targets the NEW address after a zeroconf IP change; the stale live-read comment in config_flow points at the actual mechanism; TestIpChangeSelfHealF1 drives an IP change and pins the next poller host (t32)
- fix(diagnostics): hosts join the explicit TO_REDACT list per the audit's G14 citation (t30 G14)
- docs(readme): sensor names follow the translation_key entity naming (t30 G7)
- fix(tests): drop the speculative config-entries install guard — the scoped-stub teardowns already isolate per file; full suite green both variants (completes t30 G6)
- test: cross-file stub-scoping repairs — hub ConfigFlow base carries the full plumbing, standalone rebuilds when its holder is gone, test_init scoped hygiene mirrors scoped_stubs (completes t30 G6)
- test(init): tests/test_init.py lands — domain async_setup units + YAML seed parsing/normalization, flow-init seeding records, hostless drop, duplicate guards (UI host + virtual unique_id) and single-visit interactive routing; scoped stub hygiene mirrors scoped_stubs (t30 G6/U1)
- docs(readme,strings): YAML seed-only semantics documented — interactive flow, duplicate guards, no implicit entry changes on block removal (t30 U1)
- feat:init,config_flow: YAML seed-only setup — an optional nvidia_shield block starts interactive SOURCE_IMPORT flows (parsed in async_setup), the import step guards duplicates by host/MAC-virtual unique_id and never re-seeds UI-configured hosts, protocol fields are prefill hints only (t30 U1)
- feat: standards polish — G7 sensor translation_key naming + entity strings, G10 protocol-push device identity on the registry card, G12 unrecorded poll-driven attributes (media player DAG internals + sensors), G14 async_redact_data with an explicit redaction list behind the marker scan (t30)
- feat(button,media_player): Pair ADB carries entity_category CONFIG (t30 G11) + BrowseMediaSource domain parameter at root and children (t30 G18, 2026-05-20 blog contract); stubs/tests pin both
- feat(icon): HACS-required 256x256 icon.png placeholder, generated (t30 G15)
- feat(manifest): integration_type device + domain loggers adb_shell/androidtvremote2 (t30 G1)
- feat(config_flow): commit the G2 + stub wiring lost in the amend cycle — device-MAC unique_id derivation in the flow, device-registry stubs across the flow suites
- feat(config_flow): the G2 unique_id fix lands — the androidtv entity_id is never a unique_id; MAC derived from the device registry mac connection (empty placeholders skipped), else no unique_id; rename-stability + absence pinned by test (t29 G2)
- fix: commit G3a wiring lost in the amend cycle — listener removal, update-only host path, reauth via the current API (stub surface includes async_update_reload_and_abort)
- fix: the deprecated listener+reload combo is gone — reauth uses async_update_reload_and_abort(_get_reauth_entry()), zeroconf host update is update-only, the init options-reload listener is removed (grep-pinned); host-change tests assert update-without-reload (t29 G3a)
- feat: adb_command is a conforming action — always registered in async_setup (option gates USE), services.yaml with required command/entity, strings services+exceptions, ServiceValidationError on empty/unknown-target/ADB-down; participant registry stays (t29 G8)
- docs: HA standards audit against current developer docs — deprecation gaps G3a/G3b/G8, YAML-import verdict, quality-scale notes (research)
- fix(connection,adb_client): commit the F-NEW1..3 wiring lost in the amend cycle — no-idle-timeout transport budget with in-code rationale, config accessor consumption, wrapped-line buffer
- fix(connection,adb_client): the logcat stream survives quiet windows — transport_timeout_s=None (bulk_read blocks quiet gaps; the ladder + async_stop remain recovery/cleanup), 3-line parse buffer for wrapped cmp records, public poller config accessor replaces the private reach-ins (t27 F-NEW1..3)
- test(media_player): MAC-collision pre-check migration branches — occupied MAC falls back to the entry id, free MAC taken (t26 F4)
- chore(config_flow): replace the stranded self-answering comment in the options editor with a plain statement (t26 F5)
- fix(media_player): unique_id migration pre-checks for an existing entry holding the target MAC — falls back to the config-entry id on collision (t26 F4)
- test(media_player): spied sleep proves a non-default digit delay (0.3 s) reaches the channel sequence — option consumed per digit (t26 F3)
- test(connection): drain beats before label-fetch asserts; label-less negative cache costs one pm dump ever + shlex-quote shape pinned (t26 F1,F2)
- fix(connection,app_labels): negative-cache label-less packages (same 24h TTL, no re-enqueue — kills the per-heartbeat pm dump tax) + shlex.quote the pm dump package argument (t26 F1,F2)
- feat(connection,const,strings): complete the P5-3 logcat consumer wiring lost in an earlier amend — dedicated stream, instant stamp, ladder + auto-disable, default-off toggle strings
- test(media_session,connection): logcat START parsing (cmp=, wrapped records, null/non-START ignored, u-prefixes), instant stamp + notify, duplicate START suppression, 5-in-10-min auto-disable, OFF = no stream task, stream never touches the poller socket (P5-3)
- feat(config_flow,strings): CONF_LOGCAT_EVENTS options toggle (default off, stability-report wording) (P5-3)
- test(entity_stublib): ConfigFlow stub accepts the domain= init_subclass kwarg and load_entity_modules drops config_flow (per-file loader ownership preserved) (completes P5-2 test scaffolding)
- test(config_flow,media_player,remote): digit-delay/send-enter options (store + window/error validation), IME-first text entry with ADB fallback tier, icon column parse/prefill/store (P5-2)
- feat(config_flow): digit-delay (0.05–1.0 s, invalid input error) + optional send-enter options UI consumed by the §7 channel path; strings/README updated (P5-2.1)
- fix(ha_adb_common): application-label regex accepts double-quoted labels too (completes the P5-1 parser tolerance)
- test(ha_adb_common,connection): application-label tolerance (dual quotes, empty multi-label blocks, null, absent) + label cache reuse across cycles — no duplicate pm dump (P5-1)
- test(media_player): entity tier serves below map/manifest per the P5-1 resolution ruling (was map-beats-entity contradiction)
- feat(connection,media_player): on-demand manifest-label cache (≥24h TTL, one pm dump per watchdog cycle via the task pool) + app_name order map > label > entity > raw package (P5-1)
- feat(ha_adb_common): application-label parser — default-locale from pm dump, localized variants skipped, tolerant of empty/multi-label blocks (P5-1)
- fix(media_player): store the computed adb_command participant key on the entity — completes the F4 add/remove key symmetry in the lifecycle hooks
- fix(config_flow): per-host zeroconf updates — blank auto-detect hosts self-heal from the discovery address, a deliberately-different ADB host is never clobbered, same-IP with both hosts current is a no-op (F2)
- fix(media_player): the adb_command participant registry key is computed once at registration and stored on the entity — add/remove always match (F4)
- feat(const,strings,readme): adb_command consts/service name, options toggle strings, curated DEFAULT_APP_DIRECTORY and README service notes (completes P4-2 unit 1)
- feat(media_player): BrowseMedia app directory — root lists the options apps map (curated TiviMate/Wholphin/Netflix/YouTube fallback), selection launches via play_media(app) (P4-2c)
- feat(media_player): option-gated adb_command service (default off; registered at setup, unregistered at last unload, ADB-down rejection) + redacted entry diagnostics (P4-2a,b)
- feat(const,config_flow): option-gated adb_command service switch (default off) + curated app directory consts + README service/security notes (P4-2)
- test(config_flow): zeroconf discovery (pre-fill, no-host abort, IP-change host update, same-IP skip) + apps map editor (store/parse/clear/prefill) + app_name map resolution tiers (P4-1)
- feat(config_flow,media_player): apps name/icon map editor in the options flow (package=name per line, invalid input error) + app_name resolves through CONF_APP_NAME_MAP after the entity/push tiers (P4-1b)
- feat(config_flow): zeroconf discovery step — pre-filled user step from the discovery address, duplicate-MAC abort, IP-change host update + reload for known entries (P4-1a)
- feat(const,manifest): zeroconf service type + CONF_APP_NAME_MAP; manifest declares the _androidtvremote2._tcp discovery dependency (P4-1)
- fix(config_flow): no_state_source fires only when none of the three sources is present — ADB-only standalone is valid; strings/docs name all three (F2)
- fix(media_player): privacy bare-app identity outranks the channel-title fallback in the foreground tier (F3)
- fix(media_player): channel-title fallback gated to the channel app (TIVIMATE_PACKAGE or audio_playback membership) — launcher never shows a channel number (F1)
- docs: state ladder + fallback semantics in README; mediasession2mqtt retirement + universal-player glue appendix in RESEARCH_SHIELD; TiviMate as the documented no-session case (P3-3d)
- feat(media_player): foreground tier in the state ladder with app-source now-playing (last-known → last_channel → audio hint), sensor reads the store's foreground priority chain (P3-3a,c)
- feat(running_apps): media_dag_running_apps enrichment — TTL-capped last_known_state/last_known_title for apps without a live session (P3-3b)
- feat(connection): TTL-filtered last_known_map snapshot of the per-package cache (P3-3b feed)
- test(ha_adb_common): fixture-driven foreground-parser tests — TiviMate capture, R4 launcher, wrap join, topResumed fallback ordering, duplicates tolerated (P3-2a)
- feat(connection): ADB foreground fallback on the watchdog cadence when the protocol push is silent (store priority protocol > ADB); audio-playback hint filtered through SYSTEM_MEDIA_PACKAGES (P3-2b,c)
- feat(ha_adb_common): foreground parser — mResumedActivity primary with block-join for ActivityRecord wraps, topResumedActivity fallback (R4); no window-focus parsing
- feat(media_player): app_id/app_name prefer the androidtv entity, fall back to the protocol current_app push when absent/unavailable; manifest androidtvremote2 floor aligned to >=0.2.0 (P3-1b,c)
- feat(config_flow): standalone setup — androidtv entity optional with no_state_source validation, entry data omits the field for standalone entries, sensor tolerates its absence; migration keeps v1 field / v2 absence valid (P3-1a,d)
- refactor(connection): public protocol_active accessor replaces the remote entity's private reach-in; media_player module docstring describes the Phase 2 architecture (F7)
- fix: flow VERSION=2 for new entries; optional ENTER gains the ADB keyevent-66 fallback; CI installs androidtvremote2 for the real-library tests (F4, F5, F6)
- fix(connection): ADB outage clears only ADB-derived store fields — protocol push truth survives by TTL (F2)
- test: command-routing and play_media(channel) orchestration — digit sequence with cancel guard, fallback ordering protocol→ADB→legacy, remote send_command holds/repeats, volume readout, is_on ladder
- feat(remote): protocol-backed RemoteEntity — SHORT/START_LONG/END_LONG prefixes, num_repeats/delay/hold, activity = current-app push, POWER keys honoring is_on
- feat(media_player): protocol-first command routing with ADB + legacy fallbacks, play_media(channel/app/url) per §7 with digit task-cancel guard, volume readout from protocol push, is_on tier in the power ladder
- feat: protocol key/launch command layer — RemoteKeyCode maps, C-LAUNCH app launch, ADB digit keyevent fallback, PlaybackIntent protocol path
- test(config_flow): protocol cert/PIN pairing, reauth-after-hard-reset, and v1→v2 entry migration (scoped stubs, deterministic PIN/MAC fake client)
- feat: protocol_settings wiring + InvalidAuth reauth start + entry migration to v2; PLATFORMS gains REMOTE (placeholder platform until t10)
- feat(config_flow): remote-protocol cert/PIN pairing step + reauth after device hard reset (shared .storage cert paths; ADB step body byte-intact, routes onward when protocol enabled)
- feat(const): protocol config keys + ports; connection manager generates missing certs before protocol start
- fix(connection): let the library own keep_reconnecting's task — no double scheduling on protocol start/stop
- test(connection): protocol-transport unit tests — push wiring, InvalidAuth reauth hook, lib-owned keep_reconnecting lifecycle, passive paths, volume normalization
- feat(pyproject): androidtvremote2 dev dependency; manager docstring covers both transports
- feat(connection): protocol transport alongside ADB — AndroidTVRemote client, keep_reconnecting ownership, push callbacks into StateStore, InvalidAuth→reauth hook, cert/PIN client factory
- test: sound backoff-jitter assertions (per-delay band + non-overlapping growth) and scoped import-stub teardown in the pairing regression tests (F5 residual)
- fix(media_player): ADB-health-aware _attr_available; fetch_media_info dispatches through _track_task (F2, F4)
- fix(connection): reconnect decision closes the failed socket (health_check's documented role) + symmetric backoff-bound test assertion (F3, F5)
- fix(config_flow): pairing step passes test_connect's declared signature (host, port, key_path) — regression tests cover the adb_pair submit path (F1)
- fix: await the async ADB poller-factory builder during entry setup (keeps setup non-blocking, no ConfigEntryNotReady)
- refactor(sensor): Current App sensor falls back to the connection manager StateStore and refreshes on store updates
- refactor(media_player): entity becomes a thin view over the ShieldConnectionManager store; poll loop and socket removed from the entity
- refactor(config_flow): ADB pairing step reuses ShieldConnectionManager.test_connect (throwaway one-shot connect)
- feat: entry.runtime_data ShieldConnectionManager lifecycle — passive when ADB unavailable, close on HA stop + unload; adb_session adapter docstring
- test(connection): manager unit tests with a fake poller — connect/reconnect backoff, TTL expiry, listeners, lifecycle
- feat(connection): ShieldConnectionManager + StateStore — persistent socket, watchdog backoff reconnect, TTL expiry, listener API (Phase 1, B1/B5)
- feat(const): persistent-connection timing constants — watchdog backoff/cap/jitter, StateStore TTL
- feat(adb_client): expose last_dump so consumers can parse the Audio playback section from the same query
- feat: re-export parse_audio_playback + parse_wakefulness from ha_adb_common (additive, keeps hisense_tv consumer parity)
- test: poll_running_apps parsing against SYNTHETIC activity-recents fixture (A= and I= patterns; real R6 capture still outstanding)
- fix: track intent-retry tasks in the unload-cancelled task registry so removal can't trigger a shell() auto-reconnect (reviewer F2)
- feat(adb_client): exact-value mWakefulness= parse (R5), health_check(), optional media-session truncation (B4); wakefulness fixtures + tests
- docs: fold research findings into plan — streaming_shell verified on pinned adb-shell 0.4.4 (C-STREAM), market://launch auto-prefix (C-LAUNCH), channel_up/down keys
- docs: add RESEARCH_IDEAS.md — community feature requests, androidtvremote2/adb_shell API audits, other-integration patterns, ranked ideas (research task t3)
- feat(media_session): parse PlaybackState position/speed/updated (uptime-ms) + parse_audio_playback section (MVP plan Phase 1, R9/R2)
- docs: correct Phase 2 volume expectations — androidtvremote2 has no absolute volume set (core closed it not_planned); VOLUME_STEP|MUTE only, level from push
- ci: add lint+test workflow; schedule package constants (TiviMate/Wholphin/system media); drop the stale sibling-checkout dev dependency
- refactor: centralize ADB host/key resolution in helpers.py; drop the three duplicated resolvers
- fix: make ADB poll failures visible and stop stale-state cling; cancel tracked poll tasks on unload (B2, B5-prep); lint cleanups across daemon modules
- fix: retry playback intents over the command path that originally served them (ADB broadcasts annotate the intent, self-heal retry goes back over ADB)
- test: add firmware capture fixtures and stdlib-level unit tests for parsers, intents, running apps
Downloads
-
v2026.10.09 Stable
released this
2026-10-09 06:59:23 +01:00 | 107 commits to master since this releaseRelease v2026.10.09
- docs: HA standards audit against current developer docs — deprecation gaps G3a/G3b/G8, YAML-import verdict, quality-scale notes (research)
- fix(connection,adb_client): commit the F-NEW1..3 wiring lost in the amend cycle — no-idle-timeout transport budget with in-code rationale, config accessor consumption, wrapped-line buffer
- fix(connection,adb_client): the logcat stream survives quiet windows — transport_timeout_s=None (bulk_read blocks quiet gaps; the ladder + async_stop remain recovery/cleanup), 3-line parse buffer for wrapped cmp records, public poller config accessor replaces the private reach-ins (t27 F-NEW1..3)
- test(media_player): MAC-collision pre-check migration branches — occupied MAC falls back to the entry id, free MAC taken (t26 F4)
- chore(config_flow): replace the stranded self-answering comment in the options editor with a plain statement (t26 F5)
- fix(media_player): unique_id migration pre-checks for an existing entry holding the target MAC — falls back to the config-entry id on collision (t26 F4)
- test(media_player): spied sleep proves a non-default digit delay (0.3 s) reaches the channel sequence — option consumed per digit (t26 F3)
- test(connection): drain beats before label-fetch asserts; label-less negative cache costs one pm dump ever + shlex-quote shape pinned (t26 F1,F2)
- fix(connection,app_labels): negative-cache label-less packages (same 24h TTL, no re-enqueue — kills the per-heartbeat pm dump tax) + shlex.quote the pm dump package argument (t26 F1,F2)
- feat(connection,const,strings): complete the P5-3 logcat consumer wiring lost in an earlier amend — dedicated stream, instant stamp, ladder + auto-disable, default-off toggle strings
- test(media_session,connection): logcat START parsing (cmp=, wrapped records, null/non-START ignored, u-prefixes), instant stamp + notify, duplicate START suppression, 5-in-10-min auto-disable, OFF = no stream task, stream never touches the poller socket (P5-3)
- feat(config_flow,strings): CONF_LOGCAT_EVENTS options toggle (default off, stability-report wording) (P5-3)
- test(entity_stublib): ConfigFlow stub accepts the domain= init_subclass kwarg and load_entity_modules drops config_flow (per-file loader ownership preserved) (completes P5-2 test scaffolding)
- test(config_flow,media_player,remote): digit-delay/send-enter options (store + window/error validation), IME-first text entry with ADB fallback tier, icon column parse/prefill/store (P5-2)
- feat(config_flow): digit-delay (0.05–1.0 s, invalid input error) + optional send-enter options UI consumed by the §7 channel path; strings/README updated (P5-2.1)
- fix(ha_adb_common): application-label regex accepts double-quoted labels too (completes the P5-1 parser tolerance)
- test(ha_adb_common,connection): application-label tolerance (dual quotes, empty multi-label blocks, null, absent) + label cache reuse across cycles — no duplicate pm dump (P5-1)
- test(media_player): entity tier serves below map/manifest per the P5-1 resolution ruling (was map-beats-entity contradiction)
- feat(connection,media_player): on-demand manifest-label cache (≥24h TTL, one pm dump per watchdog cycle via the task pool) + app_name order map > label > entity > raw package (P5-1)
- feat(ha_adb_common): application-label parser — default-locale from pm dump, localized variants skipped, tolerant of empty/multi-label blocks (P5-1)
- fix(media_player): store the computed adb_command participant key on the entity — completes the F4 add/remove key symmetry in the lifecycle hooks
- fix(config_flow): per-host zeroconf updates — blank auto-detect hosts self-heal from the discovery address, a deliberately-different ADB host is never clobbered, same-IP with both hosts current is a no-op (F2)
- fix(media_player): the adb_command participant registry key is computed once at registration and stored on the entity — add/remove always match (F4)
- feat(const,strings,readme): adb_command consts/service name, options toggle strings, curated DEFAULT_APP_DIRECTORY and README service notes (completes P4-2 unit 1)
- feat(media_player): BrowseMedia app directory — root lists the options apps map (curated TiviMate/Wholphin/Netflix/YouTube fallback), selection launches via play_media(app) (P4-2c)
- feat(media_player): option-gated adb_command service (default off; registered at setup, unregistered at last unload, ADB-down rejection) + redacted entry diagnostics (P4-2a,b)
- feat(const,config_flow): option-gated adb_command service switch (default off) + curated app directory consts + README service/security notes (P4-2)
- test(config_flow): zeroconf discovery (pre-fill, no-host abort, IP-change host update, same-IP skip) + apps map editor (store/parse/clear/prefill) + app_name map resolution tiers (P4-1)
- feat(config_flow,media_player): apps name/icon map editor in the options flow (package=name per line, invalid input error) + app_name resolves through CONF_APP_NAME_MAP after the entity/push tiers (P4-1b)
- feat(config_flow): zeroconf discovery step — pre-filled user step from the discovery address, duplicate-MAC abort, IP-change host update + reload for known entries (P4-1a)
- feat(const,manifest): zeroconf service type + CONF_APP_NAME_MAP; manifest declares the _androidtvremote2._tcp discovery dependency (P4-1)
- fix(config_flow): no_state_source fires only when none of the three sources is present — ADB-only standalone is valid; strings/docs name all three (F2)
- fix(media_player): privacy bare-app identity outranks the channel-title fallback in the foreground tier (F3)
- fix(media_player): channel-title fallback gated to the channel app (TIVIMATE_PACKAGE or audio_playback membership) — launcher never shows a channel number (F1)
- docs: state ladder + fallback semantics in README; mediasession2mqtt retirement + universal-player glue appendix in RESEARCH_SHIELD; TiviMate as the documented no-session case (P3-3d)
- feat(media_player): foreground tier in the state ladder with app-source now-playing (last-known → last_channel → audio hint), sensor reads the store's foreground priority chain (P3-3a,c)
- feat(running_apps): media_dag_running_apps enrichment — TTL-capped last_known_state/last_known_title for apps without a live session (P3-3b)
- feat(connection): TTL-filtered last_known_map snapshot of the per-package cache (P3-3b feed)
- test(ha_adb_common): fixture-driven foreground-parser tests — TiviMate capture, R4 launcher, wrap join, topResumed fallback ordering, duplicates tolerated (P3-2a)
- feat(connection): ADB foreground fallback on the watchdog cadence when the protocol push is silent (store priority protocol > ADB); audio-playback hint filtered through SYSTEM_MEDIA_PACKAGES (P3-2b,c)
- feat(ha_adb_common): foreground parser — mResumedActivity primary with block-join for ActivityRecord wraps, topResumedActivity fallback (R4); no window-focus parsing
- feat(media_player): app_id/app_name prefer the androidtv entity, fall back to the protocol current_app push when absent/unavailable; manifest androidtvremote2 floor aligned to >=0.2.0 (P3-1b,c)
- feat(config_flow): standalone setup — androidtv entity optional with no_state_source validation, entry data omits the field for standalone entries, sensor tolerates its absence; migration keeps v1 field / v2 absence valid (P3-1a,d)
- refactor(connection): public protocol_active accessor replaces the remote entity's private reach-in; media_player module docstring describes the Phase 2 architecture (F7)
- fix: flow VERSION=2 for new entries; optional ENTER gains the ADB keyevent-66 fallback; CI installs androidtvremote2 for the real-library tests (F4, F5, F6)
- fix(connection): ADB outage clears only ADB-derived store fields — protocol push truth survives by TTL (F2)
- test: command-routing and play_media(channel) orchestration — digit sequence with cancel guard, fallback ordering protocol→ADB→legacy, remote send_command holds/repeats, volume readout, is_on ladder
- feat(remote): protocol-backed RemoteEntity — SHORT/START_LONG/END_LONG prefixes, num_repeats/delay/hold, activity = current-app push, POWER keys honoring is_on
- feat(media_player): protocol-first command routing with ADB + legacy fallbacks, play_media(channel/app/url) per §7 with digit task-cancel guard, volume readout from protocol push, is_on tier in the power ladder
- feat: protocol key/launch command layer — RemoteKeyCode maps, C-LAUNCH app launch, ADB digit keyevent fallback, PlaybackIntent protocol path
- test(config_flow): protocol cert/PIN pairing, reauth-after-hard-reset, and v1→v2 entry migration (scoped stubs, deterministic PIN/MAC fake client)
- feat: protocol_settings wiring + InvalidAuth reauth start + entry migration to v2; PLATFORMS gains REMOTE (placeholder platform until t10)
- feat(config_flow): remote-protocol cert/PIN pairing step + reauth after device hard reset (shared .storage cert paths; ADB step body byte-intact, routes onward when protocol enabled)
- feat(const): protocol config keys + ports; connection manager generates missing certs before protocol start
- fix(connection): let the library own keep_reconnecting's task — no double scheduling on protocol start/stop
- test(connection): protocol-transport unit tests — push wiring, InvalidAuth reauth hook, lib-owned keep_reconnecting lifecycle, passive paths, volume normalization
- feat(pyproject): androidtvremote2 dev dependency; manager docstring covers both transports
- feat(connection): protocol transport alongside ADB — AndroidTVRemote client, keep_reconnecting ownership, push callbacks into StateStore, InvalidAuth→reauth hook, cert/PIN client factory
- test: sound backoff-jitter assertions (per-delay band + non-overlapping growth) and scoped import-stub teardown in the pairing regression tests (F5 residual)
- fix(media_player): ADB-health-aware _attr_available; fetch_media_info dispatches through _track_task (F2, F4)
- fix(connection): reconnect decision closes the failed socket (health_check's documented role) + symmetric backoff-bound test assertion (F3, F5)
- fix(config_flow): pairing step passes test_connect's declared signature (host, port, key_path) — regression tests cover the adb_pair submit path (F1)
- fix: await the async ADB poller-factory builder during entry setup (keeps setup non-blocking, no ConfigEntryNotReady)
- refactor(sensor): Current App sensor falls back to the connection manager StateStore and refreshes on store updates
- refactor(media_player): entity becomes a thin view over the ShieldConnectionManager store; poll loop and socket removed from the entity
- refactor(config_flow): ADB pairing step reuses ShieldConnectionManager.test_connect (throwaway one-shot connect)
- feat: entry.runtime_data ShieldConnectionManager lifecycle — passive when ADB unavailable, close on HA stop + unload; adb_session adapter docstring
- test(connection): manager unit tests with a fake poller — connect/reconnect backoff, TTL expiry, listeners, lifecycle
- feat(connection): ShieldConnectionManager + StateStore — persistent socket, watchdog backoff reconnect, TTL expiry, listener API (Phase 1, B1/B5)
- feat(const): persistent-connection timing constants — watchdog backoff/cap/jitter, StateStore TTL
- feat(adb_client): expose last_dump so consumers can parse the Audio playback section from the same query
- feat: re-export parse_audio_playback + parse_wakefulness from ha_adb_common (additive, keeps hisense_tv consumer parity)
- test: poll_running_apps parsing against SYNTHETIC activity-recents fixture (A= and I= patterns; real R6 capture still outstanding)
- fix: track intent-retry tasks in the unload-cancelled task registry so removal can't trigger a shell() auto-reconnect (reviewer F2)
- feat(adb_client): exact-value mWakefulness= parse (R5), health_check(), optional media-session truncation (B4); wakefulness fixtures + tests
- docs: fold research findings into plan — streaming_shell verified on pinned adb-shell 0.4.4 (C-STREAM), market://launch auto-prefix (C-LAUNCH), channel_up/down keys
- docs: add RESEARCH_IDEAS.md — community feature requests, androidtvremote2/adb_shell API audits, other-integration patterns, ranked ideas (research task t3)
- feat(media_session): parse PlaybackState position/speed/updated (uptime-ms) + parse_audio_playback section (MVP plan Phase 1, R9/R2)
- docs: correct Phase 2 volume expectations — androidtvremote2 has no absolute volume set (core closed it not_planned); VOLUME_STEP|MUTE only, level from push
- ci: add lint+test workflow; schedule package constants (TiviMate/Wholphin/system media); drop the stale sibling-checkout dev dependency
- refactor: centralize ADB host/key resolution in helpers.py; drop the three duplicated resolvers
- fix: make ADB poll failures visible and stop stale-state cling; cancel tracked poll tasks on unload (B2, B5-prep); lint cleanups across daemon modules
- fix: retry playback intents over the command path that originally served them (ADB broadcasts annotate the intent, self-heal retry goes back over ADB)
- test: add firmware capture fixtures and stdlib-level unit tests for parsers, intents, running apps
Downloads
-
v2026.10.08
StableRelease / release (push) Successful in 5sreleased this
2026-10-08 07:32:57 +01:00 | 191 commits to master since this releaseRelease v2026.10.08
- docs: README — drop mirror-job references after .gitea workflow rework
- ci: streamline Gitea release workflow under .gitea/ (GITEA_TOKEN, concurrency, no HACS mirror job)
- docs: rewrite README for the Shield-only fork
- chore: adopt date-based versioning; point manifest metadata at the Gitea repo
- ci: release on every push to master with date-based versioning (vYYYY.MM.DD)
- ci: port release workflow to Gitea Actions (tag + release zip, optional HACS GitHub mirror)
- docs: add MVP plan and Shield firmware research findings
Downloads