Initial sync: memory, agents, commands, and gitignore
Syncs project memory, custom agents, and commands across machines. Excludes secrets (settings.json), session state, and runtime files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
- [MQTT HA Integration Plan](project_mqtt_ha_plan.md) — Plan to add MQTT discovery integration with Home Assistant; broker is Mosquitto on HA
|
||||
- [Teach Mode + Photo-Tune Plan](project_calibration_plan.md) — Teach mode wizard UI + Claude Code photo-assisted calibration skill
|
||||
- [Feature Branches Status](project_branches.md) — All feature branches on fork with implementation status and PR info
|
||||
- [Flask Dev Port](feedback_port.md) — Run Flask dev server on port 8080, not default 80
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: Flask dev server port
|
||||
description: User runs the Flask dev server on port 8080, not the default port 80
|
||||
type: feedback
|
||||
---
|
||||
|
||||
Run the Flask dev server on port 8080 for local testing.
|
||||
|
||||
**Why:** User preference — they've been using 8080 consistently.
|
||||
|
||||
**How to apply:** When starting the Flask app for testing, always use port 8080 instead of the default.
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: Feature branches and PRs status
|
||||
description: All feature branches on csader/SplitFlapDisplay fork with implementation status and PR info
|
||||
type: project
|
||||
---
|
||||
|
||||
Fork: `github.com/csader/SplitFlapDisplay` (upstream: `adamgmakes/SplitFlapDisplay`)
|
||||
Clone: `/Users/csader/Downloads/SplitFlapDisplay`
|
||||
|
||||
**Why:** Contributing features back to the original split-flap display project.
|
||||
|
||||
**Branches and status:**
|
||||
|
||||
| Branch | Status | PR |
|
||||
|--------|--------|----|
|
||||
| `feature/5-module-bus-bar` | Merged with wrong files | #6 merged, #7 fix open |
|
||||
| `fix/5-module-bus-bar-files` | Correct FAB2 files | #7 open |
|
||||
| `feature/mqtt-home-assistant` | Implemented, pushed | Not yet PR'd |
|
||||
| `feature/teach-mode` | Implemented, pushed | Not yet PR'd |
|
||||
| `feature/photo-tune` | Implemented, pushed | Not yet PR'd |
|
||||
| `feature/expanded-sports` | Implemented, pushed | Not yet PR'd |
|
||||
| `feature/simulator` | Implemented, pushed | Not yet PR'd |
|
||||
| `feature/animated-preview` | Implemented, pushed | #8 open |
|
||||
|
||||
**How to apply:** Check branch status before working. User wants to test features before filing PRs for most branches.
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Teach Mode + Photo-Tune Calibration Plan
|
||||
description: Plan for teach mode calibration wizard in web UI and Claude Code photo-assisted tuning skill for the split-flap display
|
||||
type: project
|
||||
---
|
||||
|
||||
Plan to add two calibration features to the split-flap display.
|
||||
|
||||
**Why:** Calibrating 45 modules across 64 characters is tedious. Teach mode simplifies the web UI flow, and photo-tune lets Claude Code do the visual inspection automatically.
|
||||
|
||||
**How to apply:** When implementing, the full plan is at `.claude/plans/cached-beaming-twilight.md`. Three files involved:
|
||||
- `SplitFlap-RPI-FRONTEND/frontend_code_apr24/templates/index.html` — teach mode modal (HTML/CSS/JS, ~250 lines)
|
||||
- `SplitFlap-RPI-FRONTEND/frontend_code_apr24/app.py` — `GET /tuning_status` convenience endpoint (~25 lines)
|
||||
- `.claude/commands/photo-tune.md` — new Claude Code slash command for photo-assisted tuning
|
||||
|
||||
**Key decisions:**
|
||||
- Teach mode is a separate modal from existing auto-tune (don't modify auto-tune)
|
||||
- Reuses existing `/auto_tune` API endpoints (home, goto_char, adjust, get_positions)
|
||||
- Photo-tune skill accepts Pi hostname as parameter, documents the iterative photo→analyze→nudge workflow
|
||||
- No new Python dependencies, no firmware changes
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: MQTT Home Assistant Integration Plan
|
||||
description: Detailed plan for adding MQTT discovery-based Home Assistant integration to the split-flap display Flask app
|
||||
type: project
|
||||
---
|
||||
|
||||
Plan to add MQTT integration to the split-flap display so Home Assistant can control it natively.
|
||||
|
||||
**Why:** The display is currently only controllable via the Flask web UI. MQTT lets HA send text, switch apps/animations, and see current state via auto-discovered entities.
|
||||
|
||||
**How to apply:** When implementing, all changes go in `SplitFlap-RPI-FRONTEND/frontend_code_apr24/app.py`. The full plan is saved at `.claude/plans/cached-beaming-twilight.md`.
|
||||
|
||||
**Summary of approach:**
|
||||
- Add `paho-mqtt` dependency
|
||||
- MQTT settings added to `load_settings()` defaults: broker (homeassistant.local), port (1883), user, password, enabled flag
|
||||
- 3 HA entities via MQTT Discovery: `text` (send display text), `select` (switch app/animation mode), `sensor` (current display string)
|
||||
- All entities grouped under one device, shared LWT availability on `splitflap/availability`
|
||||
- Command handlers reuse existing patterns: `send_to_display()`, `active_app`, `stop_event.set()`, `loop_delay` logic
|
||||
- State published with `retain=True` from `send_to_display()` and route handlers so HA stays in sync
|
||||
- Graceful fallback if MQTT unavailable (same pattern as serial fallback)
|
||||
- Firmware and serial protocol unchanged
|
||||
- Broker: Mosquitto add-on on Home Assistant
|
||||
@@ -0,0 +1 @@
|
||||
- [Kiro agents adopted](user_kiro_agents.md) — homelab + obsidian agents with MCP servers mirrored to ~/.mcp.json
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
name: Kiro agents adopted
|
||||
description: User has two Kiro CLI agents (homelab, obsidian) whose MCP servers and personas are now available in Claude Code
|
||||
type: user
|
||||
---
|
||||
|
||||
User runs Kiro CLI with two custom agents:
|
||||
|
||||
1. **homelab** — "You are an expert IT, Security, and DevOps person, who specializes in helping less knowledgeable home owners setup and run their homelabs." Uses Context7 and Obsidian (local filesystem at ~/Documents/Sader) MCP servers.
|
||||
|
||||
2. **obsidian** — "You are an expert Obsidian user who knows how to best organize a second brain tool." Uses Obsidian remote MCP (localhost:3001).
|
||||
|
||||
MCP servers from both agents are configured in ~/.mcp.json for Claude Code. When the user asks about homelab/IT/DevOps topics or Obsidian/note-taking, adopt the relevant agent persona.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Home Assistant ePaper Remote - Project Memory
|
||||
|
||||
## Future Entity Types to Add
|
||||
|
||||
High value additions:
|
||||
- **Climate/Thermostat** - Temperature setpoint slider, very common use case
|
||||
- **Scene** - One-tap button to activate (no state feedback needed)
|
||||
- **Script** - Run automation scripts (same as scene)
|
||||
- **Lock** - Lock/unlock doors (button with state)
|
||||
- **Media player** - Volume slider, play/pause button
|
||||
|
||||
Lower priority:
|
||||
- **Input number** - Generic slider for HA helpers
|
||||
- **Input boolean** - Generic toggle (functionally same as switch)
|
||||
- **Vacuum** - Start/stop/dock commands
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
- Firmware slider bar is always 100px (BUTTON_SIZE constant) - not configurable
|
||||
- SLIDER_HEIGHT = 170 in configurator (100px bar + 70px label space)
|
||||
- Label drawn at widget top, bar drawn at widget bottom
|
||||
- Configurator uses File System Access API for direct project writes
|
||||
- Icons generated from MDI SVGs, converted to 1-bit BMP in JavaScript
|
||||
@@ -0,0 +1,3 @@
|
||||
- [User Profile](user_profile.md) — Chris, homelab enthusiast, Lululemon Mirror mod, delegates all code to Claude
|
||||
- [Project Architecture](project_architecture.md) — Flutter app for mirror display + phone remote on Pi 4, voice/motion
|
||||
- [Workout API](reference_workout_api.md) — workout-player endpoints at 192.168.86.172:8091, video/progress/stream contracts
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: project-architecture
|
||||
description: "Mirror OS - Flutter app for hacked Lululemon Mirror on Pi 4 with phone remote, voice, and motion"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: 826ce615-b163-439f-aaa9-7b3be198b03a
|
||||
---
|
||||
|
||||
Mirror OS is a custom app platform for a hacked Lululemon Mirror running on Raspberry Pi 4.
|
||||
|
||||
**Key decisions:**
|
||||
- Flutter (not web kiosk, not Qt) — single codebase for mirror display + phone remote
|
||||
- Pi 4 (4GB) as compute
|
||||
- Vizio board used as HDMI passthrough only (no rotation capability)
|
||||
- Pi handles rotation via wlr-randr or DRM/KMS config
|
||||
- Display is portrait 1080x1920, not touch-enabled
|
||||
|
||||
**Why:** Flutter gives one codebase for both the mirror display and the phone companion app. Phone remote is half the project — keeping it unified avoids drift. Performance is adequate for dashboard/media on Pi 4.
|
||||
|
||||
**Features planned:**
|
||||
- Dashboard (clock, weather, calendar, widgets)
|
||||
- Workout player (integrates with existing workout-player homelab service)
|
||||
- Media player (YouTube, Plex, local video/music via mpv/media_kit)
|
||||
- Voice control (OpenWakeWord + Whisper, local processing)
|
||||
- Motion-activated wake (PIR or mmWave on GPIO)
|
||||
- Phone companion app as primary control interface
|
||||
|
||||
**How to apply:** All code goes in /Users/csader/mirror-os. Flutter project with shared packages for logic, separate entry points for mirror display vs phone remote.
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: reference-workout-api
|
||||
description: "Workout-player API contract at 192.168.86.172:8091 — endpoints for videos, stats, routines, streaming"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: reference
|
||||
originSessionId: 826ce615-b163-439f-aaa9-7b3be198b03a
|
||||
---
|
||||
|
||||
Workout-player service runs at http://192.168.86.172:8091 on the homelab.
|
||||
|
||||
**Endpoints (derived from prior mirror-os JS codebase):**
|
||||
- `GET /api/videos?folder=<path>` — list videos, optional folder filter. Returns `{videos: [...], folders: [...]}`
|
||||
- `GET /api/stats` — aggregate stats (total, completed, inProgress counts)
|
||||
- `GET /api/routines` — list routines. Returns `{routines: [...]}`
|
||||
- `PATCH /api/videos` — save progress. Body: `{videoId, position, percent}`
|
||||
- `GET /api/stream?path=<encoded_path>` — stream video file directly
|
||||
|
||||
**Video object fields:** id, title, path, folder, duration, trimStart, trimEnd, lastPosition, percentCompleted, restSeconds
|
||||
|
||||
**State machine for workout sessions:** browse → playing → rest (between queue items) → complete
|
||||
|
||||
**How to apply:** When building the workout integration in Flutter, use these endpoints. The stream URL can be passed directly to media_kit/mpv for playback.
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: user-profile
|
||||
description: "Chris - homelab enthusiast with Lululemon Mirror mod project, prefers Claude writes all code"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: user
|
||||
originSessionId: 826ce615-b163-439f-aaa9-7b3be198b03a
|
||||
---
|
||||
|
||||
Chris runs a homelab (192.168.86.x network). Has a self-hosted workout-player app at 192.168.86.172:8091 with video library, routines, and progress tracking.
|
||||
|
||||
Hardware: Lululemon Mirror with BOE DV430FHM-NN5 panel (43" 1080p IPS, portrait 1080x1920), Vizio replacement mainboard (HDMI passthrough to LVDS), Raspberry Pi 4.
|
||||
|
||||
Prefers Claude writes all the code. Comfortable reviewing and making architectural decisions but delegates implementation entirely.
|
||||
|
||||
Phone: Android (primary target for remote app testing/deployment).
|
||||
|
||||
Gitea instance at git.chrissader.com (org: hermes).
|
||||
@@ -0,0 +1 @@
|
||||
- [PlateRunner deployment](reference_deployment.md) — Deploy via SSH to prox2docker, git pull, docker compose rebuild on VM 103
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: PlateRunner deployment
|
||||
description: PlateRunner deploy process — SSH to prox2docker, git pull, docker compose rebuild on VM 103
|
||||
type: reference
|
||||
---
|
||||
|
||||
PlateRunner is running on the homelab at platerunner.chrissader.com.
|
||||
|
||||
**Host:** VM 103 (192.168.86.122) on Proxmox2
|
||||
**SSH alias:** `prox2docker` (csader@192.168.86.122)
|
||||
**Stack path:** `/opt/docker/stacks/platerunner`
|
||||
**Container:** `platerunner-platecycler-1` on port 3001 → 3000
|
||||
|
||||
**Deploy process:**
|
||||
```bash
|
||||
ssh prox2docker "cd /opt/docker/stacks/platerunner && git pull && docker compose up -d --build"
|
||||
```
|
||||
|
||||
**Note:** git push from this machine may hang on credential prompt — user may need to push manually.
|
||||
@@ -0,0 +1,5 @@
|
||||
- [User profile](user_profile.md) — CNC domain expert, strong spatial reasoning, builds ShaperSlicer
|
||||
- [Be direct](feedback_be_direct.md) — Grasp geometry concepts immediately, don't over-clarify
|
||||
- [Design before code](feedback_design_first.md) — First-principles algorithm design before reading existing code
|
||||
- [Silhouette cookie cutter](project_silhouette_cookie_cutter.md) — Cumulative silhouette splits layers into boundary vs interior
|
||||
- [Shaper Origin concepts](project_shaper_origin_concepts.md) — SVG fill colors, cut types, BenchPilot behavior, tab semantics
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: Be direct about geometry concepts
|
||||
description: User gets frustrated when spatial/geometry concepts need repeated explanation
|
||||
type: feedback
|
||||
---
|
||||
|
||||
User has strong spatial reasoning and expects the same. When they describe a geometry operation (e.g., "cookie cutter" = use the silhouette to split shapes), grasp it immediately and act on it. Don't ask clarifying questions about concepts they've already explained clearly.
|
||||
|
||||
**Why:** User expressed frustration: "I'm struggling with patience here because this seems like a straightforward problem to solve to me."
|
||||
|
||||
**How to apply:** When user describes a geometry operation in plain language, translate it directly to boolean ops and implement. Don't over-complicate or second-guess their spatial intuition.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: Design before code
|
||||
description: User prefers first-principles algorithm design before reading existing code
|
||||
type: feedback
|
||||
---
|
||||
|
||||
When tackling complex geometry/algorithm problems, design the ideal approach from first principles BEFORE reading the existing code. Then compare the ideal to what's implemented to find bugs.
|
||||
|
||||
**Why:** User explicitly asked for this workflow — "I'd rather have you think of how you'd recommend doing it FIRST, then compare to the existing code." Jumping straight to code reading led to patches that missed the root cause.
|
||||
|
||||
**How to apply:** For non-trivial algorithm bugs, start with a clean-room design of what the correct approach should be, then diff against the implementation.
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Shaper Origin cut type semantics
|
||||
description: How Shaper Origin interprets SVG fill colors and cut types — critical for correct SVG output
|
||||
type: project
|
||||
---
|
||||
|
||||
Shaper Origin SVG semantics:
|
||||
- White fill (#FFFFFF) = inside cut (vector follow along the path — faster, used for boundary/cutout)
|
||||
- Gray fill (#808080) = pocket cut (area removal — raster/spiral clearing, used for interior cavities)
|
||||
- Black fill (#000000) = outside cut
|
||||
- `shaper:cutDepth` attribute sets depth per path
|
||||
- BenchPilot mode may cut layers in ANY order (not necessarily top-down), so each layer must only contain material not already removed by other layers
|
||||
- Tabs are bridges in the boundary trough that hold the piece in stock — they should NEVER affect interior/model geometry
|
||||
|
||||
**Why:** These semantics drive the entire SVG generation logic. Getting fill colors wrong means the machine uses the wrong cut strategy.
|
||||
|
||||
**How to apply:** Always verify boundary paths get white fill and interior paths get gray fill. Tabs only subtract from boundary.
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Silhouette cookie cutter approach
|
||||
description: The cumulative model silhouette is used to split every layer into boundary vs interior
|
||||
type: project
|
||||
---
|
||||
|
||||
The correct way to separate boundary (cutout ring) from interior (model cavities) in each layer:
|
||||
|
||||
1. `cumulativeCross` = union of all cross-sections across all depths = the model's full silhouette from the cutting direction
|
||||
2. For each layer's pocket geometry:
|
||||
- Boundary = pocket MINUS silhouette (material outside the model outline)
|
||||
- Interior = pocket INTERSECT silhouette (cavities within the model outline)
|
||||
3. This silhouette is constant across all layers — it's the "cookie cutter"
|
||||
|
||||
**Why:** Previously used per-layer model outline which changed shape at every depth and failed for solid shapes without holes. The silhouette approach works universally.
|
||||
|
||||
**How to apply:** If boundary/interior separation needs changes, the silhouette (cumulativeCross) is the dividing line. Filter boolean sliver artifacts with area < 0.01mm².
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: User profile
|
||||
description: CNC/woodworking domain expert building ShaperSlicer, strong spatial reasoning about geometry operations
|
||||
type: user
|
||||
---
|
||||
|
||||
User is the developer of ShaperSlicer. Has deep domain knowledge of CNC routing, specifically the Shaper Origin (handheld and BenchPilot/gantry modes). Understands how the machine interprets SVG cut types (pocket, inside, outside), depth ordering, and Autopass behavior. Thinks in terms of physical machining operations — "cookie cutter", "trough", "air cutting". Can identify geometry bugs visually from 2D layer previews.
|
||||
@@ -0,0 +1,15 @@
|
||||
- [SSH directly to VMs](feedback_ssh_directly.md) — Use csader@VM_IP, not qm guest exec through Proxmox hosts
|
||||
- [HA API access patterns](reference_ha_api_access.md) — REST/WebSocket APIs for automations, entity registry, history
|
||||
- [Verify before bulk delete](feedback_verify_before_bulk_delete.md) — Confirm entities are actual duplicates before mass removal
|
||||
- [Pixel 10 Pro Fold for notifications](user_notification_phone.md) — Use notify.mobile_app_pixel_10_pro_fold, not iPhone or notify.chris
|
||||
- [House orientation & shade positions](user_house_orientation.md) — West door (225-315°), east windows (45-135°), per-shade close values
|
||||
- [HA automation patterns](reference_ha_automation_patterns.md) — API patterns, scene save/restore, categories, weather/azimuth
|
||||
- [NR migration status](project_nr_migration.md) — Which flows are in NR vs HA after 2026-03-28 migration
|
||||
- [Backup before HA updates](feedback_backup_before_updates.md) — Always use backup:true when running update.install on add-ons
|
||||
- [MantelMount control via Bond RF](reference_mantelmount.md) — Bond RF entities, contact sensor mapping, run-then-direction sequence
|
||||
- [Zulip on VM 103](reference_zulip.md) — crew.chrissader.com, tus upload fix, post-start.sh after recreate
|
||||
- [Caddyfile edits must preserve inode](feedback_caddyfile_inode.md) — Use sed/tee, not Python write(); restart container if inode broken
|
||||
- [Check for stale/duplicate entities](feedback_stale_entity_check.md) — Re-paired devices create new entities; old named ones go stale and silently fail
|
||||
- [HA Blue SSH access](reference_ha_blue_ssh.md) — Port 2222, user csader (not root), id_ed25519 key
|
||||
- [HACS and Mushroom on HA Blue](reference_hacs_mushroom.md) — HACS, Mushroom, weatheralerts install details
|
||||
- [Never use "new" as automation ID](feedback_automation_ids.md) — Use unique numeric IDs when creating automations via REST API
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: Never use "new" as automation ID
|
||||
description: Creating HA automations via API with id "new" overwrites existing automations that also have id "new"
|
||||
type: feedback
|
||||
---
|
||||
|
||||
When creating automations via `POST /api/config/automation/config/new`, HA assigns the literal ID "new". If you create a second automation the same way, it overwrites the first.
|
||||
|
||||
**Why:** The bird waterer automation got overwritten by the hail automation because both had id "new".
|
||||
|
||||
**How to apply:** Always use a unique numeric ID (e.g., timestamp-based like `1712800000001`) when creating automations via the REST API. After creating with `/new`, immediately re-save with a proper ID and delete the "new" entry.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: Always backup before HA add-on updates
|
||||
description: Use backup:true parameter when running update.install on HA add-ons
|
||||
type: feedback
|
||||
---
|
||||
|
||||
Always pass `backup: true` when calling `update.install` on HA add-ons. This creates a snapshot before each update.
|
||||
|
||||
**Why:** User explicitly requested this as standard practice — safety net in case an update breaks something.
|
||||
|
||||
**How to apply:** Any time running firmware/add-on updates via the HA API, include `"backup": true` in the service call data.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: Caddyfile edits must preserve inode
|
||||
description: Python open().write() breaks Docker bind mounts by creating new inodes — use sed -i or tee instead
|
||||
type: feedback
|
||||
---
|
||||
|
||||
Never edit the Caddyfile (or any Docker bind-mounted file) with Python's `open(path, 'w').write()` — it creates a new inode and Docker keeps reading the old one.
|
||||
|
||||
**Why:** Docker bind mounts track the original file inode. Python's write creates a new file, so `caddy reload` reads stale content. This caused hours of debugging where Caddy appeared to ignore config changes.
|
||||
|
||||
**How to apply:** Use `sed -i` for substitutions or `cat newfile | tee /path/to/file > /dev/null` for full rewrites. If the inode is already broken, restart the container (`docker restart caddy`) to re-mount. Always verify with `docker exec caddy cat /etc/caddy/Caddyfile` after edits.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: SSH directly to VMs
|
||||
description: User prefers direct SSH to VMs (csader@IP) instead of going through Proxmox qm guest exec
|
||||
type: feedback
|
||||
---
|
||||
|
||||
SSH directly to VMs using `csader@<VM_IP>` instead of routing through Proxmox hosts with `qm guest exec`. Root SSH is blocked on VMs — use csader user with sudo when needed.
|
||||
|
||||
**Why:** User explicitly corrected this approach twice. Going through Proxmox is slower and unnecessary when direct SSH works.
|
||||
|
||||
**How to apply:** For any VM operations (.134, .122, .146, .172), SSH as csader directly. Only use Proxmox host SSH (root@.66/.67/.68) for host-level operations like `qm list`, `pct list`, `pct exec` for LXCs.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: Check for stale/duplicate entities when automations partially fail
|
||||
description: HA automations that notify but don't actuate devices — look for duplicate entities from re-paired devices
|
||||
type: feedback
|
||||
---
|
||||
|
||||
When an HA automation fires (notifications work) but device actions silently fail, check for duplicate entities. Devices that get re-paired create new entities with raw addresses (e.g., `switch.0xa4c138...`) while the old named entity goes stale.
|
||||
|
||||
**Why:** Chicken sprinkler automation sent notifications fine but `switch.turn_on` went to a dead entity. The working device had a new entity with a Zigbee address. Silent failure — no error in HA.
|
||||
|
||||
**How to apply:** When debugging partial automation failures, list all entities matching the device name and check `last_changed` dates. If the named entity hasn't changed in days but a raw-address entity is active, the device was re-paired. Fix by removing the stale entity and renaming the live one.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: Verify duplicates before bulk entity cleanup
|
||||
description: User wants confirmation that entities are actual duplicates before mass deletion
|
||||
type: feedback
|
||||
---
|
||||
|
||||
When cleaning up stale/duplicate HA entities, verify each `_N` suffixed entity actually has a newer counterpart before removing it. Don't assume all `_2` entities are stale — some may be the current active version if there's no `_3`.
|
||||
|
||||
**Why:** User stopped a bulk delete of 44 `_2` entities — only 5 of them were confirmed duplicates with `_3` counterparts. The other 39 were the active versions.
|
||||
|
||||
**How to apply:** Before any bulk entity cleanup, cross-reference suffixed entities to confirm duplicates exist. Only remove entities with a confirmed newer counterpart.
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Node-RED flows still active
|
||||
description: Which NR flows remain active vs migrated to HA after 2026-03-28 migration
|
||||
type: project
|
||||
---
|
||||
|
||||
Node-RED migration completed 2026-03-28. Most flows migrated to HA automations.
|
||||
|
||||
**Still in Node-RED (do not duplicate in HA):**
|
||||
- Follow Me Alexa — Alexa device-specific voice command routing
|
||||
- Presence — Room-level BLE/motion/bed presence tracking feeding input_select helpers
|
||||
- Home Security System — Alarm mode handling (migration planned but needs discussion on triggers)
|
||||
- Flow 1 — Alexa actionable notification support for theater mode
|
||||
|
||||
**Migrated to HA (disable in NR):**
|
||||
- Goodnight, Lights, Climate, Blinds, Theater Mode, Wake Up
|
||||
- Lights sub-flows (2026-03-28): Main Switch→Haiku Light, 3-way→Haiku Light, Auto Garage Lights (ratgdo doors), Outdoor+Garage Light Sync, Christmas Spheres Timer
|
||||
|
||||
**Deleted from NR:**
|
||||
- Chicken Sprinkler, LLM Vision, Automatic Lights
|
||||
|
||||
**Why:** Consolidating automations into HA for easier management. NR Presence flow is foundational and complex — stays in NR for now.
|
||||
|
||||
**How to apply:** When working on automations, check whether the flow is in NR or HA to avoid conflicts. Presence-related input_selects are set by NR — HA automations can read them but shouldn't write to them.
|
||||
|
||||
**Removed integrations (2026-03-28):**
|
||||
- Zigbee Lock Manager — replaced by Z2M direct, Lockly also removed (timeouts on battery lock)
|
||||
- Neato, Konnected, Telegram — no entities, ghost integrations
|
||||
- Front door lock codes managed on keypad, not via HA (Yale Assure SL sleeps too aggressively for remote code management)
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: Home Assistant API access patterns
|
||||
description: How to query HA automations, entity registry, history, and other data not available via MCP tools
|
||||
type: reference
|
||||
---
|
||||
|
||||
The HA MCP tools (`mcp__home-assistant__*`) cover device control, entity states, and live context — but NOT automations, entity registry, history, logbook, or traces.
|
||||
|
||||
For those, use the HA APIs directly:
|
||||
|
||||
- **REST API** (via curl): `http://192.168.86.36:8123/api/...` with Bearer token from `.mcp.json` (`home-assistant.headers.Authorization`)
|
||||
- `GET /api/states` — all entity states (filter by entity_id prefix for automations, etc.)
|
||||
- `GET /api/config/automation/config/<id>` — full automation config (triggers, conditions, actions) by numeric ID from entity attributes
|
||||
- `GET /api/history/period/<timestamp>?filter_entity_id=...` — historical state changes
|
||||
- `GET /api/logbook/<timestamp>?entity=...` — logbook entries
|
||||
|
||||
- **WebSocket API** (`ws://192.168.86.36:8123/api/websocket`): needed for entity registry operations
|
||||
- `config/entity_registry/remove` — delete stale/duplicate entities
|
||||
- `config/entity_registry/list` — full entity registry (very large response)
|
||||
- Requires `websockets` Python package (installed on Mac)
|
||||
- **IMPORTANT**: Must set `max_size=10*1024*1024` on `websockets.connect()` — the entity registry response exceeds the default 1MB limit
|
||||
- **Trace API** (`/api/trace/<entity_id>`): may return non-standard JSON or 404. Wrap in try/except and check raw response before parsing.
|
||||
|
||||
- **Auth token**: Available as `$HA_TOKEN` env var (set in settings.local.json). Use `Bearer $HA_TOKEN` in curl, or `os.environ['HA_TOKEN']` in Python.
|
||||
|
||||
**How to apply:** When user asks about automations, entity cleanup, or historical data, use these APIs rather than saying the MCP can't do it. Always use these patterns from the main conversation — subagents may not have Bash access.
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: HA automation management patterns
|
||||
description: How to create/update HA automations via REST/WS API, scene save/restore, categories, and established patterns
|
||||
type: reference
|
||||
---
|
||||
|
||||
Automation configs are updated via POST (not PUT):
|
||||
`POST http://192.168.86.36:8123/api/config/automation/config/<numeric_id>`
|
||||
|
||||
Key patterns established:
|
||||
- **Notifications**: `notify.mobile_app_pixel_10_pro_fold` with `"image"` for snapshots and `"clickAction"` for deep links
|
||||
- **TTS**: `tts.speak` targeting `tts.home_assistant_cloud` with `media_player_entity_id` (not deprecated `tts.google_translate_say`)
|
||||
- **Sun azimuth**: `sun.sun` attribute `azimuth` for directional triggers (west door = 225-315°, east windows = 45-135°). East shades have NO temp condition; front door shade still requires >80°F.
|
||||
- **Weather conditions**: `sensor.openweathermap_condition` states: sunny, clear-night, partlycloudy, cloudy, rainy, pouring, snowy, fog, lightning, lightning-rainy
|
||||
- **Scene save/restore**: `scene.create` with `snapshot_entities` to save state, `scene.turn_on` to restore. Used for Theater Mode and Climate thermostat save/restore.
|
||||
- **Enabling/disabling automations**: WebSocket API `config/entity_registry/update` with `disabled_by: null` to enable, `disabled_by: user` to disable
|
||||
- **Categories**: WebSocket `config/category_registry/create` (scope: automation) and `config/entity_registry/update` with `categories: {automation: cat_id}`
|
||||
|
||||
**Automation categories** (scope: automation):
|
||||
- Sprinklers, Shades & Blinds, Cameras & Security, Home Theater, Lights, 3D Printers, Garage, Fans, Climate, Routines, Severe Weather
|
||||
|
||||
**Gotchas:**
|
||||
- Don't trigger Theater Mode on TV power — TV turns on for non-movie use. Only trigger via `input_boolean.theater_mode` toggle.
|
||||
- Battery-powered Zigbee devices (locks) sleep aggressively — service calls that need a response (code queries) will timeout. Lock/unlock works because Z2M queues commands.
|
||||
- Always use `backup: true` when calling `update.install` on add-ons.
|
||||
- Wind gust entity is `sensor.openweathermap_wind_gust` (NOT `_wind_gust_speed`).
|
||||
- `weather.get_forecasts` requires `?return_response` when called via REST API. Response is at `d['service_response']['weather.openweathermap']['forecast']`.
|
||||
- Template references to NWS alerts must handle empty alerts list: use `| first | default({})` pattern, not `[0]`.
|
||||
|
||||
**How to apply:** Reference these patterns when creating or modifying HA automations.
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: HA Blue SSH access
|
||||
description: How to SSH into Home Assistant Blue — port 2222, user csader, not root
|
||||
type: reference
|
||||
---
|
||||
|
||||
SSH to HA Blue: `ssh -p 2222 csader@192.168.86.36`
|
||||
|
||||
- Port 2222 (SSH add-on)
|
||||
- User `csader` — root is blocked by AllowUsers
|
||||
- Key: `~/.ssh/id_ed25519` (ed25519, csader@chrissader.com)
|
||||
- Use `sudo` for privileged operations (e.g., HACS install)
|
||||
|
||||
**How to apply:** When needing to run commands on HA Blue directly (install HACS, check custom_components, etc.), use this SSH path.
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
name: HACS and Mushroom on HA Blue
|
||||
description: HACS v2026.1.0 and Mushroom v5.1.1 installed on HA Blue, plus weatheralerts integration
|
||||
type: reference
|
||||
---
|
||||
|
||||
**HACS** (v2026.1.0): Installed 2026-04-04 via SSH (`sudo wget -O - https://get.hacs.xyz | sudo bash -`). Configured via HA UI with GitHub OAuth.
|
||||
|
||||
**Mushroom** (v5.1.1): Installed via HACS WebSocket API (`hacs/repository/download`, repo id `444350375`). Used on Mobile Dashboard Home view for greeting card with dynamic weather/alert display.
|
||||
|
||||
**Weatheralerts** (v2026.1.0): Installed via HACS 2026-04-11. Configured for Williamson County (zone TXZ173, county TXC491). 90s poll interval, 20s timeout. Entity: `sensor.weatheralerts_williamson_txz173_txc491`.
|
||||
|
||||
**How to apply:** If HACS disappears after an HA update, re-run the install script via SSH and re-add the integration in the UI. Mushroom and weatheralerts should survive since the files persist in custom_components.
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: MantelMount control via Bond RF bridge
|
||||
description: How the MantelMount is controlled in HA — Bond RF entities, contact sensor mapping, command sequence
|
||||
type: reference
|
||||
---
|
||||
|
||||
MantelMount is controlled via a Bond RF bridge. No native HA integration — uses assumed_state entities.
|
||||
|
||||
**Entities:**
|
||||
- `light.mm_down_up` — "Run Button" — toggle starts/stops the motor
|
||||
- `fan.mm_run` — direction control. ON = down, OFF = up
|
||||
- `binary_sensor.tv_mount_angle_contact` — Zigbee door/tilt sensor. ON = mount down/extended, OFF = mount up/retracted
|
||||
|
||||
**Command sequence:** Toggle run button FIRST, then set direction 1s later. This is how the MM controller works — run first, then direction.
|
||||
|
||||
**Automation** (`automation.mantelmount_up_down`):
|
||||
- Triggers on Samsung TV on/off
|
||||
- TV-off condition: `switch.tv_power` (Zigbee power strip L4) must be on
|
||||
- Uses contact sensor as guard (skip if already in correct position) and for retry verification after 20s
|
||||
|
||||
**How to apply:** When modifying mantel mount automation, always preserve run-then-direction sequence and contact sensor verification.
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Zulip on VM 103
|
||||
description: Zulip chat server config, tus upload fix, Caddy/Authelia setup at crew.chrissader.com
|
||||
type: reference
|
||||
---
|
||||
|
||||
Zulip runs on VM 103 (192.168.86.122) port 8085, accessible at crew.chrissader.com.
|
||||
|
||||
**Compose**: `/opt/docker/stacks/zulip/` (project name `zulip-docker` in `.env` to preserve volumes)
|
||||
|
||||
**Caddy**: Uses `route` block with `@exempt path /api/* /json/* /user_uploads/*` matcher and `reverse_proxy @exempt` before `forward_auth`. The `route` directive is critical — without it, Caddy reorders directives and runs `forward_auth` first regardless of source order. The `handle` block approach also doesn't work. Authelia also has bypass rules for the same paths as belt-and-suspenders.
|
||||
|
||||
**Tus upload fix**: Zulip's puppet overwrites `/etc/nginx/zulip-include/app` on container start. The tus location block needs `proxy_redirect http://crew.chrissader.com https://crew.chrissader.com;` added (inlined proxy config, no `include proxy`). Without this, tusd generates `http://` Location headers and browsers block the PATCH as mixed content.
|
||||
|
||||
**How to apply:** After any `docker compose up` that recreates the zulip container, run `/opt/docker/stacks/zulip/post-start.sh` to re-apply the nginx fix.
|
||||
|
||||
**LOADBALANCER_IPS**: Includes `172.26.0.0/16` (Docker bridge) so nginx trusts `X-Forwarded-Proto` from Caddy.
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: House window orientations and shade close positions
|
||||
description: Window shade orientations, azimuth ranges, and fully-closed position values per shade
|
||||
type: user
|
||||
---
|
||||
|
||||
Chris's front door faces due west. The sun hits it in the afternoon/evening. Auto Front Door Shade automation uses azimuth 225°-315° range.
|
||||
|
||||
Living room window shades (1-5) face east. Sun-Tracking automation uses azimuth 45°-135° range. No temperature condition — fires on sun angle + clear weather only.
|
||||
|
||||
Fully closed shade positions (not all are 100%):
|
||||
- Shades 1 & 2: position 100
|
||||
- Shades 3 & 4: position 35
|
||||
- Shade 5: position 60
|
||||
|
||||
House is in Round Rock, TX (zip 78681).
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
name: Chris uses Pixel 10 Pro Fold for HA notifications
|
||||
description: Primary notification target is notify.mobile_app_pixel_10_pro_fold, not iPhone 15 or notify.chris
|
||||
type: user
|
||||
---
|
||||
|
||||
Chris's primary phone is a Pixel 10 Pro Fold. Use `notify.mobile_app_pixel_10_pro_fold` for HA push notifications — not `notify.chris` (broken/legacy) or `notify.mobile_app_iphone_15`.
|
||||
|
||||
For HA companion app deep links, use `clickAction` with dashboard paths like `/mobile-dashboard/sprinklers`. Snapshots attach via `"image": "/api/image_proxy/image.<entity>"`.
|
||||
Reference in New Issue
Block a user