For Agents

Living index of themes for this project. Each H2 is a topic; bullets are wikilinks to related notes. Updated by obsidian-documenter when documenting work. Read by historian at bootstrap. Topics kept alphabetical.

Buttons & Switch Wiring

  • NC conventiongreen NO, red NC, the industrial start/stop convention. Chosen for failure behaviour: a broken wire on an NO button is silent (reads as “never pressed”, indistinguishable from idle); NC fails loud (reads as permanently pressed). A stop that silently disables itself is the failure being designed out. The SS-5GL is SPDT, so NO/NC is a wiring choice, not a purchase
  • Wiring — finalboth buttons GPIO → contact → GND on internal pull-ups, zero external components. Green HIGH at rest / LOW pressed; red LOW at rest / HIGH pressed, inverted in one line of firmware. Red’s 73 µA continuous is irrelevant on mains and design-breaking on a cell
  • A normally-closed switch bleeds current continuously — the general form of the same rule

Cross-Project

  • esp32 — the cross-project ESP32 silicon/toolchain/wiring reference; read before touching the board
  • esp32-battery-deep-sleep — where this project’s NC-bias, ext1 polarity and WiFi-latency findings live in generalised form
  • inventory — the XIAO C3s, SS-5GL switches and JST-PH parts are on order, not owned
  • lightaim — the other ESP32 human-input project; single-button UX precedent
  • hardcut — same instinct as “a software stop is not a stop”: a 74HC74 hardware interlock makes the dangerous state physically unreachable rather than merely checked in firmware

Firmware / Protocol Design

  • Wire Format — the device has no opinion — ⭐ the load-bearing decision. The device sends {"button", "held_ms", "seq"} on release and nothing else; all gesture semantics live server-side. Rationale: gesture meaning becomes editable config — a long-press added two months later is a Python dict edit, not a reflash of a device that has to be physically opened. seq gives free lost-press detection; held_ms catches a stuck or broken switch (a 45 000 ms “press” is a fault, not a press)
  • Double-press does not tax every press — fire on release immediately, then linger ~350 ms (~0.004 mAh); the daemon buffers 300 ms ONLY for buttons that actually have a double binding, so single-binding buttons pay zero added latency

Mechanical & Enclosure

Power & Low Power

  • USB, always onmains, always on. The payoff is latency, not convenience: staying associated drops press-to-action from ~500 ms to ~30 ms
  • The Abandoned Battery Design — keep it, it is correct — ⭐ kept deliberately. NC to 3.3 V + 1 MΩ pull-DOWN, internal pulls off: standby 73 µA → 3.3 µA, and it forces both pins to the same edge because esp_sleep_enable_ext1_wakeup() takes ONE trigger level for the whole pin mask, not per-pin. Alternative: the ESP-IDF 5.x per-IO API
  • Latency Budget — naive vs tuned~2.6 s → ~500 ms via RTC-slow-memory BSSID/channel cache, static lease, literal IP, no TLS on LAN. ⚠️ Full-scan fallback is mandatory given documented router reflash / DFS churn

Safety & Failure Modes

  • The “contactor” misread — 🔴 “contactor” was misread as a load-switching contactor, producing a full mains-safety design for a project with no mains and no load (it was the contact blocks behind the pushbuttons). The topology is kept because the principle generalises: ⛔ red must stay hardwired in series with the coil so it physically breaks the circuit regardless of firmware — a software stop is not a stop

Transport & Networking

Unresolved

  • Unresolved — ❓ (1) Is the enclosure plastic or metal? It decides XIAO C3 (onboard antenna) vs a 32UE + U.FL external antenna, and the 32UE is the scarce antenna-capable stock — only 5 exist. Go look.(2) Toggle state ownershipproposed, NOT confirmed: the daemon queries the real target and inverts what it finds, with a stored-boolean fallback that logs loudly, because a stored boolean desyncs the moment anything else changes the target