diff --git a/CHANGELOG.md b/CHANGELOG.md index f0abbe9..87d83c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.2.0] - 2026-05-06 + ### Changed - **BREAKING** `rustyfarian-esp-hal-wifi`: removed the synchronous `WiFiManager::init`, `init_with_led`, `wait_connected`, `get_ip`, `take_sta_device`, and the `WifiDriver` trait impl, along with the `S: StatusLed` generic on `WiFiManager` and the `WifiError::{StartFailed, ConnectFailed, DisconnectFailed, RadioInitFailed}` variants — `esp-radio 0.18` removed direct `smoltcp` integration and made the bare-metal Wi-Fi controller async-only, so the sync surface no longer has a backing driver. The async path (`WiFiManager::init_async` + `AsyncWifiHandle`) is now the only public surface; the `embassy` Cargo feature is therefore effectively required alongside any chip feature - **BREAKING** `rustyfarian-esp-hal-wifi`: removed the `hal_c3_connect`, `hal_c6_connect`, `hal_c3_wifi_raw`, `hal_c6_wifi_raw`, and `hal_c6_connect_nonblocking_rgb` examples — all depended on the deleted sync smoltcp path; the three remaining `hal_*_async*` examples cover ESP32-C3 + ESP32-C6 in headless and LED-feedback variants +- **April 2026 esp-hal stack wave** — coordinated workspace-wide bump of every bare-metal crate to exact pins (`Cargo.toml` `[workspace.dependencies]`): `esp-hal 1.0.0`→`=1.1.0`, `esp-rtos 0.2.0`→`=0.3.0`, `esp-radio 0.17.0`→`=0.18.0`, `esp-bootloader-esp-idf 0.4.0`→`=0.5.0`, `esp-alloc 0.9.0`→`=0.10.0`, `esp-println 0.16.1`→`=0.17.0`, `esp-backtrace 0.18.1`→`=0.19.0`; embassy ecosystem `embassy-executor 0.9`→`=0.10.0`, `embassy-net 0.7`→`=0.8.0`, `embassy-time 0.5`→`=0.5.1`, `embassy-sync` newly pinned at `=0.8.0`. `smoltcp` is now exact-pinned at `=0.12.0` but is no longer a direct dependency of `rustyfarian-esp-hal-wifi` — `esp-radio 0.18` removed the `smoltcp` feature in favour of `embassy-net-driver`. Coordinated with `rustyfarian-ws2812`'s April 2026 wave (see `docs/features/archive/esp-hal-stack-upgrade-april-2026-v1.md`) +- ws2812 cross-repo dependencies (`led-effects`, `rustyfarian-esp-idf-ws2812`, `rustyfarian-esp-hal-ws2812`) re-pinned from `tag = "v0.4.0"` to `tag = "v0.5.0"` — v0.5.0 is the April 2026 wave release that ships the matching exact pins for `esp-hal`/`esp-rtos`/`esp-radio`, so the resolved feature graph stays unified with this workspace's bare-metal stack +- **BREAKING** `rustyfarian-esp-hal-wifi`: API renames flowing through from `esp-radio 0.18` — `WifiDevice` → `Interface`, `ModeConfig::Client(ClientConfig)` → `Config::Station(StationConfig)`, `Interfaces.sta` → `.station`, `WifiEvent::StaDisconnected` → `StationDisconnected`, `WifiError::Disconnected` is now a tuple variant carrying `DisconnectedStationInfo`, `controller.is_connected()` returns `bool` directly (not `Result`), `controller.connect()`/`disconnect()` are async-only (`connect_async`/`disconnect_async`), `controller.wait_for_event(StaDisconnected)` becomes `wait_for_disconnect_async`, `esp_radio::wifi::new()` is now `(WIFI, ControllerConfig)` (the radio init parameter is gone — radio init is implicit) +- **BREAKING** `rustyfarian-esp-hal-wifi`: `set_config` is now idempotent in `esp-radio 0.18` and implicitly starts the controller and initiates association — the explicit `start()`/`connect()` calls that existed in 0.17 are no longer needed (or available) +- `rustyfarian-esp-idf-espnow`: `default_interface()` always returns `WifiInterface::Sta` — `init_with_radio()` starts in STA mode, not AP (fixes `ESP_ERR_ESPNOW_IF` on send) +- `sdkconfig.defaults`: added `CONFIG_ESP_WIFI_NVS_ENABLED=n` to prevent stale WiFi credential caching ### Added @@ -57,15 +65,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Justfile: `ESPFLASH_PORT` env var for multi-board setups, `fresh-run` and `erase-flash` recipes, `--non-interactive` monitor - Build scripts: `*wifi*` and `*espnow*` crate auto-detection in `build-example.sh` and `flash.sh` -### Changed - -- **April 2026 esp-hal stack wave** — coordinated workspace-wide bump of every bare-metal crate to exact pins (`Cargo.toml` `[workspace.dependencies]`): `esp-hal 1.0.0`→`=1.1.0`, `esp-rtos 0.2.0`→`=0.3.0`, `esp-radio 0.17.0`→`=0.18.0`, `esp-bootloader-esp-idf 0.4.0`→`=0.5.0`, `esp-alloc 0.9.0`→`=0.10.0`, `esp-println 0.16.1`→`=0.17.0`, `esp-backtrace 0.18.1`→`=0.19.0`; embassy ecosystem `embassy-executor 0.9`→`=0.10.0`, `embassy-net 0.7`→`=0.8.0`, `embassy-time 0.5`→`=0.5.1`, `embassy-sync` newly pinned at `=0.8.0`. `smoltcp` is now exact-pinned at `=0.12.0` but is no longer a direct dependency of `rustyfarian-esp-hal-wifi` — `esp-radio 0.18` removed the `smoltcp` feature in favour of `embassy-net-driver`. Coordinated with `rustyfarian-ws2812`'s April 2026 wave (see `docs/features/archive/esp-hal-stack-upgrade-april-2026-v1.md`) -- ws2812 cross-repo dependencies (`led-effects`, `rustyfarian-esp-idf-ws2812`, `rustyfarian-esp-hal-ws2812`) re-pinned from `tag = "v0.4.0"` to `tag = "v0.5.0"` — v0.5.0 is the April 2026 wave release that ships the matching exact pins for `esp-hal`/`esp-rtos`/`esp-radio`, so the resolved feature graph stays unified with this workspace's bare-metal stack -- **BREAKING** `rustyfarian-esp-hal-wifi`: API renames flowing through from `esp-radio 0.18` — `WifiDevice` → `Interface`, `ModeConfig::Client(ClientConfig)` → `Config::Station(StationConfig)`, `Interfaces.sta` → `.station`, `WifiEvent::StaDisconnected` → `StationDisconnected`, `WifiError::Disconnected` is now a tuple variant carrying `DisconnectedStationInfo`, `controller.is_connected()` returns `bool` directly (not `Result`), `controller.connect()`/`disconnect()` are async-only (`connect_async`/`disconnect_async`), `controller.wait_for_event(StaDisconnected)` becomes `wait_for_disconnect_async`, `esp_radio::wifi::new()` is now `(WIFI, ControllerConfig)` (the radio init parameter is gone — radio init is implicit) -- **BREAKING** `rustyfarian-esp-hal-wifi`: `set_config` is now idempotent in `esp-radio 0.18` and implicitly starts the controller and initiates association — the explicit `start()`/`connect()` calls that existed in 0.17 are no longer needed (or available) -- `rustyfarian-esp-idf-espnow`: `default_interface()` always returns `WifiInterface::Sta` — `init_with_radio()` starts in STA mode, not AP (fixes `ESP_ERR_ESPNOW_IF` on send) -- `sdkconfig.defaults`: added `CONFIG_ESP_WIFI_NVS_ENABLED=n` to prevent stale WiFi credential caching - ### Fixed - `rustyfarian-esp-idf-espnow`: `scan_for_peer()` and `send_and_wait()` now serialise their send-callback registration through an internal mutex — concurrent calls can no longer steal each other's ACKs @@ -88,3 +87,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Dual-HAL script infrastructure: `build-example.sh`, `flash.sh`, `ensure-bootloader.sh`, and `xtensa-toolchain.sh` for `hal_*` bare-metal targets - Examples: `idf_c3_connect`, `idf_c3_mqtt`, `idf_esp32_mqtt`; hardware reference `docs/heltec-wifi-lora-32-v3.md` - CI: pure-crate test job for all host tests (`rustyfarian-network-pure`, `wifi-pure`, `lora-pure`, `espnow-pure`) + +[Unreleased]: https://github.com/datenkollektiv/rustyfarian-network/compare/v0.2.0...HEAD +[0.2.0]: https://github.com/datenkollektiv/rustyfarian-network/compare/v0.1.0...v0.2.0 +[0.1.0]: https://github.com/datenkollektiv/rustyfarian-network/releases/tag/v0.1.0 diff --git a/Cargo.toml b/Cargo.toml index fed6112..68e1b82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ resolver = "2" members = ["crates/*"] [workspace.package] +version = "0.2.0" authors = ["datenkollektiv"] edition = "2021" license = "MIT OR Apache-2.0" diff --git a/crates/espnow-pure/Cargo.toml b/crates/espnow-pure/Cargo.toml index 103a713..91d01e5 100644 --- a/crates/espnow-pure/Cargo.toml +++ b/crates/espnow-pure/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "espnow-pure" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/lora-pure/Cargo.toml b/crates/lora-pure/Cargo.toml index dc5bac0..0c03c60 100644 --- a/crates/lora-pure/Cargo.toml +++ b/crates/lora-pure/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lora-pure" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/ota-pure/Cargo.toml b/crates/ota-pure/Cargo.toml index 1114e0c..26188a8 100644 --- a/crates/ota-pure/Cargo.toml +++ b/crates/ota-pure/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ota-pure" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/rustyfarian-esp-hal-lora/Cargo.toml b/crates/rustyfarian-esp-hal-lora/Cargo.toml index bb82d5b..eb9ac00 100644 --- a/crates/rustyfarian-esp-hal-lora/Cargo.toml +++ b/crates/rustyfarian-esp-hal-lora/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyfarian-esp-hal-lora" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/rustyfarian-esp-hal-ota/Cargo.toml b/crates/rustyfarian-esp-hal-ota/Cargo.toml index 5d061cf..cf8584e 100644 --- a/crates/rustyfarian-esp-hal-ota/Cargo.toml +++ b/crates/rustyfarian-esp-hal-ota/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyfarian-esp-hal-ota" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/rustyfarian-esp-hal-wifi/Cargo.toml b/crates/rustyfarian-esp-hal-wifi/Cargo.toml index 53b818e..2eee8ae 100644 --- a/crates/rustyfarian-esp-hal-wifi/Cargo.toml +++ b/crates/rustyfarian-esp-hal-wifi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyfarian-esp-hal-wifi" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/rustyfarian-esp-idf-espnow/Cargo.toml b/crates/rustyfarian-esp-idf-espnow/Cargo.toml index a185f32..2936228 100644 --- a/crates/rustyfarian-esp-idf-espnow/Cargo.toml +++ b/crates/rustyfarian-esp-idf-espnow/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyfarian-esp-idf-espnow" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/rustyfarian-esp-idf-lora/Cargo.toml b/crates/rustyfarian-esp-idf-lora/Cargo.toml index 05e5199..de54ff4 100644 --- a/crates/rustyfarian-esp-idf-lora/Cargo.toml +++ b/crates/rustyfarian-esp-idf-lora/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyfarian-esp-idf-lora" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/rustyfarian-esp-idf-mqtt/Cargo.toml b/crates/rustyfarian-esp-idf-mqtt/Cargo.toml index 8c09c1c..5e2ff75 100644 --- a/crates/rustyfarian-esp-idf-mqtt/Cargo.toml +++ b/crates/rustyfarian-esp-idf-mqtt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyfarian-esp-idf-mqtt" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/rustyfarian-esp-idf-ota/Cargo.toml b/crates/rustyfarian-esp-idf-ota/Cargo.toml index 51090c7..85957f4 100644 --- a/crates/rustyfarian-esp-idf-ota/Cargo.toml +++ b/crates/rustyfarian-esp-idf-ota/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyfarian-esp-idf-ota" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/rustyfarian-esp-idf-wifi/Cargo.toml b/crates/rustyfarian-esp-idf-wifi/Cargo.toml index 3baf808..1eb0b56 100644 --- a/crates/rustyfarian-esp-idf-wifi/Cargo.toml +++ b/crates/rustyfarian-esp-idf-wifi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyfarian-esp-idf-wifi" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/rustyfarian-network-pure/Cargo.toml b/crates/rustyfarian-network-pure/Cargo.toml index 058b7a0..8189074 100644 --- a/crates/rustyfarian-network-pure/Cargo.toml +++ b/crates/rustyfarian-network-pure/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyfarian-network-pure" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/wifi-pure/Cargo.toml b/crates/wifi-pure/Cargo.toml index 52855c1..44c210e 100644 --- a/crates/wifi-pure/Cargo.toml +++ b/crates/wifi-pure/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wifi-pure" -version = "0.1.0" +version.workspace = true authors.workspace = true edition.workspace = true license.workspace = true diff --git a/release-plan.md b/release-plan.md new file mode 100644 index 0000000..878aaab --- /dev/null +++ b/release-plan.md @@ -0,0 +1,87 @@ +# Release Plan + +Release process for `rustyfarian-network`. +Covers versioning, pre-flight checks, publish targets, and post-release steps. + +## Versioning + +- **Scheme:** SemVer (pre-1.0 — minor bumps signal breaking changes) +- **Lockstep:** all 13 workspace crates move together at the same version +- **Snapshot convention:** none (we tag the release commit, no `-SNAPSHOT` between releases) +- **Who decides version:** maintainer, based on `CHANGELOG.md` `[Unreleased]` content + +## Branch and Tag Convention + +- **Release branch:** `prepare-release` → merged to `main` after publish +- **Tag format:** `vX.Y.Z` (annotated) +- **Tagging:** manual on the release commit on `main` + +## Pre-flight Checklist + +Before any release: +- [ ] Working tree clean on `prepare-release` (untracked `review-queue/` is OK) +- [ ] `just fmt` clean +- [ ] `just verify` passes (fmt-check + cargo deny + check + clippy) +- [ ] `just test` passes (all pure-crate host tests) +- [ ] At least one hardware example builds via `just build-example ` for each tier touched (sanity check; not exhaustive) +- [ ] `cargo audit` shows no new advisories beyond those allow-listed in `deny.toml` +- [ ] `CHANGELOG.md` `[Unreleased]` has entries for the target version +- [ ] `[workspace.package].version` in root `Cargo.toml` matches the target version; no member crate overrides it (each declares `version.workspace = true`) + +## Version Bump + +Single source of truth: `[workspace.package].version` in the root `Cargo.toml`. +Each member crate inherits via `version.workspace = true`, so a release bump is one edit. + +Post-release bump target: none (next-version bump happens when the next `[Unreleased]` block is finalised) + +## Publish + +**Target registry:** none — tag-only on GitHub +**Tag command (on the release commit):** + +```sh +git tag -a vX.Y.Z -m "vX.Y.Z" +git push origin vX.Y.Z +``` + +**Branch push:** `git push origin main` (or open a PR from `prepare-release` → `main` and merge) +**Credentials:** standard GitHub push credentials (no registry tokens needed) +**Signing:** not required (commit / tag GPG signing optional, follow whatever git is already configured to do) + +## Changelog + +**Location:** `CHANGELOG.md` +**Format:** Keep a Changelog 1.1.0 +**Process:** rename `## [Unreleased]` to `## [X.Y.Z] - YYYY-MM-DD`; create a fresh empty `## [Unreleased]` block above it for next cycle + +## GitHub Release + +- [ ] Create release page at: `https://github.com/datenkollektiv/rustyfarian-network/releases/new` +- [ ] Use tag `vX.Y.Z` +- [ ] Title: `vX.Y.Z` +- [ ] Body: paste the `## [X.Y.Z]` section from `CHANGELOG.md` +- [ ] No artifact attachments (workspace is library crates; users consume via git dep) + +## Post-release Steps + +- [ ] Merge `prepare-release` → `main` (fast-forward) +- [ ] Update `docs/ROADMAP.md` if any items shipped in this release are still listed as in-progress +- [ ] Verify the GitHub release page is publicly visible and the tag resolves + +## Rollback Procedure + +If a release must be retracted after tagging: +1. Delete remote tag: `git push --delete origin vX.Y.Z` +2. Delete local tag: `git tag -d vX.Y.Z` +3. Delete the GitHub release page (via web UI or `gh release delete vX.Y.Z`) +4. Revert the release commit on `main`: `git revert ` and push + +Note: because nothing is published to a registry, rollback is fully reversible. + +## Release Record Location + +Each release produces files in `release/`: +1. `YYYY-MM-DD--preflight.md` — pre-flight assessment +2. `YYYY-MM-DD--plan.md` — ordered execution plan +3. `YYYY-MM-DD--record.md` — what was published and what remains