v0.1.0
First release. Async client for the Yamaha Disklavier ENSPIRE local HTTP API, developed
against firmware 5.24.00 on an ENSPIRE PRO grand.
Added
Disklavierclient covering state, transport, volume, power, quiet mode, repeat and
shuffle, library browsing, radio, and one-shot notifications.- Typed models —
StaticInfo,CurrentInfo,MasterState,PlaybackSnapshot,Song,
Album,Playlist,RadioChannel— that convert the firmware's string-encoded numbers
once, so callers never have to. async_notify, withasync_snapshot_playbackandasync_restore_playback, for playing a
one-shot notification and putting the piano back as it was.async_play_test_chord, which sounds a C major triad without touching the sequencer.- Enumerations mirroring the firmware exactly:
PowerStatus,PlaybackStatus,QuietMode,
SongGroup,PlaylistGroup,Genre,GenreSelect,RepeatMode. - PEP 561
py.typedmarker, so type hints reach consumers. - Browse methods translate the firmware's empty-library error envelope into the empty list
it denotes, andDisklavierResponseErrorcarriescommandanderror_infoattributes so
the envelope errors that remain can be told apart without parsing messages.
Security
- Response bodies are read against a 1 MiB ceiling rather than without limit, so a hostile
or broken device cannot stream the client's host out of memory. - Redirects are refused. No endpoint the client calls legitimately redirects, and following
one would hand the request to whatever host a spoofed device names.
Notes on firmware behaviour
These shaped the API and are documented in docs/enspire-api.md:
- Targets the versioned open API at
/api/1.0/<command>, rather than the/api/api.php
spelling of the same surface. The two were verified equivalent down to their error codes. - There is no stop state —
stopreports aspauseat position zero, exposed as
CurrentInfo.is_stopped. power_statushas a transitionalwakeupvalue lasting roughly twelve seconds, during
which the piano ignores commands.- Empty libraries arrive as an error envelope inside HTTP 200; the browse methods translate
it back into an empty list. - List responses switch between
song_listanditem_listdepending on the group. - State files can be read mid-rewrite and come back truncated, or carry a trailing NUL. Reads
retry; the NUL is stripped rather than retried. - Restoring playback stops first, because
load_songchanges the sequencer's selection
without halting what is currently sounding.