PyLoxone-Audio 0.1.0__tar.gz → 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyloxone_audio-0.1.1/API.md +123 -0
- pyloxone_audio-0.1.1/DIAGNOSTICS.md +203 -0
- pyloxone_audio-0.1.1/EXACT-TRACK-RETURN.md +94 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/MANIFEST.in +4 -0
- pyloxone_audio-0.1.1/NATIVE-MODES.md +96 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/NOTICE.md +7 -5
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/PKG-INFO +56 -18
- pyloxone_audio-0.1.1/POSITION-RESTORE.md +99 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/PyLoxone_Audio.egg-info/PKG-INFO +56 -18
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/PyLoxone_Audio.egg-info/SOURCES.txt +10 -1
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/README.md +55 -17
- pyloxone_audio-0.1.1/SPOTIFY.md +102 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyloxone_audio/__init__.py +11 -15
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyloxone_audio/catalogue.py +37 -1
- pyloxone_audio-0.1.1/pyloxone_audio/diagnostic_events.py +276 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyloxone_audio/metadata.py +12 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyloxone_audio/native.py +166 -17
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyloxone_audio/selection.py +7 -45
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyloxone_audio/sources.py +124 -29
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyproject.toml +1 -1
- pyloxone_audio-0.1.1/tests/library/test_audio_modes.py +301 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_boundary_qualification.py +1 -47
- pyloxone_audio-0.1.1/tests/library/test_diagnostic_events.py +178 -0
- pyloxone_audio-0.1.1/tests/library/test_diagnostic_wire.py +105 -0
- pyloxone_audio-0.1.1/tests/library/test_exact_track_start.py +67 -0
- pyloxone_audio-0.1.1/tests/library/test_portable_policies.py +12 -0
- pyloxone_audio-0.1.1/tests/library/test_restore_readiness.py +191 -0
- pyloxone_audio-0.1.0/API.md +0 -86
- pyloxone_audio-0.1.0/SPOTIFY.md +0 -260
- pyloxone_audio-0.1.0/pyloxone_audio/spotify.py +0 -88
- pyloxone_audio-0.1.0/tests/library/test_portable_policies.py +0 -33
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/LICENSE +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/PyLoxone_Audio.egg-info/dependency_links.txt +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/PyLoxone_Audio.egg-info/requires.txt +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/PyLoxone_Audio.egg-info/top_level.txt +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyloxone_audio/announcement.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyloxone_audio/clock.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyloxone_audio/models.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyloxone_audio/py.typed +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/pyloxone_audio/radio.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/setup.cfg +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/conftest.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/fixtures/audioserver/README.md +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/fixtures/audioserver/sebastian_alarm_end.txt +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/fixtures/audioserver/sebastian_loxone_radio.json +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/fixtures/audioserver/sebastian_tts.json +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/fixtures/audioserver/sebastian_tunein.json +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/pytest.ini +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_audioserver_announcement.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_audioserver_connection.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_audioserver_events.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_audioserver_library_source.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_audioserver_metadata.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_audioserver_playback.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_audioserver_seek.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_audioserver_timing.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_audioserver_wire.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_boundary_environment.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_boundary_ownership.py +0 -0
- {pyloxone_audio-0.1.0 → pyloxone_audio-0.1.1}/tests/library/test_distribution_dependencies.py +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# PyLoxone-Audio 0.1.1 — API and compatibility
|
|
2
|
+
|
|
3
|
+
A separately installable Apache-2.0 Python library containing the concrete native
|
|
4
|
+
audio implementation used by one existing PyLoxone integration. This is not a
|
|
5
|
+
second integration, new login, facade-only prototype or claim of upstream automatic
|
|
6
|
+
adoption. Public availability is verified separately by the release production gate. See NOTICE.md for attribution/provenance.
|
|
7
|
+
|
|
8
|
+
## Concrete public API and ownership
|
|
9
|
+
|
|
10
|
+
The explicit exports in pyloxone_audio/__init__.py are the public API:
|
|
11
|
+
|
|
12
|
+
- AudioServerCommands(host, current_credentials) owns bounded native command
|
|
13
|
+
authentication, correlation, cancellation, close and uncertain-write fences.
|
|
14
|
+
The callback supplies the current username/token; there is no token persistence.
|
|
15
|
+
- AudioServerListener and AudioEventReceiver receive/parse exact-player metadata;
|
|
16
|
+
AudioZoneMetadata is the neutral snapshot. AudioMetadataCoordinator supports
|
|
17
|
+
exact-player subscriptions, optional host task scheduling, start and awaited stop.
|
|
18
|
+
- AudioCatalogue(commands, player_id), CatalogueTarget, ConfiguredSource and
|
|
19
|
+
AudioFavourite own discovery, opaque browser targets, last-good source history,
|
|
20
|
+
configured favourites, provider/account qualification and neutral search values.
|
|
21
|
+
- MediaNode, SearchResult and MediaKind contain no HA entity or UI dependency.
|
|
22
|
+
- async_select_catalogue, async_select_favourite, async_select_radio_station and
|
|
23
|
+
async_native_catalogue_noop own source dispatch, settlement and fresh exact-room
|
|
24
|
+
provider feedback. Browser selection remains strict exact-item proof. Source
|
|
25
|
+
return for a saved exact item requires matching track feedback, and may attempt
|
|
26
|
+
at most one optional best-effort position restore after bounded seek readiness. Optional failure does not
|
|
27
|
+
undo confirmed playback; a fixed warning is emitted, never exception payloads.
|
|
28
|
+
- async_source_route owns native/retained routing and safety decisions; SourceRoute
|
|
29
|
+
and SourceContentRequiredError describe its outcomes. Hosts provide lifecycle/
|
|
30
|
+
newest-request liveness callbacks and snapshot bootstrap. There is no HA-provider
|
|
31
|
+
bridge callback. Native identity checks, uncertain-write fences and cancellation
|
|
32
|
+
remain; no blind replay/retry or substitute content is introduced.
|
|
33
|
+
- manual_seek_supported, manual_seek_position, native_track_identity,
|
|
34
|
+
ManualSeekQualification and async_seek_track retain strict current-track/manual
|
|
35
|
+
seek capability, account/identity, echo and observed-progress qualification.
|
|
36
|
+
- passive_history_eligible and confirmed_library_session own reusable native
|
|
37
|
+
history eligibility. Genuine ordered observed feedback is distinct from intent.
|
|
38
|
+
- async_send_prepared_announcement handles prepared bounded WAV bytes through
|
|
39
|
+
the native event operation; the host supplies an existing lazy HTTP session.
|
|
40
|
+
- audioserver_uri and parse_audio_events retain their concrete native semantics.
|
|
41
|
+
|
|
42
|
+
SourceEnvironment(clock=callable) is immutable per-consumer clock configuration.
|
|
43
|
+
Pass environment= to source/seek/routing functions when injecting a clock.
|
|
44
|
+
The callable must return aware UTC datetimes in the metadata.received_at domain.
|
|
45
|
+
The default is the library's aware UTC clock, not HA or another consumer's state.
|
|
46
|
+
Its async_observed_change method executes the concrete native settlement algorithm;
|
|
47
|
+
asyncio deadlines remain monotonic. No process-wide clock replacement is required.
|
|
48
|
+
|
|
49
|
+
The host retains HA setup/entities/registries/services, newest-request tasks and
|
|
50
|
+
unload cancellation, existing native authentication, error translation, artwork and
|
|
51
|
+
HA media/TTS preparation. It must keep liveness checks valid across awaits, drain
|
|
52
|
+
owned tasks before teardown and close commands before metadata/token owners.
|
|
53
|
+
ManualSeekQualification must be checked against actual current native metadata
|
|
54
|
+
and the host revision/duration, not merely a cached UI value. Optional native
|
|
55
|
+
completion requires settled dispatch and fresh exact-room/provider/account proof.
|
|
56
|
+
|
|
57
|
+
## Native modes
|
|
58
|
+
|
|
59
|
+
`AudioRepeatMode` (OFF=0, ALL=1, ONE=3) and `audio_mode_supported` are public
|
|
60
|
+
HA-independent exports. `AudioZoneMetadata` adds nullable `shuffle`, typed
|
|
61
|
+
`repeat` and connection-qualified `shuffle_switch_supported` state.
|
|
62
|
+
`AudioServerCommands.async_set_shuffle(player_id, bool, *, is_current=...)` and
|
|
63
|
+
`async_set_repeat(player_id, AudioRepeatMode, *, is_current=...)` send exactly one
|
|
64
|
+
explicit native player request through existing authentication/serialization and
|
|
65
|
+
strictly validate its reply. The host qualifies fresh native permissions/state
|
|
66
|
+
and maintains its liveness callback; no Spotify bridge/API or optimistic metadata
|
|
67
|
+
write is involved. See [NATIVE-MODES.md](NATIVE-MODES.md) for firmware, partial
|
|
68
|
+
repeat capability, standard HA mapping and unknown/lifecycle semantics.
|
|
69
|
+
|
|
70
|
+
## Optional structured diagnostics (new 0.1.1 increment)
|
|
71
|
+
|
|
72
|
+
`pyloxone_audio.diagnostic_events` defines the version1 fixed-field schema,
|
|
73
|
+
`DiagnosticEmitter`, `diagnostics_enabled` and exception-isolating
|
|
74
|
+
`diagnostic_event`. `AudioServerCommands(..., diagnostics=None)` and
|
|
75
|
+
`AudioMetadataCoordinator.diagnostics` accept an optional observer. Its `enabled`
|
|
76
|
+
must be literally true; its synchronous `emit(stage, **fields)` must only enqueue,
|
|
77
|
+
never await/write files. Callers gate detailed construction before invoking it.
|
|
78
|
+
The emitter allowlists fields/routes and keyed pseudonyms before calling its sink.
|
|
79
|
+
Foreign observer exceptions are isolated. Authentication data never enters events.
|
|
80
|
+
|
|
81
|
+
The HA adapter supplies `EntryAudioDiagnostics`/`RollingJournal`, one diagnostic
|
|
82
|
+
switch and the existing admin config-entry download. These are host internals,
|
|
83
|
+
not a portable HA/storage dependency or a second integration. Separate HA Store
|
|
84
|
+
preference/salt avoids reload-on-options. See [DIAGNOSTICS.md](DIAGNOSTICS.md) for
|
|
85
|
+
the supported enable/export workflow, exact bounds and evidence/privacy limits.
|
|
86
|
+
|
|
87
|
+
This narrowly supersedes the earlier blanket instrumentation exclusion. The old
|
|
88
|
+
`pyloxone_audio.diagnostics`, `SourceDiagnostics`, `trace_source_action`, raw
|
|
89
|
+
snapshot logging and `last_source_failure` API remain removed, not compatibility
|
|
90
|
+
stubs. No source/playback, authentication, fence, clock or retry policy changes.
|
|
91
|
+
|
|
92
|
+
## Tested boundary and installation
|
|
93
|
+
|
|
94
|
+
Only the canonical Python 3.14.7 / HA 2026.9.1 / websockets 15.0.1 /
|
|
95
|
+
pycryptodome 4.0.1 / aiohttp 3.14.3 environment is exercised here. The metadata
|
|
96
|
+
requires Python >=3.14 but is not a wider tested compatibility promise. HA-free
|
|
97
|
+
portable runs explicitly reject HA imports. External I/O in tests is synthetic;
|
|
98
|
+
AF_UNIX wire tests use actual websocket/crypto implementations with TCP blocked.
|
|
99
|
+
No all-version/firmware/room or universal physical playback claim follows from these tests.
|
|
100
|
+
|
|
101
|
+
For Python consumers, install the public named pin `PyLoxone-Audio==0.1.1` in a
|
|
102
|
+
supported isolated environment. The release production gate checks both public
|
|
103
|
+
wheel and sdist resolution, dependencies, imports and runtime identity. A local
|
|
104
|
+
`--no-deps` wheel installation is only an artifact test, not public resolution.
|
|
105
|
+
The matching host manifest pins that version while retaining domain `loxone`,
|
|
106
|
+
name PyLoxone and integration version 0.10.2. For HA, use the complete matching
|
|
107
|
+
adapter/preview and normal host dependency handling, not a manual live pip step.
|
|
108
|
+
|
|
109
|
+
The matching library and adapter passed independent source and exact-wheel review, and the common pair was installed on Home Assistant OS (Core 2026.10.4, Python 3.14.9). On 28 October 2026 the owner accepted two normal-use Local Library → Spotify returns to the same track near its saved position, supported by integration command and native content/position feedback. This is one-room confirmation, not all-room acoustic, whole-queue, persistent shuffle or restart-recovery proof.
|
|
110
|
+
|
|
111
|
+
For public availability, use the matching GitHub release, PyPI version and release verification receipts. Source, tag or uploader success alone is not the production gate. Existing Home Assistant installations do not automatically update.
|
|
112
|
+
|
|
113
|
+
## Intentional 0.1.1 retirement
|
|
114
|
+
|
|
115
|
+
The optional SpotifySessionBridge, SpotifyNativeSession,
|
|
116
|
+
NativeSessionUnavailableError, NativeResumeOutcome, async_optional_native_resume
|
|
117
|
+
and async_resume_native_session API and its bridge parameter are removed together
|
|
118
|
+
with the HA-only controller. Consumers using those optional interfaces must update
|
|
119
|
+
alongside the matching 0.1.1 adapter pin; no compatibility facade silently retains
|
|
120
|
+
provider access. The native command/authentication/metadata/Browse/manual-seek API
|
|
121
|
+
remains. previous_source_labels is the room-local playable-content view; configured
|
|
122
|
+
presence is still source_descriptors, not evidence of selected/played content.
|
|
123
|
+
See SPOTIFY.md and POSITION-RESTORE.md for the current function map and limits.
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Opt-in audio diagnostics — 0.1.1
|
|
2
|
+
|
|
3
|
+
This feature is part of the matching PyLoxone 0.10.2 adapter and PyLoxone-Audio
|
|
4
|
+
0.1.1 release pair, not the older 0.1.0 release. Installing the wheel alone does
|
|
5
|
+
not add the Home Assistant switch. The matching pair has been privately installed
|
|
6
|
+
on HAOS (Core 2026.10.4, Python 3.14.9); owner-enabled collection and a downloaded
|
|
7
|
+
diagnostic report have been observed. This is not public availability, upstream
|
|
8
|
+
approval, a universal UI/device test or a physical playback repair.
|
|
9
|
+
|
|
10
|
+
The final same-track/native-mode pair has completed independent review and
|
|
11
|
+
common private adoption. The owner subsequently accepted two one-room returns
|
|
12
|
+
with supporting saved-session, exact command, content and position feedback.
|
|
13
|
+
That is bounded confirmation, not all-room acoustic or queue proof.
|
|
14
|
+
|
|
15
|
+
Defaults, switch preferences, retention, storage/export bounds and schema version1
|
|
16
|
+
remain unchanged. Its narrowly extended allowlist records native aliased
|
|
17
|
+
`shuffle/enable|disable`, `repeat/0|1|3`, standard HA `shuffle_set`/`repeat_set`
|
|
18
|
+
requests and validated feedback fields `shuffle` (literal boolean) and `repeat`
|
|
19
|
+
(`off|all|one`). Unknown mode fields are omitted, never inferred as off; malformed
|
|
20
|
+
routes/enums/booleans remain rejected. A command reply is not physical acceptance.
|
|
21
|
+
No raw mode payload, credential or provider state is exported.
|
|
22
|
+
During a bounded readiness wait, `seek_unsupported` is a
|
|
23
|
+
current decision, not proof the source can never seek. A later `eligible` requires
|
|
24
|
+
positive capability on the same valid target; a source-transport `timeout` with
|
|
25
|
+
`seek_unsupported` means playback was retained without a seek. No prior raw native
|
|
26
|
+
capability mask can be reconstructed from a false diagnostic boolean.
|
|
27
|
+
|
|
28
|
+
## Tester workflow
|
|
29
|
+
|
|
30
|
+
1. In Home Assistant **Settings > Devices & services > Entities**, filter to your
|
|
31
|
+
Loxone integration entry and find **Audio diagnostics**. It is a diagnostic
|
|
32
|
+
entity, hidden from automatic dashboards, not disabled. Turn it **on**. With
|
|
33
|
+
several entries each has its own switch and independent report.
|
|
34
|
+
2. Reproduce the problem through your usual native UI or controlling app. Note
|
|
35
|
+
local time/timezone, the room, source sequence, expected result and what you
|
|
36
|
+
actually saw/heard. Do not repeatedly trigger a failure merely to fill a report.
|
|
37
|
+
3. Open **Settings > Devices & services > Loxone**, use the relevant entry's
|
|
38
|
+
three-dot menu and **Download diagnostics**. This uses HA's existing
|
|
39
|
+
administrator-only config-entry diagnostic download, not a new public endpoint.
|
|
40
|
+
4. Turn **Audio diagnostics off**. That stops new collection, not the integration
|
|
41
|
+
or playback. No reload, new connection, Core restart, media command or bookmark
|
|
42
|
+
reset occurs when switching it on/off. The explicit setting survives ordinary
|
|
43
|
+
restarts once persistence is confirmed; new installs/upgrades without a valid
|
|
44
|
+
saved setting start **off**. OFF stops emission immediately, before storage I/O.
|
|
45
|
+
Check the switch/report health: `pending_preference` is the latest unconfirmed
|
|
46
|
+
requested bool (or null when confirmed), and `preference_restart_risk` is true
|
|
47
|
+
while pending. `storage_unavailable` plus a sticky `storage_failures` count
|
|
48
|
+
reports failed, mismatched, deferred or cancelled persistence. A successful
|
|
49
|
+
journal flush/export does not clear that pending preference error.
|
|
50
|
+
5. Review the downloaded JSON before attaching it to your agreed issue/report
|
|
51
|
+
channel. Nothing uploads automatically. Include the exact candidate/ZIP hash,
|
|
52
|
+
HA/PyLoxone/library versions, symptom time/timezone, steps and audible versus
|
|
53
|
+
displayed result. Locally match a room to its `room`/`player` aliases if needed;
|
|
54
|
+
do not post original household IDs or private account details. Do not contact
|
|
55
|
+
maintainers/testers until your own agreed outreach/publication gate is met.
|
|
56
|
+
|
|
57
|
+
The switch and actual HA admin download handler have been exercised through an
|
|
58
|
+
offline owning-HA harness, then installed and checked on the real HAOS runtime.
|
|
59
|
+
An owner subsequently enabled collection and supplied an actual downloaded report
|
|
60
|
+
containing send/completion/reply, saved-session and restore-decision evidence.
|
|
61
|
+
The supplied report had no storage, observer or queue-loss errors. This validates
|
|
62
|
+
that live collection/export journey, not all branches or audible playback.
|
|
63
|
+
Menu placement may vary with HA. The private report is not a public fixture.
|
|
64
|
+
|
|
65
|
+
## Reading a report and preparing a useful bug report
|
|
66
|
+
|
|
67
|
+
- Check `enabled` and `status`: `collecting` means the feature was enabled when
|
|
68
|
+
exported. It is independent of the integration's existing experimental
|
|
69
|
+
play/pause option, which gates native Audio Server playback features rather
|
|
70
|
+
than diagnostic recording. Turning diagnostics on does not enable those controls.
|
|
71
|
+
- Check `coverage_oldest_utc`, `coverage_newest_utc` and `export_oldest_utc` against
|
|
72
|
+
the incident time. The report cannot reconstruct commands from before collection
|
|
73
|
+
started. A short window immediately after enabling is normal.
|
|
74
|
+
- Check `dropped_queue`, `dropped_storage`, `export_omitted_records`,
|
|
75
|
+
`storage_failures` and `observer_failures`. Nonzero counters qualify what can be
|
|
76
|
+
inferred; zero counters do not prove every external/native event was received.
|
|
77
|
+
- `complete_24h: false` is deliberately conservative, not by itself a fault.
|
|
78
|
+
Retention is up to 24 hours; it is not a promise of uninterrupted or complete
|
|
79
|
+
reception, and the bounded download may be shorter than the stored window.
|
|
80
|
+
- Follow the same request/player/source aliases through `request`,
|
|
81
|
+
`send_attempt`, `send_completed` and `reply` or an error/timeout. Use
|
|
82
|
+
`session_saved` and `restore_decision` to distinguish a missing bookmark, an
|
|
83
|
+
ineligible seek and an actual seek attempt. A `restore_echo` is not proof the
|
|
84
|
+
loudspeaker playback moved; report what was heard separately.
|
|
85
|
+
- Include the local incident time and timezone, intended room/source, exact
|
|
86
|
+
versions/build, normal UI steps, and expected versus observed behaviour.
|
|
87
|
+
Review the complete JSON before attaching it manually. Do not post private
|
|
88
|
+
room/account mappings, credentials or unrelated raw exports.
|
|
89
|
+
|
|
90
|
+
Turning collection off preserves unexpired evidence, so a report can also be
|
|
91
|
+
downloaded after disabling it. Do not assume `enabled: false` means a retained
|
|
92
|
+
timeline is empty. Check the actual event times and collection status instead.
|
|
93
|
+
|
|
94
|
+
## Retention and limits
|
|
95
|
+
|
|
96
|
+
Collection continues while on: **24 hours is a rolling maximum record age, not a
|
|
97
|
+
collection timeout**. Off retains unexpired evidence for reporting and preserves
|
|
98
|
+
configuration. Disabled housekeeping runs approximately every 60 seconds;
|
|
99
|
+
export filters expiry too. Timestamps use UTC/elapsed seconds, including DST.
|
|
100
|
+
Already expired records are not recovered after restart or a coverage gap.
|
|
101
|
+
|
|
102
|
+
Preference saves use HA's existing Store and public readback, checking the exact
|
|
103
|
+
requested bool and this entry's pseudonym key without exporting the key. The
|
|
104
|
+
existing housekeeping writer retries the latest pending request at most once per
|
|
105
|
+
60 seconds (monotonic backoff), outside the journal lock. It never replays an old
|
|
106
|
+
ON over a newer OFF; closing retires retry ownership. HA stopping/deferred writes
|
|
107
|
+
are not treated as durable confirmation. Once storage recovers and save/readback
|
|
108
|
+
succeed, pending clears and ordinary `off`/`collecting` health returns. While a
|
|
109
|
+
failed OFF remains unpersisted, an actual restart can restore the earlier saved
|
|
110
|
+
ON. Storage that cannot write cannot promise durable OFF: resolve the reported
|
|
111
|
+
disk/permission problem and confirm pending has cleared before relying on restart.
|
|
112
|
+
|
|
113
|
+
Per integration entry:
|
|
114
|
+
|
|
115
|
+
- Queue: at most **256 events**; overflow removes the oldest queued record.
|
|
116
|
+
- Sanitised event: at most **2 KiB**; no unbounded raw frames or DEBUG logs.
|
|
117
|
+
- Timeline: at most **4 MiB**, in **256 KiB** segments. Size pressure rotates the
|
|
118
|
+
oldest segment, potentially shortening coverage to much less than 24 hours.
|
|
119
|
+
- Atomic maintenance reserves at most one additional segment plus bounded counter
|
|
120
|
+
metadata (8 KiB read bound). Preference/pseudonym-key storage is separate and
|
|
121
|
+
tiny. Local files are private, outside web/static paths.
|
|
122
|
+
- Export: newest records within a bounded **1 MiB** audio-report budget. The
|
|
123
|
+
adapter reserves **64 KiB** for HA's separate envelope. HA owns that envelope;
|
|
124
|
+
unusually large platform metadata is not under this integration's control.
|
|
125
|
+
Exports state their omission count rather than promising every retained record.
|
|
126
|
+
|
|
127
|
+
Coverage oldest/newest times, export oldest time, mapped/omitted room aliases,
|
|
128
|
+
expiry/rotation/invalid counts and queue/storage/observer failures accompany the
|
|
129
|
+
report. `complete_24h` is conservatively false: a timestamp range is not proof of
|
|
130
|
+
unbroken reception. Restarted sequence/monotonic values belong to a new process;
|
|
131
|
+
UTC and transport/request/player aliases provide correlation, not unique physical
|
|
132
|
+
causality. A reported storage failure warns once with fixed advice to check disk
|
|
133
|
+
space/permissions; it never includes exception text or interrupts playback.
|
|
134
|
+
|
|
135
|
+
File I/O runs in the existing HA executor, through one entry-owned writer and
|
|
136
|
+
serial lock. Cancellation waits for an in-progress filesystem operation before
|
|
137
|
+
releasing that lock. This cannot cancel a stuck OS filesystem operation. A slow
|
|
138
|
+
or full disk can lose diagnostics, not backpressure native playback. Stored
|
|
139
|
+
partial/invalid event lines are rejected; atomic replacement preserves preceding
|
|
140
|
+
complete records where possible. A report can honestly have no recoverable data.
|
|
141
|
+
Startup and ordinary maintenance (even cached/OFF maintenance) discard abandoned
|
|
142
|
+
`events-<numeric index>.jsonl.tmp` files with the journal's minimum 16-digit index
|
|
143
|
+
and `state.json.tmp`; uncommitted payloads are not evidence. Cleanup never reads
|
|
144
|
+
these payloads or follows symlinks, leaves unrelated names untouched, inspects at
|
|
145
|
+
most 256 directory entries and removes at most 64 recognised regular temporary
|
|
146
|
+
files per operation. Unexpected types, work limits or unlink errors report storage
|
|
147
|
+
failure rather than claiming recovery. Successful recovery/rotation restores the
|
|
148
|
+
timeline plus one atomic segment and small metadata allowance above; foreign files
|
|
149
|
+
or an inaccessible directory cannot be claimed bounded or successfully cleaned.
|
|
150
|
+
|
|
151
|
+
## What the evidence means
|
|
152
|
+
|
|
153
|
+
- `ha_service_request` is HA's request event for an exact registered audio entity;
|
|
154
|
+
area/device-only targeting and unrelated controls are not reconstructed.
|
|
155
|
+
- `session_saved` samples the actual qualified room/source cache, not Recorder or
|
|
156
|
+
a separately recreated bookmark. `restore_decision` reports the first evaluated
|
|
157
|
+
guard reason, saved/current numeric positions/durations and initial/post-auth
|
|
158
|
+
phase; unevaluated guards are not falsely described as failures.
|
|
159
|
+
- Audio Server `request`, `authenticated`, `send_attempt`, `send_completed` and
|
|
160
|
+
`reply` distinguish authentication, the actual existing socket send await and
|
|
161
|
+
a parsed native result. Source confirmation can instead settle from separately
|
|
162
|
+
qualified requested-source feedback. A completed send is **not device execution**.
|
|
163
|
+
- `restore_echo` is a numeric native position echo, **not acoustic movement** or
|
|
164
|
+
proof that playback advanced from the requested position. Optional-restore
|
|
165
|
+
failure leaves confirmed source success intact; no retry is introduced.
|
|
166
|
+
- Miniserver sends are recorded on its existing connection **only** for discovered
|
|
167
|
+
audio controls and allowlisted play/pause/stop/next/previous/volume operations.
|
|
168
|
+
Encrypted command bytes/authentication remain untouched; no auth envelope enters
|
|
169
|
+
the sink. Relevant numeric volume/play-state feedback is labelled separately
|
|
170
|
+
from Audio Server track/source/position/event feedback and disconnects.
|
|
171
|
+
|
|
172
|
+
The same opt-in policy covers all AudioZoneV2 players discovered in that loaded
|
|
173
|
+
entry; there are no hardcoded household room IDs. Report aliases correlate routes,
|
|
174
|
+
player, room, account, content and parent context without exposing originals.
|
|
175
|
+
Meaningful non-secret seek numbers and semantic route structure remain exact.
|
|
176
|
+
No title, private announcement text, raw house structure, arbitrary frame/error,
|
|
177
|
+
credential, cookie, token, password or raw media URL is persisted by this feature.
|
|
178
|
+
|
|
179
|
+
HA itself adds standard system/custom-integration metadata to diagnostic downloads,
|
|
180
|
+
which can include installation/platform/hostname details. That HA-owned envelope
|
|
181
|
+
is **not** claimed to be anonymous. Review the actual entire download before
|
|
182
|
+
sharing; pseudonymisation of the audio portion is not universal anonymisation.
|
|
183
|
+
|
|
184
|
+
## Scope and cost
|
|
185
|
+
|
|
186
|
+
The library supplies no-op-by-default structured events and imports no HA/storage
|
|
187
|
+
implementation. The existing adapter owns the switch, preference, local writer
|
|
188
|
+
and export. There is no sidecar, second integration, new socket, global debug
|
|
189
|
+
setting or automatic upload. Disabled callers skip detailed diagnostic field
|
|
190
|
+
construction and queue/file writes; expiry of previously retained data still runs.
|
|
191
|
+
|
|
192
|
+
Synthetic HA-harness measurements are retained with this candidate's development
|
|
193
|
+
receipts: process CPU deltas, `/proc/self/status` RSS/HWM, event rate, actual journal
|
|
194
|
+
bytes and export bytes/time. They are a short synthetic load, not quiet-house or
|
|
195
|
+
busy-house measurements, device latency proof, a per-day write forecast, or an
|
|
196
|
+
incremental production Core memory estimate. Limits are fixed bounds, not a promise
|
|
197
|
+
that a busy installation will retain a full day.
|
|
198
|
+
|
|
199
|
+
This capability cannot retrieve commands from before enablement or retroactively
|
|
200
|
+
diagnose earlier Spotify returns. It changes no source, queue, seek, retry, newest
|
|
201
|
+
request, authentication or control policy. Existing independently operated private
|
|
202
|
+
rolling observers/watchdogs are neither imported, replaced nor stopped. Their
|
|
203
|
+
records are not included in this report, and their settings remain independent.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Exact remembered-track return — 0.1.1
|
|
2
|
+
|
|
3
|
+
The matching library and adapter passed independent source and exact-wheel review, and the common pair was installed on Home Assistant OS (Core 2026.10.4, Python 3.14.9). On 28 October 2026 the owner accepted two normal-use Local Library → Spotify returns to the same track near its saved position, supported by integration command and native content/position feedback. This is one-room confirmation, not all-room acoustic, whole-queue, persistent shuffle or restart-recovery proof.
|
|
4
|
+
|
|
5
|
+
For public availability, use the matching GitHub release, PyPI version and release verification receipts. Source, tag or uploader success alone is not the production gate. Existing Home Assistant installations do not automatically update.
|
|
6
|
+
Use the exact matching release wheel, adapter, preview and checksums; historical
|
|
7
|
+
same-version development artifacts are not interchangeable.
|
|
8
|
+
|
|
9
|
+
## What this correction does
|
|
10
|
+
|
|
11
|
+
- Individual Spotify **track and podcast-episode** starts include the native
|
|
12
|
+
per-start `/noshuffle` argument, after any validated parent/cursor. Configured
|
|
13
|
+
account, exact item and optional parent/zero-based index stay unchanged.
|
|
14
|
+
Account-qualified item identifiers are retained, not stripped.
|
|
15
|
+
- When returning to a saved exact Local Library/Spotify item, feedback from the
|
|
16
|
+
same provider/account but a **different track is not success**. It cannot
|
|
17
|
+
trigger the old track's position seek or replace the preceding last-good item.
|
|
18
|
+
The player still displays the track actually reported by Loxone.
|
|
19
|
+
- Continuing feedback from that rejected return retains the prior bookmark.
|
|
20
|
+
A later explicit return attempts that retained item instead of treating the
|
|
21
|
+
wrong currently-playing track as a provider-only no-op. No automatic retry is
|
|
22
|
+
added. A matching return, a new explicit Browse selection, or independently
|
|
23
|
+
corroborated later different playback can update the record normally.
|
|
24
|
+
- After matching playback, at most **one best-effort** position attempt retains
|
|
25
|
+
existing bounded capability readiness, authentication, room/account/track,
|
|
26
|
+
lifecycle, event/fence and newer-action checks. An unsupported/failed optional
|
|
27
|
+
seek does not turn matching confirmed playback into source failure.
|
|
28
|
+
- A positively qualified current native Spotify session can still use native
|
|
29
|
+
empty-content resume. Unknown/history-only context return retains its existing
|
|
30
|
+
provider contract; exact remembered-item confirmation does not invent an item
|
|
31
|
+
for a context. Local Library commands, context starts, radio, Line-In,
|
|
32
|
+
explicit native Shuffle/Repeat setters and their capability rules are unchanged.
|
|
33
|
+
|
|
34
|
+
There is no Spotify API, compensating Shuffle/Repeat write, queue controller,
|
|
35
|
+
new setting, delay-only fix, cursor arithmetic change, fallback item, cross-room
|
|
36
|
+
policy or persistence implementation. The existing playback setup gate remains
|
|
37
|
+
required (see the main README).
|
|
38
|
+
|
|
39
|
+
## Function-to-feature map
|
|
40
|
+
|
|
41
|
+
| File/symbol | Change and regression coverage |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `pyloxone_audio/native.py:AudioServerCommands.async_play_catalogue` | Type-specific per-item flag; `tests/library/test_exact_track_start.py` checks tracks/episodes, qualified IDs, no parent and cursors 0/13/63, plus context/other-route negatives |
|
|
44
|
+
| `pyloxone_audio/sources.py:_source_matcher`, `async_select_catalogue` | Saved exact-item match before confirmation/optional seek; preserve ordered source/track/account restore reasons |
|
|
45
|
+
| `pyloxone_audio/selection.py:async_source_route` | Owning adapter may suppress current-session no-op after a rejected exact return; ordinary native session routing unchanged |
|
|
46
|
+
| `adapters/pyloxone/overlay/custom_components/loxone/media_player.py:LoxoneAudioZoneV2._update_audio_metadata`, `async_select_source`, `_async_play_radio` | One room-local rejected-return marker, using the existing saved session and passive qualification. Protect last-good without changing truthful metadata; release on qualified replacement/explicit success |
|
|
47
|
+
| `adapters/pyloxone/overlay/custom_components/loxone/audio_diagnostics.py:_safe_event` | Persisted strict schema retains the aliased Spotify flag; recovery/extra-tail/non-Spotify negatives in owning-HA tests |
|
|
48
|
+
| `pyloxone_audio/diagnostic_events.py:DiagnosticEmitter.route` | Recognise only the fixed per-item flag, preserving keyed account/content/parent aliases; unknown tails still refused |
|
|
49
|
+
| `tests/adapter/test_exact_track_return_ha.py` | Real owning HA service/coordinator/authenticated native transport, synthetic I/O: 30.021s/index13 shape, wrong feedback even with new flag and reported shuffle false/true, delayed correct feedback, account/room negatives, explicit retry/Browse, late matches and independent replacement |
|
|
50
|
+
|
|
51
|
+
Existing full-suite lifecycle/authentication/cancellation, all-room isolation,
|
|
52
|
+
mode, manual seek, announcement, setup/unload and no-uncertain-replay controls
|
|
53
|
+
remain part of acceptance. See the maintainer's `EXACT-TRACK-DELTA.json` and
|
|
54
|
+
`EXACT-TRACK-TEST-MIGRATIONS.json` for exact file/expectation dispositions.
|
|
55
|
+
|
|
56
|
+
## Source evidence and limits
|
|
57
|
+
|
|
58
|
+
The pinned official Loxone 17.2.2 client, retrieved 26 October 2026 from the official
|
|
59
|
+
Linux release AppImage, uses `playItem -> shouldShuffleAudioItem ->
|
|
60
|
+
ServicePlayScheme`; individual track/episode types choose `noshuffle`, serialized
|
|
61
|
+
**after** `parentpath/<parent>/<zero-based-index>`. The retained bundle SHA-256 is
|
|
62
|
+
`76f4ff34c3156cf9109524c37640d33352968fc7dc7477af6866a9983f5abacf`.
|
|
63
|
+
This is command/caller parity, not proof of the physical firmware's selection
|
|
64
|
+
algorithm or a persistent shuffle/queue-preservation guarantee. The motivating
|
|
65
|
+
wrong-track observation included reported shuffle **false**, so it is not
|
|
66
|
+
explained simply by a shuffle-on switch.
|
|
67
|
+
|
|
68
|
+
Wrong-feedback fixtures are deliberately independent of the flag. A simulator
|
|
69
|
+
that returns the right item when it sees the flag cannot prove the hardware cause.
|
|
70
|
+
Those offline fixtures use no device credentials or household commands. Later
|
|
71
|
+
owner-operated one-room returns supplied matching content/position confirmation;
|
|
72
|
+
parent/queue, universal audible position and persistent-mode effects remain unproved.
|
|
73
|
+
|
|
74
|
+
The receiver cannot establish an external command's issuer from identical
|
|
75
|
+
same-item feedback. Continuing the rejected item alone does not establish a new
|
|
76
|
+
independent selection. Explicit Browse can deliberately choose that item; later
|
|
77
|
+
qualified different playback also replaces the marker. This is a bounded
|
|
78
|
+
interpretation of observed identity, not invented causal device evidence.
|
|
79
|
+
|
|
80
|
+
## Review and adoption
|
|
81
|
+
|
|
82
|
+
1. Inspect the exact delta, test-migration map and retained original failed receipts.
|
|
83
|
+
2. Reproduce canonical source and exact installed-wheel suites with blocked TCP,
|
|
84
|
+
strict runtime/resource warning gates, case parity and import evidence.
|
|
85
|
+
3. Verify the complete preview against its provenance; exercise the unchanged
|
|
86
|
+
builder/install/update/rollback tests. Preview material stays out of Python
|
|
87
|
+
wheel/sdist. Do not use older same-version artifact hashes.
|
|
88
|
+
4. Preserve the completed independent exact-correction review and common adoption
|
|
89
|
+
evidence. Re-review changed runtime; historical mode/seek reviews alone do not
|
|
90
|
+
approve future changes.
|
|
91
|
+
5. Keep software tests, installed-byte verification, one-room owner acceptance and
|
|
92
|
+
the public production gate separate. Upstream adoption/contact is not implied.
|
|
93
|
+
|
|
94
|
+
Restart persistence is a separate design and is intentionally not bundled here.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Native Shuffle and Repeat — 0.1.1
|
|
2
|
+
|
|
3
|
+
## What appears in Home Assistant
|
|
4
|
+
|
|
5
|
+
Open an existing Loxone room's **More info** media-player dialog. Where the
|
|
6
|
+
current Audio Server reports support, the normal HA controls offer **Shuffle**
|
|
7
|
+
and **Repeat**. Shuffle is on/off; Repeat cycles **Off → All → One → Off**.
|
|
8
|
+
The standard icons distinguish the reported modes. Compact Media Control/Tile
|
|
9
|
+
cards do not necessarily show extended controls. No custom card, helper switch,
|
|
10
|
+
frontend resource or Core patch is installed.
|
|
11
|
+
|
|
12
|
+
Configure **Audioserver host** and turn on the existing option
|
|
13
|
+
**Use Audio Server player play/pause (experimental; off by default)**
|
|
14
|
+
(`audioserver_playback`). This option and its default are unchanged. Metadata can
|
|
15
|
+
still be received with control disabled. **Audio diagnostics** is a different,
|
|
16
|
+
default-off feature, not a prerequisite for mode control.
|
|
17
|
+
|
|
18
|
+
These are **Loxone player controls, not Spotify controls**. Every action addresses
|
|
19
|
+
one exact existing native Audio Server player through the library's current-token
|
|
20
|
+
command client. Local Library and any other genuinely capable native source use
|
|
21
|
+
the same implementation. There is no Spotify Web API/Connect command, HA Spotify
|
|
22
|
+
entity/service, provider credential, binding or provider-derived mode state in
|
|
23
|
+
this feature. Existing room identities, configuration and independent bookmarks
|
|
24
|
+
are retained. Radio or Line-In labels do not imply support.
|
|
25
|
+
|
|
26
|
+
## Truthful state and limits
|
|
27
|
+
|
|
28
|
+
- The exact player's native `plshuffle` and `plrepeat` feedback supplies the
|
|
29
|
+
displayed state, including changes made in Loxone or another controlling app.
|
|
30
|
+
A submitted HA request or successful socket write does not turn the indicator
|
|
31
|
+
on. A validated native reply acknowledges the command; this adapter waits for
|
|
32
|
+
the ordinary exact-player feedback to change its displayed mode.
|
|
33
|
+
- Missing, malformed or disconnected state is **unknown**, not a fabricated Off.
|
|
34
|
+
Full native player-state records are replaced rather than merging absent mode
|
|
35
|
+
fields from an older track/session. Announcement events are not queue state.
|
|
36
|
+
- Shuffle requires native bit2048, known shuffle state, current ordinary playing
|
|
37
|
+
media, and API >=1.6 / firmware >=16.1.09.23 on the event connection. The command
|
|
38
|
+
connection must independently qualify that greeting before sending an explicit
|
|
39
|
+
enable/disable. There is no fallback to the older no-argument shuffle action.
|
|
40
|
+
- Native repeat is **0 Off / 1 All / 3 One**, never2. HA has one REPEAT_SET feature
|
|
41
|
+
and its standard button cycles all three modes. Therefore this adapter exposes
|
|
42
|
+
that button only with known repeat state and **both** native permissions4096
|
|
43
|
+
and8192 on current playing/paused media. Partial repeat support is not advertised
|
|
44
|
+
as a full cycle; a direct HA setter also refuses it. The library's qualification
|
|
45
|
+
helper can check a specifically requested repeat mode for another typed host.
|
|
46
|
+
- Support follows current native data, not provider/source-name guesses. Unknown
|
|
47
|
+
permissions and unsupported source records hide the extended control without
|
|
48
|
+
changing existing Miniserver controls. Unknown or older shuffle firmware does
|
|
49
|
+
not disable otherwise-qualified native Repeat.
|
|
50
|
+
- Exactly one requested native mode command is sent. No play, source start,
|
|
51
|
+
queue replacement, seek, skip or automatic retry is added. In particular this
|
|
52
|
+
mode-control feature does **not** replace queues or implement source-return
|
|
53
|
+
selection. The separate exact-item return correction is described in
|
|
54
|
+
[EXACT-TRACK-RETURN.md](EXACT-TRACK-RETURN.md).
|
|
55
|
+
- A queued request cannot survive loss of its original track/account/context,
|
|
56
|
+
capability, connection, newest-action ownership or entity lifetime while
|
|
57
|
+
authentication is awaited. Existing shared serialization and clean cancellation
|
|
58
|
+
remain. Mode feedback does not alter artwork identity or saved source content.
|
|
59
|
+
|
|
60
|
+
## Portable API and adapter map
|
|
61
|
+
|
|
62
|
+
`AudioRepeatMode` and `audio_mode_supported` are public HA-independent exports.
|
|
63
|
+
`AudioZoneMetadata.shuffle` is `bool | None`; `repeat` is
|
|
64
|
+
`AudioRepeatMode | None`; `shuffle_switch_supported` is connection-qualified
|
|
65
|
+
`bool | None`. Only greeting versions are retained, never the session credential.
|
|
66
|
+
|
|
67
|
+
`AudioServerCommands.async_set_shuffle(player_id, bool, *, is_current=...)` and
|
|
68
|
+
`async_set_repeat(player_id, AudioRepeatMode, *, is_current=...)` reuse current
|
|
69
|
+
authentication, bounded command-wide timeout, connection serialization and close.
|
|
70
|
+
The host must qualify the latest native snapshot and maintain a liveness callback
|
|
71
|
+
across awaits. The repeat API rejects bare integers/strings rather than silently
|
|
72
|
+
coercing an unknown enum. Setters strictly validate the corresponding native mode
|
|
73
|
+
reply. Neither setters nor helpers import Home Assistant or own provider APIs.
|
|
74
|
+
|
|
75
|
+
The existing AudioZoneV2 entity translates HA SHUFFLE_SET/REPEAT_SET and
|
|
76
|
+
`async_set_shuffle`/`async_set_repeat` into those calls. The normal event callback
|
|
77
|
+
updates HA attributes. The same policy is used in every mapped room, with no
|
|
78
|
+
per-room flags/delays. Strict optional diagnostics add only fixed aliased command
|
|
79
|
+
routes and typed mode fields; default-off and all storage/export bounds remain.
|
|
80
|
+
|
|
81
|
+
## Evidence and remaining acceptance
|
|
82
|
+
|
|
83
|
+
The maintained tests use synthetic data and real owning HA services, native
|
|
84
|
+
RSA/AES authentication and AF_UNIX WebSocket framing with TCP blocked. The all-room
|
|
85
|
+
matrix includes Local Library and native Spotify without loading HA Spotify;
|
|
86
|
+
additional positive/negative permission controls do not claim physical radio or
|
|
87
|
+
Line-In firmware support. Existing mode-control tests remain separate from exact-item source-start tests.
|
|
88
|
+
Version-matched frontend function tests exercise HA's real control/icon/cycle
|
|
89
|
+
functions using emitted HA entity states, not a replacement player UI.
|
|
90
|
+
|
|
91
|
+
Independent review and common private HAOS adoption are complete. Actual mode
|
|
92
|
+
requests and native mode feedback were observed, but those are not proof of
|
|
93
|
+
physical queue behaviour or every rendered frontend control. The ordinary
|
|
94
|
+
install/backup/update/rollback route is in
|
|
95
|
+
[the preview guide](preview-build/README.md); the maintainer's exact patch and
|
|
96
|
+
what/why/test map are in [the review pack](adapters/pyloxone/jo-review/README.md).
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
# Provenance and licence —
|
|
1
|
+
# Provenance and licence — PyLoxone-Audio 0.1.1
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
PyLoxone-Audio 0.1.1 is supplied under Apache-2.0. Published 0.1.0 remains
|
|
4
|
+
immutable. `LICENSE` retains PyLoxone's Apache License, Version 2.0 verbatim.
|
|
5
|
+
Actual public availability is established by the matching release production gate.
|
|
4
6
|
|
|
5
|
-
The HA entry ownership, exact-player mapping, current-token callback and entity-property delegation are adapted from the PyLoxone integration maintained by JoDehli and its contributors, specifically the sealed `media_player.py`, `audio.py` and `coordinator.py` call graph. Those inspected source files contain no additional per-file copyright notices to remove or replace. This
|
|
7
|
+
The HA entry ownership, exact-player mapping, current-token callback and entity-property delegation are adapted from the PyLoxone integration maintained by JoDehli and its contributors, specifically the sealed `media_player.py`, `audio.py` and `coordinator.py` call graph. Those inspected source files contain no additional per-file copyright notices to remove or replace. This project does not assign invented upstream copyright ownership.
|
|
6
8
|
|
|
7
9
|
The original native protocol source retains this attribution, which must accompany any future adaptation of its event mapping:
|
|
8
10
|
|
|
9
11
|
> Event names adapted from SebastianEitzert's Apache-2.0 POC in #523, comment 6251138699. See tests/fixtures/audioserver/README.md for provenance.
|
|
10
12
|
|
|
11
|
-
The actual parser/event mapping is now extracted into `pyloxone_audio/native.py`, retaining that attribution. Native transport/authentication, metadata coordination, source policy, radio and catalogue implementations are derived from the immutable accepted source tree identified by `baseline-verification.json` and the extraction provenance receipts. Native announcement ownership
|
|
13
|
+
The actual parser/event mapping is now extracted into `pyloxone_audio/native.py`, retaining that attribution. Native transport/authentication, metadata coordination, source policy, radio and catalogue implementations are derived from the immutable accepted source tree identified by `baseline-verification.json` and the extraction provenance receipts. Native announcement ownership remains extracted; the optional HA-Spotify bridge/provider session controller was retired in0.1.1, preserving native Spotify. HA preparation and UI responsibilities stay with the host. Relevant upstream attribution and Apache-2.0 terms are retained; no invented copyright assignment is made.
|
|
12
14
|
|
|
13
|
-
Historical fake-facade, extraction and operational evidence remains outside release assets. The concrete package exports real native classes and source-policy functions instead. Synthetic fixture provenance is preserved under `tests/library/fixtures/audioserver/README.md` outside the wheel. The older path in the attribution quoted above is historical; the current location applies to this repository and its source archive.
|
|
15
|
+
Historical fake-facade, extraction and operational evidence remains outside release assets. The concrete package exports real native classes and source-policy functions instead. Synthetic fixture provenance is preserved under `tests/library/fixtures/audioserver/README.md` outside the wheel. The older path in the attribution quoted above is historical; the current location applies to this repository and its source archive. New default-off fixed-schema audio diagnostics supersedes the blanket instrumentation exclusion only for this increment; legacy private tracing, household observer/watchdog assets and HA failure-summary publication remain excluded.
|
|
14
16
|
|
|
15
17
|
Dave directed requirements, behaviour decisions and normal-use validation. Implementation and offline testing were AI-assisted through Hermes with OpenAI primary models; release-cutoff implementation uses gpt-6.1-sol and the independently recorded review uses an actual primary OpenAI invocation. AI assistance is provenance, not an invented human author, a transfer of upstream ownership, hardware certification or a guarantee of defect freedom. Independent review identity and limitations are recorded in release-level evidence, not claimed as a substitute for tests.
|