Skip to main content

esp-hermes-channel

Build the ESP32-S3 (M5Stack) as a first-class Hermes voice channel — like Telegram/Desktop, not a standalone agent. Covers architecture, audio pipeline, 2-mode design (always-on VAD + push-to-talk), and petdex LCD rendering via gateway state-push.

Ir a la instalación

Datos de origen

Repositorio
ohrbit/hermes_plugins
Última actividad en el origen
17 de julio de 2026 a las 00:33
Idioma detectado de SKILL.md
inglés
Estrellas
3
Forks
0

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Explorador de archivos
4 archivos

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
esp-hermes-channel
description
Build the ESP32-S3 (M5Stack) as a first-class Hermes voice channel — like Telegram/Desktop, not a standalone agent. Covers architecture, audio pipeline, 2-mode design (always-on VAD + push-to-talk), and petdex LCD rendering via gateway state-push.
version
0.1.0
author
Hermes Agent
license
MIT
metadata
{"hermes":{"tags":["esp32","m5stack","hermes","voice-channel","iot","petdex","gateway"]}}
# ESP-Hermes Channel Turn an ESP32-S3 (M5Stack) into a **Hermes voice channel** — parity with Telegram/Desktop clients, NOT a standalone agent. Hermes (gateway) does STT + reasoning + tools + TTS + pet-state; the ESP does I/O only. ## Architecture ``` ESP32-S3 (esp-hermes firmware, C/Arduino) mic ──audio──▶ Hermes Gateway (:9119, like Telegram channel) │ ├─ STT (local faster-whisper / groq) ├─ Agent reasoning + tools + memory ├─ TTS (Edge TTS) ──audio──▶ speaker └─ Pet-State push (idle/run/review/error/done) ──▶ LCD ``` - ESP is a **gateway client**, not an LLM client. Do NOT use ESP-Claw's LLM mode — that makes the ESP a standalone agent. We want Hermes as the brain. - Channel parity table: | Feature | Desktop | Telegram | ESP32 | |---|---|---|---| | Send text/audio | ✓ | ✓ | ✓ (button→mic) | | Agent replies | ✓ | ✓ | ✓ (TTS→speaker) | | Pet on display | ✓ | ✗ | ✓ (LCD) | | Tool-calls | ✓ | ✓ | ✓ (via gateway) | ## Full Hardware Access (Hermes-controlled IoT Node) ESP is a **gateway client**, so the agent gets full tool-call access to the S3's IO — the device becomes Hermes' physical extremity. | IO | Access via Hermes | Example | |---|---|---| | **GPIO** (digital in/out) | Tool-Call → ESP sets/reads pin | relay, LED | | **I2C / SPI** (sensors, displays) | Tool-Call → Bus-Read/Write | external sensors | | **ADC** (analog, voltage, temp) | Tool-Call → `analogRead` | battery, thermistor | | **PWM** (LEDs, servos, motors) | Tool-Call → `ledcWrite` | dimming, servo | | **UART** (other MCUs) | Tool-Call → Serial passthrough | chain devices | | **Button/Touch** | Input-Event → triggers Hermes | PTT, mode toggle | | **IMU — Accelerometer + Gyroscope** | Tool-Call `esp_imu_read` **+ Event-Driven triggers** | motion/orientation/gesture | | **LCD** | Pet-State **+** arbitrary render output | pet + status | | **mic/speaker** | Voice-Channel (as discussed) | talk to Hermes | ### IMU (Accelerometer + Gyroscope) — special case M5Stack S3 includes a 6-axis IMU (accel + gyro). Not just readable — **event-driven**: - **Polled:** `esp_imu_read` → returns accel/gyro vector on demand ("what's the orientation?"). - **Event-Driven (recommended):** on-device motion detection triggers Hermes events without a prompt: - **Shake** → toggle always-on / PTT mode - **Tap** → PTT trigger (alt to button) - **Orientation flip** → context switch ("device picked up" → wake) - **Stillness timeout** → return to `idle` pet state - ESP runs lightweight motion filter (threshold/low-pass) so it doesn't spam the gateway with noise. Mirrors ESP-Claw's "Event Driven" feature — but the *brain* stays Hermes (gateway), not on-device Lua. ### Design Principles (user-driven — learned this session) - **Device = Hermes channel, not standalone agent.** ESP speaks to the gateway (WS); Hermes is the brain. Do NOT use ESP-Claw's LLM mode. - **Reuse vendor SDK/components** (ESP-Claw `common`/`edge_agent`) instead of rewriting from scratch. Strip the LLM client, keep hardware/IMU/event layers. - **Start small, phased** (voice-pet first, body later). Ship Phase 1, grow incrementally. User explicitly: "wir fangen klein an". - **MCP direction caution:** a device's MCP adapter usually makes the *device* the MCP *client* (it calls servers), so it does NOT grant Hermes access to the device. Don't assume reverse direction. - **Verify spec/benchmark numbers before stating them.** User corrects confident wrong claims — e.g. 200 TOPS NPU ≠ faster LLM than his S24 (real token speed wins); and LMArena ELO for gemma-4-31b (1451) was wrongly attributed to the 2B mobile variant. Check the number matches the exact model/size before claiming. ## Two Modes (REQUIRED) 1. **Push-to-talk (PTT):** Hold button → record → release → upload. Pet shows `recording` state while held. 2. **Always-on (VAD):** Continuous mic, on-device Voice Activity Detection triggers upload only on speech. Pet shows `listening` idle state; `run` while Hermes processes. Mode toggle: button short-press cycles modes, or gateway config push. Persist mode in ESP NVS. ## Audio Pipeline - Upload: raw PCM or OGG/Opus (M5 mic → encode → POST to gateway `/voice` or webhook). - Downlink: TTS audio streamed back → ESP decodes → speaker. - Codec decision pending hardware arrival (I2S mic + MAX98357 or built-in M5 speaker). ## Pet on LCD - petdex renderer runs on the **gateway** (Hermes side), not ESP. - Gateway pushes `pet_state` + frame data over the same channel socket (WebSocket recommended). - ESP LCD renders frames for current state. States: `idle`, `run`, `review`, `error`, `done`. - Pet slug chosen by user (same gallery as desktop — `hermes pets list`). ### petdex scope vs. custom IMU layer (IMPORTANT) petdex (verified): 3,317+ pets, Codex sprite format, 192×208 grid. Pets react to **agent-lifecycle states** (`idle`/`run`/`review`/`error`/`done`) — this is the foundation and works out-of-the-box for the ESP LCD. **Gap:** petdex does NOT react to physical device motion. IMU coupling (pet leans on tilt, dizzy on shake) is NOT a native petdex feature. Two integration paths: - **Path A (safe, compatible):** IMU → gateway maps motion to existing petdex states (`run`=busy, `done`=content). Always compatible, no custom frames. - **Path B (rich, custom):** add custom pet states (`tilt`, `shake`, `stretch`) — requires pets whose atlases contain those frames. Needs custom pet or petdex atlas extension. **Decision:** petdex = foundation (agent states). Physical IMU coupling = custom layer on top (Path A for v1, Path B later). The gateway controls the state-push, so we own the mapping. ### Video on state change (optional, theoretical) Beyond sprite pets, the LCD can play **short video clips** on state transitions: - Gateway pushes `play_video: <clip-id>` instead of (or alongside) `pet_state`. - Feasible formats on ESP32-S3: MJPEG (TJpgDec per-frame), animated GIF, or raw RGB frames. Avoid MP4/H.264 (no hardware decoder on S3). - Resolution cap: ∼QVGA (320×240) or the Stick-S3 native panel. Keep clips 1–3s. - **Best mix:** sprite pet as persistent idle mode (cheap, smooth); video burst only on event (`error`→glitch clip, `done`→celebrate clip). - Storage: clips on SD/SPIFFS or streamed from gateway over WiFi. ## Transport / Connectivity - ESP connects to Hermes gateway over WiFi (HTTP or WebSocket). - Gateway must be reachable: Cloudflare tunnel or VPN (same as S24 setup). - Auth: API key / basic auth in front of endpoint. - Recommended: WebSocket for bidirectional (audio up + state/TTS down) to avoid polling. ## IO-Tool Layer (Channel Registration) On connect, the ESP **registers its IO tools** with the gateway so Hermes sees them like any other tool. Define a stable schema: ```json { "tool": "esp_gpio_set", "device": "<esp-id>", "params": { "pin": 12, "state": "HIGH" } } { "tool": "esp_gpio_read", "params": { "pin": 14 } } { "tool": "esp_adc_read", "params": { "pin": 36, "atten": 11 } } { "tool": "esp_pwm_set", "params": { "pin": 13, "duty": 2048, "freq": 5000 } } { "tool": "esp_i2c_read", "params": { "addr": 64, "reg": 0, "len": 2 } } { "tool": "esp_i2c_write", "params": { "addr": 64, "reg": 0, "data": [1,2] } } { "tool": "esp_uart_send", "params": { "data": "AT+CMD\r\n" } } { "tool": "esp_imu_read", "params": { "axis": "all" } } ``` - Hermes routes these as normal tool-calls; the gateway serializes → WebSocket → ESP → Arduino handler. - ESP replies with JSON result (value / ack / error). - **Dynamic discovery:** ESP sends a `capabilities` message on connect so the gateway knows which pins/peripherals exist (avoids hardcoding per-device). ## Safety (CRITICAL — full HW access = physical consequences) Because Hermes can move motors, flip relays, fire PWM, the channel needs guardrails: 1. **Pin Allowlist** — `config.yaml` under `esp_hermes.allowed`: ```yaml esp_hermes: devices: stick-s3: allowed_pins: [12, 13, 14, 36] # only these are callable allowed_i2c: [0x40, 0x68] # sensor addresses only blocked_pins: [0, 1, 2, 3] # boot/flash/UART0 never exposed ``` 2. **Destructive-action approval** — mirror `approvals.mode`. Critical IO (relay, motor PWM, any `gpio_set` on allowlisted power pin) prompts the user before execution unless `esp_hermes.auto_approve_safe: true`. 3. **Rate-limit** — cap `esp_pwm_set` / `esp_gpio_set` calls per second to prevent strobe / burn-out loops. 4. **Power pins protected** — never expose EN, MTDI, GPIO0/1/2/3 (boot/flash). Hard-block in firmware regardless of allowlist. 5. **IMU event debounce** — on-device low-pass + threshold filter; only emit `tap`/`shake` after N stable samples (no gateway spam). 6. **Audit log** — every IO tool-call logged to `~/.hermes/logs/esp_hermes.log` with timestamp + device + pin + value. ## Physical Interaction Beyond Wake (Embodied Hermes) The device is not just an input surface — **movement in 3D space is meaningful**. Hermes gets a "body" via the IMU + motor control. Start small, expand later. ### Pet Animation ↔ Motion Coupling The pet on the LCD must **react to physical movement**, not just agent state: | Physical action | Pet reaction | Optional task trigger | |---|---|---| | Lift / pick up | pet "wakes up", stretches | none (ambient) | | Shake | pet gets dizzy / spins | toggle mode | | Tilt left/right | pet leans, looks curious | none | | Set down gently | pet settles to `idle` | none | | Fast spin | pet excited 🌀 | easter egg | | Flip upside down | pet confused 🙃 | none | → IMU orientation vector drives pet **pose/animation**, not just events. Smooth interpolation (not snapping) so the pet "feels" alive. ### Movement-Triggered Tasks Beyond wake: specific gestures = specific Hermes actions (user-definable mapping): - **Double-tap + tilt** → start a named cron/ritual - **Figure-8 motion** → "summarize my day" task - **Knock on table (IMU shock)** → quick status ping These are event-driven tool-calls, same mechanism as mode-toggle, but **mapped to user tasks** via config. ### Easter Eggs Motion-based hidden behaviors (fun + delight): - **Secret shake pattern** → pet does a dance, plays a sound - **Upside-down hold 3s** → pet "sleeps", LCD dims - **Rapid 3x tap** → surprise animation Keep them on-device (cheap, no gateway) so they feel instant. ### Motor Control (Hermes gets a body) Later phase: attach a motor/servo/RGB — Hermes can **move** the device or its surroundings: - `esp_motor_set` → rotate / nudge / point - Physical "nod" on task complete, "shake" on error (mirrors pet states in 3D) - Turns the channel from a passive speaker into an **embodied agent** ### Phased Rollout (start small) 1. **Phase 1 (first boot):** PTT + always-on voice + pet on LCD (idle/run/done). 2. **Phase 2:** IMU wake + tap/shake mode-toggle + pet motion-coupling (lean/dizzy). 3. **Phase 3:** IO-tool layer (GPIO/I2C/PWM) + safety allowlist. 4. **Phase 4:** movement-triggered tasks + easter eggs. 5. **Phase 5:** motor control — Hermes has a body. Never block Phase 1 on later phases. Ship the voice-pet first, grow the body incrementally. ## Open Questions (resolve at hardware arrival) - [ ] Audio codec (Opus vs PCM) — bandwidth vs ESP decode cost - [ ] State-push protocol (WS msg schema) — define with gateway team - [ ] Pet frame format for LCD (sixel? custom sprite? downscaled 192×208) - [ ] Power: always-on VAD battery impact - [ ] Wake-word for always-on mode (optional, on-device) ## Build Checklist (when hardware arrives) - [ ] Flash esp-hermes firmware (C/Arduino, WiFi + I2S + LCD) - [ ] Point ESP at gateway WebSocket URL + auth - [ ] Verify PTT: button→mic→STT→TTS→speaker - [ ] Verify always-on: VAD trigger - [ ] Wire pet-state push → LCD render - [ ] Select pet slug via `hermes pets` - [ ] Tunnel/gateway auth hardened ## Development Workflow (proven this session) How the project was actually scaffolded — reuse for future builds: 1. **Kanban board** `esp-hermes` (Hermes `kanban`) — 7 cards map to spec sections (gateway-adapter / ws-hub / io-tools / config-safety / commands / firmware-draft / repo-scaffold). Each card tagged with `esp-hermes-channel` skill so JIT workers load context. 2. **JIT agents on Modal** build the gateway-side code (Python) in parallel — firmware is **draft-only** until hardware arrives (no flash/test possible without the device). 3. **Repo layout:** `ohrbit/hermes_plugins` → subfolder `esp-hermes/` (NOT hermes_skills). Structure: `gateway/`, `tools/`, `firmware/`, `config/`, `references/`, hand-authored `README.md` (use `github-readme-authoring` skill — no generators), `LICENSE` (MIT), `implementation-spec.md`. 4. **GitHub push without `gh`:** `gh` CLI is NOT installed in this env. Use `GITHUB_TOKEN` from `~/.hermes/.env` + curl API + `git remote set-url origin https://$GITHUB_TOKEN@github.com/<repo>.git`. Verify push via `GET /repos/<repo>/contents/<path>` (expect 200). 5. **Tunnel-Derby lesson applies:** when dispatching JIT workers, pass `skills=[esp-hermes-channel]` and confirm Modal RAM before fan-out. ### Kanban / JIT dispatch — exact commands that worked (learned the hard way) - **Board + cards:** `hermes kanban --board <name> create "Title" --body "..." --skill esp-hermes-channel` (the `--board` flag goes BEFORE the subcommand; `--title`/`--board` AFTER it error out).
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub