canbus: add Fable session handoff doc (assembly + flash + open items)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,103 @@
|
|||||||
|
# Handoff — finish & flash the OneControl IDS-CAN node
|
||||||
|
|
||||||
|
**Goal:** complete and flash an ESP32 firmware that puts our RV's Lippert
|
||||||
|
OneControl system (tanks, lights, switches) into Home Assistant as native
|
||||||
|
entities, talking directly to the OneControl CAN network. This replaces the
|
||||||
|
slower Bluetooth integration in `../src/` + `../custom_components/`.
|
||||||
|
|
||||||
|
Read `README.md` first — it has the full message-format documentation, the node
|
||||||
|
map for this coach, and the wiring procedure. This file is just the current
|
||||||
|
state + what's left.
|
||||||
|
|
||||||
|
## Current status (2026-06-12)
|
||||||
|
|
||||||
|
- **Message format documented and confirmed against live captures.** The bus is
|
||||||
|
Lippert **IDS-CAN** (250 kbit/s, 11-bit IDs), not RV-C. Every tank, light,
|
||||||
|
pump, heater, the awning, and battery voltage is decoded — see the node map in
|
||||||
|
`README.md`.
|
||||||
|
- **Read path:** modules broadcast their state continuously, no authentication.
|
||||||
|
- **Command path:** each command is preceded by a short challenge/response
|
||||||
|
authentication exchange (the same one the OEM app uses). Implemented in
|
||||||
|
`ids_can_auth.py` (reference) and `esphome/ids_can_auth.h` (the firmware copy,
|
||||||
|
verified **bit-exact** against the Python and against captured/live values).
|
||||||
|
- **Proven working end to end.** `idscan_cmd.py` ran the full exchange over a USB
|
||||||
|
CAN adapter and operated the interior lights (node `F8`) on/off/on, each
|
||||||
|
answering a distinct fresh challenge, with the module's own status broadcast
|
||||||
|
confirming the result. A bare command with no exchange is ignored.
|
||||||
|
- **Firmware compiled successfully** last night (`esphome/.esphome/build/…`).
|
||||||
|
|
||||||
|
## Hardware (assembly-ready)
|
||||||
|
|
||||||
|
- ESP32 WROOM devboard (`esp32dev`) + Waveshare **SN65HVD230** transceiver
|
||||||
|
(3.3 V logic, onboard 120 Ω terminator → this node is the bus-END node).
|
||||||
|
- **Power:** buck converter dialed to **5 V**, tapped from the panel's 12 V
|
||||||
|
supply (common ground with the bus — good). Feed the ESP32 5 V pin.
|
||||||
|
- **Connection:** Molex Mini-Fit Jr. pigtail into the panel's CAN **data** port
|
||||||
|
(the one with the terminator), per `README.md` → "Physical connection".
|
||||||
|
⚠️ Meter the port first: data idles ~2.5 V, power reads ~12 V; 12 V on CAN-H/L
|
||||||
|
destroys the transceiver.
|
||||||
|
- **GPIO:** transceiver `CTX/D` ← ESP32 `GPIO5` (tx_pin), `CRX/R` → `GPIO4`
|
||||||
|
(rx_pin). Adjust `substitutions:` in the YAML if you wire differently.
|
||||||
|
|
||||||
|
## Remaining work (in order)
|
||||||
|
|
||||||
|
1. **`secrets.yaml`** — copy `esphome/secrets.yaml.example`, fill in WiFi, the
|
||||||
|
ESPHome `api_key`, and the fallback-AP password. It's git-ignored.
|
||||||
|
2. **First flash over USB:** `esphome run esphome/onecontrol-canbus.yaml` (pick
|
||||||
|
the serial port). OTA after that. Mirrors the gazebo-fan-proxy workflow.
|
||||||
|
3. **Confirm the read entities populate** in HA once it's on the bus: the four
|
||||||
|
tanks and the two light switches publish from the page-3 broadcasts. Watch the
|
||||||
|
DEBUG frame dump (`logger: level: DEBUG`) to confirm frames are decoded; drop
|
||||||
|
to INFO when happy.
|
||||||
|
4. **Finish the two open read items in the YAML lambda:**
|
||||||
|
- **Battery voltage** — rides a 29-bit telemetry frame (src `7D`/`AE`,
|
||||||
|
page `0x11`), bytes 2–3 big-endian / 256 = volts. Match that frame and
|
||||||
|
publish `battery_voltage`. (See README "29-bit extended frames".)
|
||||||
|
- Optionally add **water pump (`61`)** and **water heater (`95`)** — both are
|
||||||
|
ordinary switched loads, same decode + command path as the lights.
|
||||||
|
5. **Verify the command path** from HA: toggle Interior/Exterior Lights. The
|
||||||
|
`send_load_command` script + `on_frame` handler do the exchange and send the
|
||||||
|
opcode. The node allowlist is **lights only** — keep movement nodes
|
||||||
|
(awning/slides/jacks, type `0x21`) off the switch list until a careful
|
||||||
|
attended first test.
|
||||||
|
6. **DSI fault `binary_sensor`** — see the section below (pending a capture).
|
||||||
|
7. **(Optional) Surface at the campsite HA + bridge home** like the gazebo fans /
|
||||||
|
OneControl BLE devices, if you want these in the home dashboard too.
|
||||||
|
|
||||||
|
## File map
|
||||||
|
|
||||||
|
| File | What it is |
|
||||||
|
|------|-----------|
|
||||||
|
| `esphome/onecontrol-canbus.yaml` | the ESP32 firmware (read dispatch + command path) — the thing to finish & flash |
|
||||||
|
| `esphome/ids_can_auth.h` | command-authentication response, used by the YAML lambda |
|
||||||
|
| `esphome/secrets.yaml.example` | template for the git-ignored secrets |
|
||||||
|
| `ids_can_auth.py` | Python reference for the same authentication + 51/51 self-test |
|
||||||
|
| `idscan_cmd.py` | desktop tool that proved the command path over a USB CAN adapter |
|
||||||
|
| `captures/` | raw bus logs + the challenge/response pairs + `analyze_auth.py` |
|
||||||
|
| `captures/log-can.sh` | bring up the USB CAN adapter and log frames |
|
||||||
|
| `README.md` | full message-format documentation + node map + wiring |
|
||||||
|
|
||||||
|
## Safety notes
|
||||||
|
|
||||||
|
- **Command path is lights-only by allowlist.** Movement nodes use the same
|
||||||
|
authentication but are untested from this node — don't add them until you can
|
||||||
|
watch the motor on the first actuation.
|
||||||
|
- The physical connection is fully reversible: unplug, re-seat the terminator.
|
||||||
|
- One transceiver = one bus-end terminator. Never add a terminated node in the
|
||||||
|
middle of the bus (would make three terminators).
|
||||||
|
|
||||||
|
## DSI fault — PENDING a fault capture
|
||||||
|
|
||||||
|
> The water-heater DSI (gas ignition) fault is almost certainly on the bus, but
|
||||||
|
> every capture so far is of a healthy heater, so the exact byte is unknown.
|
||||||
|
>
|
||||||
|
> **Capture plan (this session):** close the propane valve, run the water heater
|
||||||
|
> on gas until it locks out (DSI fault light on the panel), capture ~20 s, and
|
||||||
|
> diff against a healthy baseline (`captures/baseline-2026-06-11_223823.log`).
|
||||||
|
> Prime suspects (both sit at a constant "all-clear" value today):
|
||||||
|
> - node `95` (heater) page-3 `b1` — always `0xFF`; expect a bit to drop on fault.
|
||||||
|
> - node `AE` (type 0x27, ?LP-gas/diagnostics) page-3 — always `0x00`; expect non-zero on fault.
|
||||||
|
>
|
||||||
|
> **TODO once decoded:** record the node/page/byte/bit here, then add a
|
||||||
|
> `binary_sensor` to the YAML (`device_class: problem`) that reads it — the DSI
|
||||||
|
> fault the Bluetooth app never exposed.
|
||||||
Reference in New Issue
Block a user