canbus: hard safety gate — slides/jacks are control-panel only, never over CAN

Per policy, the firmware must never command a slide or jack. command_guard.h adds
command_blocked(node, type): refuses any motor-class (0x21) node except the
awning (0x75), with an explicit slide/jack denylist (6A/7F/9C) that holds even
before a node's page-2 identity is observed.

Enforced in two independent places — the command-entry script (send_load_command)
and the actual transmit point (on_frame, right before TX) — so loosening one
can't open the other. Adding a slide/jack switch entity cannot actuate it. Node
device class is learned from page-2 broadcasts (g_node_type). Predicate
unit-tested 9/9 (host g++). Switch comments + HANDOFF safety notes updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wes
2026-06-12 11:34:21 -04:00
co-authored by Claude Opus 4.8
parent d57c2b21d2
commit f05203b9e3
3 changed files with 93 additions and 10 deletions
+12 -3
View File
@@ -80,9 +80,18 @@ The DSI fault is already decoded and wired in (see below) — no capture needed.
## 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.
- **SLIDES AND JACKS ARE CONTROL-PANEL ONLY — never over CAN. This is a hard
rule, do not weaken it.** `esphome/command_guard.h` (`command_blocked()`) is the
single source of truth: it refuses any motor-class (0x21) node other than the
awning, via an explicit slide/jack denylist (6A/7F/9C, effective even before a
node's identity is heard) *and* a general class check. It's enforced in two
independent places — the command-entry script and the actual transmit point —
so loosening one does not open the other. Adding a slide/jack switch entity
cannot actuate it; the gate drops the command before any frame goes out.
- **Command path is otherwise lights-only by allowlist.** The awning is permitted
by the safety gate but intentionally left unwired (operate it from the panel).
To expose any new switched load, add its node to the layer-2 allowlist in
`send_load_command`; never add a slide/jack.
- 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).