# Changelog ## 1.0.0 — 2026-04-22 The 1.0 Python client, mirroring the Rust client 1.0 API and the DongLoRa Protocol v2 wire format. ### Breaking - **DongLoRa Protocol v2 wire format** (wire-incompatible with 0.x firmware and clients). All message types, tag correlation, and framing now follow `PROTOCOL.md` v1.0. - **Module split.** Monolithic `protocol.py` / `client.py` are replaced with: `dongle.py` (high-level async `Dongle`), `session.py` (reader task, tag routing, keepalive), `frame.py` (streaming `FrameDecoder` + `encode_frame`), `commands.py` / `events.py` / `errors.py` / `modulation.py` / `info.py` / `crc.py`, matching the `donglora-protocol` Rust crate module-for-module. - **Async API throughout.** Serial I/O via `asyncio-serial`; mux connections via `asyncio` streams. The blocking client surface is gone. - **New error hierarchy.** `DongloraError` base with `Timeout`, `TransportClosed`, `ReaderExited`, `BadFrame`, and `ErrClient...` variants mirroring the Rust client's `ClientError`. ### Added - Tag-aware dispatch with concurrent in-flight commands. The `TagAllocator` hands out 16-bit device tags; `Session` routes each response back to the originating coroutine. - Auto-recovery from `ERR(ENOTCONFIGURED)`. The `Dongle` caches the last `SET_CONFIG` and silently re-applies it on timeout, retrying once. - 500 ms background keepalive task per `PROTOCOL.md §3.4`. - Sticky mux reconnect: once a mux connection succeeds, all future `connect()` calls in the same process only try the mux (waiting for it to reappear if needed). `try_connect()` raises immediately so callers can retry with backoff. Prevents clients from stealing the serial port during mux restarts. ### Test suite - New tests: `test_dongle`, `test_session`, `test_frame`, `test_events`, `test_modulation`, `test_crc`, `test_ergonomics`. - Removed: `test_client`, `test_protocol` (superseded). ## 0.2.0 — 2026-04-08 ### Features - **Module split matching Rust structure** — split monolithic `__init__.py` into `protocol.py`, `codec.py`, `discovery.py`, `transport.py`, `connect.py`, and `client.py`. All symbols re-exported from top-level for backwards compatibility. - **Ping-on-connect validation** — all connect functions automatically ping the device and reject non-DongLoRa devices within 200 ms (matches Rust v0.2.0). - **`try_connect(timeout)`** — non-blocking alternative to `connect()`. Returns an error immediately if no device is found. - **`connect_default()`** — convenience wrapper with default timeout. - **`connect_mux_auto(timeout)`** — mux-only connection, never falls back to USB serial. Equivalent of Rust client's "sticky mux" behaviour. - **`default_socket_path()`** — resolve the preferred mux socket path. - **`validate(ser)`** — public function for manual device validation. - **Payload size validation** — `encode_command("Transmit", ...)` rejects payloads exceeding 256 bytes. - **`Bandwidth` and `ErrorCode` enums** — `IntEnum` types matching the Rust definitions. - **`RadioConfig` TypedDict** — typed dict for radio configuration. - **New constants** — `MAX_PAYLOAD`, `RADIO_CONFIG_SIZE`, `CMD_TAG_*`, `RESP_TAG_*`, `ERROR_*` tag/error constants. - **`py.typed` marker** — PEP 561 support for type checkers. - **Comprehensive test suite** — 46 tests ported from the Rust client covering protocol roundtrips, COBS framing, client send/recv, firmware wire compatibility. - **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. ### Breaking changes - **Package renamed back to `donglora`** — the short-lived `donglora-python` name is reverted. Import as `import donglora` (was always the intended API). - **`connect()` no longer falls through from mux to USB serial** — if a mux socket file exists, the function commits to the mux or raises an error (matches Rust v0.2.1). This prevents port-stealing race conditions. - **Sticky mux global removed** — the module-level `_mux_mode` variable and `_reconnect_mux()` are gone. Use `connect_mux_auto()` for mux-only mode. - **`DEFAULT_CONFIG` now includes `cad: 1`** — previously relied on `encode_config()` defaulting it. ### Fixes - Fixed broken dependency paths that prevented `uv sync` from resolving. - Replaced `print()` calls with `logging` in discovery module. ## 0.1.0 — 2026-04-06 Initial release.