You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+10-2Lines changed: 10 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@
5
5
6
6
## Project Overview
7
7
8
-
`rustyfarian-network` is a Rust workspace providing Wi-Fi, MQTT, LoRa, and ESP-NOW networking libraries for ESP32 firmware.
8
+
`rustyfarian-network` is a Rust workspace providing Wi-Fi, MQTT, LoRa, ESP-NOW, and OTA networking libraries for ESP32 firmware.
9
9
Two implementation tiers coexist: an ESP-IDF tier (`rustyfarian-esp-idf-*`, std-based) and a bare-metal `esp-hal` tier (`rustyfarian-esp-hal-*`, no_std).
10
10
Both tiers share platform-independent `*-pure` crates that compile and unit-test on any host without the ESP toolchain.
11
11
@@ -19,6 +19,7 @@ ADRs in `docs/adr/` document each architectural split.
Pure crates contain validation, types, traits, state machines, and timing math.
@@ -41,7 +42,7 @@ just run <name> # flash + serial monitor
41
42
42
43
Run `just fmt` before `just verify` — the latter's `fmt-check` will reject unformatted code.
43
44
`just verify` only compiles the workspace default target (`riscv32imac-esp-espidf`); use `just build-example <name>` to validate Xtensa IDF and bare-metal targets.
44
-
Pure crates iterate fast without the ESP toolchain — see `just check-wifi-pure`, `just test-wifi`, etc.
45
+
Pure crates iterate fast without the ESP toolchain — see `just check-wifi-pure`, `just test-wifi`, `just test-ota`, etc.
45
46
46
47
## Key Conventions
47
48
@@ -54,6 +55,13 @@ Pure crates iterate fast without the ESP toolchain — see `just check-wifi-pure
54
55
-**Cross-repo git deps** must be pinned with `tag` or `rev` — the workspace pulls in `links = "..."` crates that fail to resolve if upstream bumps without coordination.
55
56
-**License:** dual MIT / Apache-2.0 (see `LICENSE`).
56
57
58
+
## Coding Principles
59
+
60
+
-**State assumptions** before starting. If a task has multiple valid interpretations, present them rather than picking silently.
61
+
-**Simplicity first.** Minimum code that solves the problem. No features beyond what was asked. No abstractions for single-use code. No error handling for impossible scenarios.
62
+
-**Surgical changes.** Touch only what the task requires. Do not improve adjacent code, comments, or formatting. Every changed line should trace directly to the user's request.
63
+
- When your changes create orphans (unused imports, variables, functions), remove them. Do not remove pre-existing dead code unless asked.
|`.with_startup_message()` opt-in on `MqttBuilder`| Batteries-included: consumer opts in once, crate handles the rest on every (re)connect automatically |`MqttHandle::send_startup_message()` (manual call) — caller would need to wire it themselves in `on_connect`|
8
+
| Publish via `client.enqueue()` inside the builder's wrapped `on_connect`|`enqueue` is non-blocking and safe to call from a callback context |`MqttHandle::publish()` — holds the Mutex, deadlocks when called from inside a callback |
9
+
| Topic and payload hardcoded to `iot/{client_id}/startup` / `"1"`| Matches the old `MqttManager.send_startup_message()` convention; YAGNI — no consumer has requested customisation | Configurable topic/payload — deferred to v2 if a real need arises |
10
+
| Update `send_startup_message()` deprecation notice | Gives consumers a clear migration path to `.with_startup_message()`| Leave notice as-is — unhelpful without a pointer to the replacement |
11
+
12
+
## Constraints
13
+
14
+
- Must use `client.enqueue()` (passed into `on_connect`), not `MqttHandle::publish()` — the latter acquires the Mutex and deadlocks from a callback context.
15
+
- Topic must interpolate `client_id`, which is available from `MqttConfig` at `.build()` time — no runtime lookup needed.
16
+
- Must fire on every (re)connect, not just the first — consistent with `MqttBuilder`'s reconnect transparency.
17
+
18
+
## Open Questions
19
+
20
+
_(none)_
21
+
22
+
## State
23
+
24
+
-[x] Design approved
25
+
-[ ] Core implementation
26
+
-[ ] Tests passing
27
+
-[ ] Documentation updated
28
+
29
+
## Session Log
30
+
31
+
- 2026-05-12 — Feature doc created via /feature dialog
-`WifiError::Disconnected` is now a tuple variant `Disconnected(DisconnectedStationInfo)` — pattern matches that previously used the unit variant break
109
109
-`controller.is_connected()` returns `bool` directly, not `Result<bool, WifiError>`
110
-
-`controller.connect()`, `disconnect()`, `start()` (sync) — all removed; replacements are `connect_async().await`, `disconnect_async().await`; `set_config()` is now idempotent and implicitly starts the controller and begins association
110
+
-`controller.connect()`, `disconnect()`, `start()` (sync) — all removed; replacements are `connect_async().await`, `disconnect_async().await`; `set_config()` is now idempotent and starts the radio (`esp_wifi_start`) but does **not** initiate association — `connect_async()` must still be called explicitly
111
111
-`controller.wait_for_event(WifiEvent::StaDisconnected)` removed; replacement is `controller.wait_for_disconnect_async().await -> Result<DisconnectedStationInfo, WifiError>`
112
112
-`esp_radio::wifi::new()` signature is now `(WIFI<'d>, ControllerConfig)` — the prior `radio_ref` parameter is gone; `esp_radio::init()` is now `pub(crate)` and not part of user code
0 commit comments