3.8 KiB
3.8 KiB
Changelog
1.0.0 — 2026-04-22
Breaking
- Upgraded to the DongLoRa Protocol v2 wire format. The 0.x line spoke the legacy
v0.1 protocol with hardcoded tag constants (
TAG_OK=4,TAG_ERROR=5,CMD_TAG_SET_CONFIG=2, …) that don't exist in v1.0. This release is wire-incompatible with 0.x clients and firmware. - Pins
donglora>=1.0.0and uses itsdonglora.frame/donglora.events/donglora.commandsmodules as the wire-level backbone. No more in-package reimplementation of the wire protocol. - Structural rewrite mirroring the Rust sibling
donglora-muxone-to-one:donglora_mux/{daemon,intercept,session,tagmap}.pyreplace the single 601-line__init__.py.
Added
TagMapper— per-command device-tag allocator. Enables concurrent out-of-order command/response correlation for multi-client setups (the v0.1-era single-oneshot-response slot is gone).- Full
§13.2multi-clientSET_CONFIGsemantics — tracks the(client_id, modulation)lock owner. Cross-client calls synthesize:OK(APPLIED / MINE, params)when the caller owns the lock (forwarded to dongle).OK(ALREADY_MATCHED / OTHER, current)when another client holds the lock and the requested params byte-match.OK(LOCKED_MISMATCH / OTHER, current)when they differ;currentechoes the lock owner's actual modulation.- Lock auto-releases when the owning client disconnects.
- TX loopback fan-out (
§13.4) — onTX_DONE(TRANSMITTED)the mux synthesizes anRXframe withorigin = LOCAL_LOOPBACKand sends it to every connected client except the transmitter. - Async
ERR(EFRAME)fan-out — if the dongle emits async framing errors (tag 0), they're broadcast to all clients rather than swallowed. - Per-client TX cache on
ClientSessionso the loopback fan-out doesn't need the sender to re-buffer the payload. - Socket and serial file locking (
fcntl.flock) to prevent multiple mux instances from fighting over the same dongle or socket path. - 500 ms keepalive matching
PROTOCOL.md §3.4(2× margin on the 1 s inactivity timer). Replaces the 5 s cadence from 0.x. - Clean ^C / SIGTERM shutdown — per-client handler tasks are tracked
and cancelled on shutdown, so blocked
reader.read()calls no longer pin the event loop open.
Removed
- Every v0.1 wire constant and the inline
cobs+ rawserial.Serialframe codec. - The single
pending_response: asyncio.Futureslot (fundamentally incompatible with v1.0's per-tag concurrency).
Test coverage
- 28 tests (up from 11):
test_tagmap.py(6) — tag allocator behaviour.test_intercept.py(13) — every branch of thedecide()matrix, including theALREADY_MATCHED/LOCKED_MISMATCHsynthesis paths.test_multiclient.py(9) — asyncio-driven daemon dispatch tests: concurrent tag routing,SET_CONFIGlock installation, TX loopback to peer clients, lock release on disconnect, unsolicited-frame drop.
0.2.0 — 2026-04-08
Features
- PyPI-ready metadata — full classifiers, URLs, keywords, readme. Publishable
as
donglora-mux. - Interception test suite — 11 tests ported from the Rust mux covering SetConfig locking, StartRx/StopRx reference counting, and passthrough behaviour.
- GitHub Actions CI — ruff lint + format, pytest on Python 3.10–3.13, PyPI publish on tag.
- Strict ruff linting — E, W, F, I, UP, B, C4, ARG, SIM, RUF rules.
Fixes
- Fixed broken dependency path (
../../clients/python→../client-py). - Fixed dependency name (
donglora-python→donglora). - Applied
contextlib.suppresswhere ruff/SIM105 flagged try-except-pass. - Collapsed nested
ifper ruff/SIM102.
0.1.0 — 2026-04-06
Initial release.