Skip to content

fix(sendspin): record a declared aiosendspin override so MA controller state parses - #12

Merged
kiwipaulrob merged 1 commit into
sendspin-advancedfrom
fix/sendspin-aiosendspin-override
Sep 29, 2026
Merged

kiwipaulrob merged 1 commit into
sendspin-advancedfrom
fix/sendspin-aiosendspin-override

Conversation

@kiwipaulrob

Copy link
Copy Markdown
Owner

Problem

sendspin 7.5.0 declares:

Requires-Dist: aiosendspin[server]~=6.0.1

PEP 440 expands ~=6.0.1 to >=6.0.1,<6.1.0 — 6.0.x only. But aiosendspin 6.1.0 added seek and seek_relative to MediaCommand, and servers now advertise them. Music Assistant 2.10.x sends seek_relative in supported_commands, as does Loxone/Sonn Core 4.0.0-beta.21.

Because supported_commands is typed list[MediaCommand], one unknown member discards the whole server/state message:

ERROR:aiosendspin.client.client:Failed to parse server message: {"type":"server/state",...}
mashumaro.exceptions.InvalidFieldValue: Field "supported_commands" of type list[MediaCommand] has invalid value [...]

Audio keeps playing (a different message), so the client still looks healthy while controller state — volume, mute, repeat, shuffle — silently stops syncing. Observed on a moOde 10.3.4 Pi against Music Assistant: 15 dropped messages in one hour, stream unaffected.

This is a known upstream issue

Already reported, no fix released:

So this PR does not fix upstream; it makes the moOde install correct until upstream relaxes the pin.

Fix

The installer records a declared --overrides entry in the uv tool receipt:

aiosendspin>=6.1.1,<6.2

uv tool install ... --overrides <file> overrides the transitive constraint, and — unlike a hand-applied uv pip install — the override is recorded in uv-receipt.toml, so it is part of the resolution and survives uv tool upgrade (which otherwise re-resolves straight back to 6.0.5). Verified: with the override recorded, uv tool upgrade sendspin leaves 6.1.1 in place.

The upper bound is deliberately narrow. >=6.1.1 alone resolves to 9.1.1, three majors past the declared range, and upstream PR moode-player#276 shows 9.1 needed code migration — so 6.1.x, the additive delta verified in moode-player#280, is the safe range. Drop the override once upstream relaxes the pin.

New ensure_aiosendspin_override() runs in install_prerequisites (so both fresh installs and re-runs after a moOde update pick it up), plus detect_aiosendspin_override() in the post-install verification block as a warning.

Verification

bash -n passes. The new functions were extracted verbatim from the branch into a harness and run on the Pi:

=== TEST: simulated stock state ===
simulated stock: aiosendspin-6.0.5
DETECT: FAIL (needs override)                      <- correctly detects the gap
[INFO]   Applying aiosendspin override >=6.1.1,<6.2 (upstream sendspin#280)
[OK]   aiosendspin override applied (6.0.5 -> 6.1.1)
ensure rc=0
[INFO]   aiosendspin 6.1.1 satisfies the override  <- second call is a no-op
ensure rc=0

=== final state ===
aiosendspin: 6.1.1
seek_relative: 1
override file: aiosendspin>=6.1.1,<6.2
receipt: overrides = [{ name = "aiosendspin", specifier = ">=6.1.1,<6.2" }]
detect now: PASS

End-to-end with the override live: a real Music Assistant stream started (Stream started with codec flac), audio device held by the daemon, metadata endpoint populated, and 0 deserialisation exceptions since the daemon started (previously recurring).

Installer bumped to v4.1.6; README gains a "Known upstream issue" section documenting the symptom, the upstream references, and how to inspect/remove the override.

…r state parses

sendspin 7.5.0 declares aiosendspin[server]~=6.0.1, i.e. >=6.0.1,<6.1.0, but
aiosendspin 6.1.0 added seek/seek_relative to MediaCommand and servers now
advertise them (Music Assistant 2.10.x, Loxone/Sonn Core 4.0.0-beta.21). Since
supported_commands is typed list[MediaCommand], one unknown member discards the
whole server/state message:

  mashumaro.exceptions.InvalidFieldValue: Field "supported_commands" ...

Audio keeps playing, so the client looks alive while controller state
(volume/mute/repeat/shuffle) silently stops syncing.

Reported upstream as Sendspin/sendspin-python-cli#280 and moode-player#278; no fix released.
This does not fix upstream, it keeps the moOde install correct meanwhile.

The installer now records a declared --overrides entry (aiosendspin>=6.1.1,<6.2)
in the uv tool receipt. Unlike a hand-applied uv pip install, the recorded
override is part of the resolution and survives uv tool upgrade, which would
otherwise re-resolve back to 6.0.5. The bound is narrow on purpose: >=6.1.1
alone resolves to 9.1.1, and upstream PR moode-player#276 shows 9.1 needed code migration,
so 6.1.x is the verified-safe range. Remove once upstream relaxes the pin.

Verified by running the new functions verbatim on the Pi: 6.0.5 -> 6.1.1,
second call a no-op, override present in the receipt, 0 deserialisation
exceptions with a live Music Assistant stream. Installer bumped to v4.1.6.
@kiwipaulrob
kiwipaulrob merged commit 2f1b1ae into sendspin-advanced Sep 29, 2026
@kiwipaulrob
kiwipaulrob deleted the fix/sendspin-aiosendspin-override branch September 29, 2026 01:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant