diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c9573d..78264f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,48 @@ # Changelog -## Unreleased +## 1.0.0 โ€” 2026-04-22 -### Fixed +The 1.0 Python client, mirroring the Rust client 1.0 API and the +DongLoRa Protocol v2 wire format. -- 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. +### 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 diff --git a/pyproject.toml b/pyproject.toml index fff34fc..8fca133 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "donglora" -version = "0.2.0" +version = "1.0.0" description = "DongLoRa host library โ€” talk LoRa from Python over USB" license = "MIT" requires-python = ">=3.10" @@ -8,7 +8,7 @@ readme = "README.md" authors = [{ name = "Stephen Waits", email = "steve@waits.net" }] keywords = ["lora", "radio", "usb", "embedded", "serial"] classifiers = [ - "Development Status :: 3 - Alpha", + "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", diff --git a/uv.lock b/uv.lock index a86ec79..de6d718 100644 --- a/uv.lock +++ b/uv.lock @@ -296,7 +296,7 @@ wheels = [ [[package]] name = "donglora" -version = "0.2.0" +version = "1.0.0" source = { editable = "." } dependencies = [ { name = "cobs" },