|
| 1 | +# AGENTS.md — Navien ESPHome Integration |
| 2 | + |
| 3 | +## What this repository is |
| 4 | +This repository provides: |
| 5 | +- An ESPHome external component for local control and telemetry of Navien water heaters via RS-485 |
| 6 | +- Reverse-engineered protocol documentation, traces, and message decoding notes |
| 7 | +- Optional hardware reference materials for DIY controller builds |
| 8 | + |
| 9 | +Primary goal: reliable, local Home Assistant integration without proprietary cloud dependencies. |
| 10 | + |
| 11 | +The root README is the source of truth for end-user setup and supported configurations. |
| 12 | + |
| 13 | +## Scope & boundaries |
| 14 | +- Prefer **backwards-compatible** changes; avoid breaking existing YAML keys, entity names, or IDs. |
| 15 | +- Protocol changes must be documented under `doc/` with examples. |
| 16 | +- Do **not** add cloud-based features or proprietary APIs. |
| 17 | +- **Safety first**: never recommend wiring to unknown or high-voltage pins; explicitly warn when a pin is known to be ~14V or otherwise unsafe. |
| 18 | + |
| 19 | +## Repository layout |
| 20 | +- `esphome/` — ESPHome external component and example YAMLs |
| 21 | +- `doc/` — protocol reverse-engineering notes and field documentation |
| 22 | +- `trace/rs485/` — RS-485 captures used for validation |
| 23 | +- `hardware/` — PCB, connector, and harness reference designs |
| 24 | +- `src/` — implementation details (protocol parsing, entities) |
| 25 | + |
| 26 | +## Supported workflows |
| 27 | + |
| 28 | +### Build / compile |
| 29 | +Follow the workflow in the root README: |
| 30 | +- Install ESPHome (`pip install esphome`) |
| 31 | +- Copy secrets (`cp secrets.yaml.sample secrets.yaml`) |
| 32 | +- Compile: `esphome compile <config>.yml` |
| 33 | +- Flash/run: `esphome run <config>.yml` |
| 34 | + |
| 35 | +ESPHome versions can introduce breaking changes; follow README version guidance. |
| 36 | + |
| 37 | +### Runtime validation |
| 38 | +When modifying protocol parsing or entity behavior: |
| 39 | +- Enable DEBUG logging and capture at least one full request/response cycle |
| 40 | +- Verify: |
| 41 | + - Stable RS-485 connection |
| 42 | + - Sensors update correctly |
| 43 | + - Controls (power, hot button, target temp) still work on known-good models |
| 44 | + |
| 45 | +### Protocol decode changes (required checklist) |
| 46 | +If protocol parsing changes: |
| 47 | +1. Update documentation in `doc/` (byte offsets, scaling, meaning) |
| 48 | +2. Include at least one example frame (raw bytes + decoded values) |
| 49 | +3. Document model-specific behavior (e.g., NPE vs NCB) |
| 50 | +4. Preserve unknown bytes or log them; do not silently drop data |
| 51 | + |
| 52 | +## C++ conventions & formatting |
| 53 | + |
| 54 | +### Indentation / whitespace (required) |
| 55 | +- **Spaces only. No tabs.** |
| 56 | +- Use **2 spaces** for indentation. |
| 57 | +- Strip trailing whitespace. |
| 58 | +- End all files with a newline. |
| 59 | + |
| 60 | +### Style |
| 61 | +- Favor readability over cleverness. |
| 62 | +- Keep functions short and single-purpose. |
| 63 | +- Use `const` where applicable; pass large objects by `const&`. |
| 64 | +- Prefer `enum class` for new enums. |
| 65 | +- Avoid macros unless required by ESPHome. |
| 66 | + |
| 67 | +### Memory & dependencies (embedded best practices) |
| 68 | +- **Avoid the C++ standard library** (`std::vector`, `std::map`, `std::string`, streams, etc.). |
| 69 | +- **Do not use dynamic allocation**: |
| 70 | + - No `malloc` / `free` |
| 71 | + - No `new` / `delete` |
| 72 | +- Prefer **statically allocated or stack-allocated C data structures**: |
| 73 | + - Fixed-size arrays and ring buffers |
| 74 | + - POD `struct`s with explicit sizes |
| 75 | + - Preallocated buffers with strict bounds checks |
| 76 | +- If dynamic allocation is absolutely unavoidable: |
| 77 | + - Justify it clearly in the PR |
| 78 | + - Ensure it never occurs in `loop()` or hot paths |
| 79 | + - Document ownership and lifetime explicitly |
| 80 | + |
| 81 | +### Safety & performance |
| 82 | +- Never block in hot paths (`loop()`, callbacks). |
| 83 | +- Avoid long delays or busy waits. |
| 84 | +- Minimize allocations and heavy string operations. |
| 85 | +- Treat all inbound RS-485 data as untrusted: |
| 86 | + - Validate lengths before indexing |
| 87 | + - Verify checksums/CRCs if available |
| 88 | + |
| 89 | +### Logging |
| 90 | +- Use ESPHome logging macros (`ESP_LOGD`, `ESP_LOGI`, `ESP_LOGW`). |
| 91 | +- Log unknown or unsupported frames at DEBUG with: |
| 92 | + - Message/opcode (if known) |
| 93 | + - Raw bytes (trimmed if large) |
| 94 | +- Avoid log spam in steady state; throttle repeated warnings. |
| 95 | + |
| 96 | +### Protocol parsing conventions |
| 97 | +- Centralize parsing logic; do not duplicate byte-offset logic. |
| 98 | +- Keep conversion math close to decode logic and comment units. |
| 99 | +- Isolate model-specific branching and document it. |
| 100 | + |
| 101 | +## Adding a new exposed metric (recommended flow) |
| 102 | +1. Identify the field in traces (`trace/rs485/`) |
| 103 | +2. Document it in `doc/` (offsets, scaling, examples) |
| 104 | +3. Implement decode + conversion |
| 105 | +4. Expose via ESPHome entity |
| 106 | +5. Update README or example YAML if user-visible |
| 107 | + |
| 108 | +## Communication & contributions |
| 109 | +- When handling issues/PRs: |
| 110 | + - Ask for model info and PCB/front-panel photos when relevant |
| 111 | + - Request RS-485 traces and ESPHome logs |
| 112 | + - Avoid speculative electrical advice; call out unverified assumptions |
| 113 | + |
| 114 | +## What not to do |
| 115 | +- Do not recommend bypassing safety systems or modifying heater internals. |
| 116 | +- Do not introduce breaking renames without strong justification and migration notes. |
| 117 | +- Do not add “magic” auto-detection that can misconfigure pins or voltage assumptions. |
0 commit comments