# RuView ↔ HomePod Integration Guide **Ambient intelligence for Apple Home.** Run RuView as a native HomeKit accessory so your HomePod discovers it, Siri understands it, and Apple Home automations govern it — no Home Assistant required. --- ## Architecture Overview RuView turns WiFi radio reflections into spatial intelligence (presence, breathing, fall risk, activity patterns). When paired with a HomePod or Apple TV acting as your Home Hub, RuView becomes an invisible sensor that feeds Siri, automations, and scenes: ``` ESP32-C6 CSI node (living room) ↓ (UDP feature stream) RuView Sensing Server (announces presence, vital signs, BFLD events) ↓ (HTTP polling) HAP Bridge (advertises HomeKit accessory on mDNS) ↓ (Bonjour discovery) HomePod or Apple TV (Home Hub) ↓ (forwards to Home app + Siri) iPhone, iPad, Mac, Watch, Apple Home automations ``` The integration leverages HomeKit Accessory Protocol (HAP-1.1) — the same standard that Philips Hue, Eve, and Nanoleaf use. Your HomePod discovers the bridge within seconds of launch, pairing is one-tap from the Home app, and Siri queries work immediately: *"Hey Siri, is anyone in the living room?"* For design rationale and privacy safeguards, see [ADR-125 — RuView ↔ Apple Home native HAP bridge](docs/adr/ADR-125-ruview-apple-home-native-hap-bridge.md). --- ## What's Shipped Today (Tier 1 + Tier 2) Eight incremental iterations landed in PR #797 on the `feat/adr-125-apple-fabric` branch: | Iteration | Capability | Commit | Status | |-----------|-----------|--------|--------| | 1 | Multi-characteristic HomeKit accessory (Motion + Occupancy + StatelessProgrammableSwitch) | `48db60a65` | Runtime-live | | 2 | Sensing-server HTTP endpoints for bridge polling (`/api/v1/vitals`, `/api/v1/bfld`, `/api/v1/semantic-events`) | `194a2e163` | Runtime-live, curl-validated | | 3 | HAP bridge with N child accessories; Siri-by-room (name each room, Siri voices it) | `63b77f760` | Runtime-live, two bridges advertising | | 4 | Semantic-events endpoint per §2.1.d (`Unknown Presence`, `Unexpected Occupancy`, `Unrecognized Activity Pattern`) | `3d30261e7` | Runtime-live, privacy invariant I1 enforced | | 5 | rvagent MCP consumer (agentic chain); 12 MCP tools for Claude Code integration | `c19742d71` | Runtime-validated on real C6 | | 6 | PyO3 BFLD PrivacyClass binding (SOTA rust crate exposed to Python) | `de0712d43` | Source-built (`cargo check` green) | | 7 | Shortcuts-as-glue (launchd job + Speak Text on HomePod via iCloud Home graph, bypasses Bonjour blocker) | `d0525359d` | Runtime-validated, osascript trigger green | | 8 | Custom characteristic UUID scaffold for Eve.app rendering (design complete; runtime HAP-python JSON-loader follow-up) | `3bb8c1621` | Design scaffolded | **What you can do today:** - Pair a RuView bridge into your Home app on iPhone, iPad, or Mac. - Ask Siri room-specific presence questions ("is anyone home", "is the office occupied", "did someone fall"). - Trigger automations on presence detection, breathing presence, fall risk, or activity pattern anomalies. - Stream RuView events to HomePod announcements via the Shortcuts-as-glue path (Tier 2). - Query RuView data programmatically through the agentic MCP interface (Claude Code integration). --- ## Quickstart (5 minutes) ### Prerequisites - **Hardware**: ESP32-C6 running CSI firmware (rev v0.7.0+) on the same WiFi network as your Mac and HomePod. - **Software**: Python 3.8+ on a Mac that's already paired into your Home app (iCloud account). - **Network**: Mac, HomePod, and ESP32-C6 must all be on the same LAN subnet (e.g., `192.168.1.0/24`). ### Step 1: Provision the ESP32-C6 Connect the C6 via USB and run the provisioning script: ```bash python firmware/esp32-csi-node/provision.py \ --port /dev/ttyUSB0 \ --ssid "YourWiFiSSID" \ --password "YourWiFiPassword" \ --target-ip 192.168.1.20 ``` Verify the C6 boots on the network: ```bash ping 192.168.1.20 ``` ### Step 2: Create a Python venv on the Mac and install HAP-python ```bash mkdir -p ~/ruview-hap cd ~/ruview-hap python3 -m venv venv source venv/bin/activate pip install HAP-python ``` ### Step 3: Copy the RuView bridge scripts to the Mac From the repository (e.g., cloned on your Mac), copy these files: ```bash cp scripts/c6-presence-watcher.py ~/ruview-hap/ cp scripts/ruview-sensing-server.py ~/ruview-hap/ cp scripts/ruview-hap-bridge.py ~/ruview-hap/ ``` ### Step 4: Start the three daemons in order **Terminal 1: Start the C6 presence watcher** (reads UDP packets from the C6, applies BFLD privacy gate) ```bash cd ~/ruview-hap source venv/bin/activate python c6-presence-watcher.py --node-id 1 --esp32-ip 192.168.1.20 --privacy-class 2 ``` Output: Writes presence events to `/tmp/ruview-state.json`. **Terminal 2: Start the sensing server** (HTTP polling interface for the HAP bridge) ```bash cd ~/ruview-hap source venv/bin/activate python ruview-sensing-server.py --port 3000 ``` Output: Listening on `http://127.0.0.1:3000/api/v1/...`. **Terminal 3: Start the HAP bridge** (advertises HomeKit accessory on mDNS) ```bash cd ~/ruview-hap source venv/bin/activate python ruview-hap-bridge.py --port 51826 --pin 200-70-910 ``` Output: Look for setup code in the terminal output, e.g., `Setup code: 200-70-910`. ### Step 5: Pair the bridge from your iPhone 1. Open the **Home** app on your iPhone. 2. Tap the **+** icon (top right) → **Add Accessory**. 3. Scan the setup code (or tap **Don't Have a Code or Can't Scan?** → **More Options**). 4. Select the **RuView Sense** bridge from the list (should appear within 10 seconds). 5. Assign to a room (e.g., "Living Room"). 6. Tap **Done**. ### Step 6: Test with Siri Once paired, ask Siri: ``` "Hey Siri, is anyone in the living room?" ``` Siri will respond with the current occupancy state. Walk past the C6 and ask again — the presence value should update within 1–2 seconds. --- ## Per-Room Expansion To monitor multiple rooms, run multiple C6 nodes, each with its own `c6-presence-watcher.py` instance: ```bash # Terminal: Room 1 (Living Room, node_id=1) python c6-presence-watcher.py --node-id 1 --esp32-ip 192.168.1.20 \ --output /tmp/ruview-state.living-room.json # Terminal: Room 2 (Bedroom, node_id=2) python c6-presence-watcher.py --node-id 2 --esp32-ip 192.168.1.21 \ --output /tmp/ruview-state.bedroom.json # Terminal: HAP bridge (auto-discovers both state files) python ruview-hap-bridge.py --port 51826 --rooms "Living Room,Bedroom" ``` The HAP bridge auto-discovers `*.json` files in `/tmp/ruview-state*` and creates a child HomeKit accessory per room. Each room appears separately in the Home app and can be assigned to its physical location. --- ## Privacy Semantics RuView's BFLD (Beamforming Feedback Layer for Detection) uses a **privacy class** gate that enforces what data can cross the HomeKit boundary. Only Classes 2 and 3 (Anonymous and Restricted) are eligible; Class 0/1 (Raw identity information) is never exposed. ### The Three Semantic Events HomeKit exposes **thresholded events**, not raw probabilities: | Event | HomeKit Characteristic | Meaning | Example Automation | |-------|----------------------|---------|-------------------| | **Unknown Presence** | MotionSensor (stateful) | Person detected + no matching identity record for >30s | "Turn on porch light when Unknown Presence detected after 9pm" | | **Unexpected Occupancy** | OccupancySensor | Occupancy outside the operator's defined schedule | "Send notification if office is occupied on weekends" | | **Unrecognized Activity Pattern** | ProgrammableSwitch (momentary) | Activity drift or recalibration gate fires | "Run a re-learning sequence when activity changes" | ### What's Deliberately Hidden The following are **never** exposed to HomeKit: - `identity_risk_score` (numeric 0–1 confidence) — only thresholded semantic events cross the boundary - Soul-Signature match probability — internal to BFLD - `rf_signature_hash` — cryptographic internal state This enforces **ADR-125 §2.1.d invariant I1**: raw identity information never exits the node. The semantic framing is intentional — "Unknown Presence" reads as *who's-here-and-it's-fine-but-worth-noting*, not as an accusation. For the technical definition, see [ADR-118 — Beamforming Feedback Layer for Detection](docs/adr/ADR-118-bfld-beamforming-feedback-layer-for-detection.md). --- ## Siri-by-Room Name each HomeKit accessory after its room. The HAP bridge pulls room names from the state file prefixes: ```bash python c6-presence-watcher.py --node-id 1 \ --output /tmp/ruview-state.LIVING_ROOM.json # HAP bridge sees this and names the accessory "Living Room" ``` When paired in the Home app, Siri knows the room: | Query | Result | |-------|--------| | "Is anyone in the living room?" | Queries the Living Room accessory's motion sensor | | "Is anyone home?" | Queries all room accessories; returns true if any motion is detected | | "Turn on the bedroom lights when occupancy is detected" | Automation triggers on the Bedroom accessory only | ### StatelessProgrammableSwitch for Automations Each room also exposes a **StatelessProgrammableSwitch** that fires on semantic-event boundaries (Unrecognized Activity Pattern, Recalibration, etc.). This is the HomeKit primitive for momentary triggers: 1. In the Home app, go to **Automation** → **Create New Automation** → **When an Accessory is Controlled**. 2. Select **Living Room** → **Programmable Switch** → **Single Press**. 3. Add an action: *Turn on scene*, *Send notification*, *Set HomeKit Secure Video recording*, etc. --- ## HomePod Announcements via Shortcuts (Tier 2 Path) The easiest way to announce RuView events on a HomePod is through **Shortcuts-as-glue** — a native macOS launchd job that watches RuView's semantic events and triggers a Shortcut you define. This path **bypasses the Bonjour reflector blocker** that can prevent HomePod discovery in some mesh networks. Instead of direct mDNS, the Mac uses the Home graph (iCloud-paired) to reach the HomePod. ### One-Time Setup #### 1. Create the Shortcut in Shortcuts.app 1. Open **Shortcuts.app** on your Mac. 2. Click **+** (top left) → **Create Shortcut**. 3. Click **Add Action** → search for **"Speak Text"** → add it. 4. In the **"Speak Text"** action, click the **speaker icon** → select your **HomePod** (or HomePod mini). 5. Name the Shortcut **`RuView Announce`** (exact name). 6. **Save** (top right). #### 2. Test the Shortcut from the terminal ```bash osascript -e 'tell application "Shortcuts Events" to run shortcut "RuView Announce" with input "Test from RuView"' ``` Your HomePod should speak "Test from RuView" in your chosen voice. #### 3. Install the launchd job Copy the launchd plist from the repository: ```bash cp scripts/macos-shortcuts/ruview-watcher.plist \ ~/Library/LaunchAgents/com.ruvnet.ruview.watcher.plist launchctl load ~/Library/LaunchAgents/com.ruvnet.ruview.watcher.plist launchctl list | grep ruvnet # Confirm it's loaded ``` #### 4. Verify it works Tail the log in one terminal: ```bash tail -f /tmp/ruview-watcher.log ``` In another terminal, walk past the C6 and trigger a presence detection. The log should show: ``` [17:10:12] unknown_presence rising-edge → running 'RuView Announce' ``` And your HomePod should announce the event in its configured voice. ### Extending to Multiple Rooms To announce different events in different rooms, create multiple Shortcuts in Shortcuts.app: - `RuView Announce Kitchen` - `RuView Announce Bedroom` Then run multiple watcher jobs with different `--shortcut-name` flags: ```bash # Kitchen events on HomePod mini in kitchen scripts/macos-shortcuts/announce-via-homepod.sh \ --node-id 1 --event unknown_presence \ --shortcut-name "RuView Announce Kitchen" \ --poll-interval 2 & # Bedroom events on HomePod in bedroom scripts/macos-shortcuts/announce-via-homepod.sh \ --node-id 2 --event unknown_presence \ --shortcut-name "RuView Announce Bedroom" \ --poll-interval 2 & ``` ### Going Further Because the Shortcut is operator-editable in Shortcuts.app, you can extend it to do anything: - **Activate a scene** ("turn on bedtime scene when fall risk detected") - **Send a notification** to your Apple Watch - **Call a Webhook** to integrate with other systems - **Send a message** to another person's iPhone - **Trigger a HomeKit secure camera recording** This is the flexibility of the Shortcuts-as-glue approach — no code change needed in RuView, all customization in the operator's own Shortcuts library. For complete setup details and troubleshooting, see [`scripts/macos-shortcuts/README.md`](scripts/macos-shortcuts/README.md). --- ## Agentic Consumption via MCP RuView's sensing stream is also available through Model Context Protocol (MCP) — the standard interface for Claude Code and other AI agents to query RuView data. ### The `@ruvnet/rvagent` npm package (v0.1.0) The package exposes **12 MCP tools** that let Claude Code agents: - Query presence and occupancy per room - Read breathing rate and heart rate telemetry - Monitor BFLD semantic events - Inspect the app registry (edge modules) - Kickstart background training jobs ### Installation In your Claude Code project: ```bash npm install -D @ruvnet/rvagent@0.1.0 # Or, add via MCP: claude mcp add rvagent -- npx -y @ruvnet/rvagent@0.1.0 ``` Then in your Claude Code chat: ``` /claude-flow-help # Lists all available MCP tools ``` ### Tool Reference | Tool | Input | Output | |------|-------|--------| | `ruview_csi_latest` | node_id | Latest CSI window (1024 subcarriers, 30 OFDM symbols) | | `ruview_pose_infer` | CSI window | 17-keypoint skeleton (x, y, confidence per joint) | | `ruview_count_infer` | CSI window | Person count + 95% CI | | `ruview_registry_list` | query (optional) | List of 105+ available edge modules | | `ruview_train_count` | epochs, learning_rate | Kickoff training job ID | | `ruview_job_status` | job_id | Progress, ETA, current loss | | `ruview.bfld.last_scan` | node_id | Latest BFLD scan: privacy_class, person_count (identity_risk_score=null per I1 invariant) | | `ruview.bfld.subscribe` | node_id, event_filter | Stream BFLD windows until you close the stream | | `ruview.presence.now` | room (optional) | Current occupancy per room | | `ruview.vitals.get_breathing` | node_id | Breathing rate (BPM) + confidence | | `ruview.vitals.get_heart_rate` | node_id | Heart rate (BPM) + confidence | | `ruview.vitals.get_all` | node_id | Breathing + heart rate + metadata | ### Example: Claude Code Agent Workflow ```python # Claude-flow agent pseudocode import claude_code tools = claude_code.mcp_tools("rvagent") # Query latest presence presence = tools["ruview.presence.now"](room="living room") print(f"Living room occupancy: {presence.occupancy}") # True/False # Check vitals vitals = tools["ruview.vitals.get_all"](node_id=1) print(f"Breathing: {vitals.breathing_bpm} BPM") # Stream BFLD events in real-time for event in tools["ruview.bfld.subscribe"](node_id=1, event_filter="unknown_presence"): print(f"Unknown presence detected: privacy_class={event.privacy_class}") ``` For the full MCP specification, see [ADR-124 — rvagent MCP / RuVector npm integration](docs/adr/ADR-124-rvagent-mcp-ruvector-npm-integration.md). --- ## Troubleshooting ### HomePod Not Visible on `dns-sd -B _airplay._tcp local.` from the Mac **Likely cause**: HomePod and Mac are on different subnets despite being on the same SSID. Some mesh networks segment 2.4 GHz and 5 GHz bands onto different `/24` subnets, or place guest devices on a separate VLAN. **Check**: 1. Open your router admin page and confirm both the HomePod and Mac are in the same subnet range (e.g., both `192.168.1.x`). 2. If they're on different subnets (e.g., `192.168.1.x` vs `192.168.100.x`), enable **IGMP Proxying** in your router settings (common on Netgear Nighthawk). If available, enable **Bonjour Repeater** or **mDNS Reflector** instead. 3. Restart the HomePod and Mac. **Note**: The **Shortcuts-as-glue path (Tier 2)** doesn't need this fix — it routes announcements through the iCloud Home graph, not mDNS. ### iPhone Pairing Fails with "Couldn't Add Accessory" **Likely cause**: The HAP bridge's pairing state is corrupt or out of sync with mDNS. **Fix**: 1. Stop the HAP bridge daemon. 2. Delete the pairing state file: ```bash rm -rf ~/.ruview-hap-prod/accessory.state ``` 3. Restart the HAP bridge — it regenerates a new setup code. 4. From the Home app, retry **Add Accessory** → **More Options** with the new setup code. ### The Setup Code Regenerates on Restart **Expected behavior.** HAP-python regenerates the setup code if the pairing persist file is missing or corrupt. Once you've paired successfully, the pairing key is stored separately in `~/.ruview-hap-prod/` and survives restarts — the setup code itself is transient and only matters during initial pairing. If you lose the setup code before pairing, simply delete the state and restart to get a new one. ### Presence Updates Are Slow or Stuck **Likely cause**: The HTTP polling loop in `ruview-sensing-server.py` is blocked, or the C6 is not sending UDP packets. **Check**: 1. Verify the C6 is booting: `ping 192.168.1.20`. 2. Verify packets are reaching the sensing server: ```bash nc -u -l 5005 & # Listen on UDP 5005 # You should see occasional packets from the C6 ``` 3. Manually query the sensing server: ```bash curl http://127.0.0.1:3000/api/v1/vitals/latest ``` Should return JSON with breathing and heart rate fields. 4. If the HAP bridge doesn't reflect the changes after polling, restart it. --- ## What's NOT in Scope These items are intentionally deferred or beyond the current release: | Item | Status | Timeline | |------|--------|----------| | **Matter Protocol (P3)** | Deferred | Waiting for `matter-rs` SDK stabilization; HAP-1.1 covers 95% of the UX today | | **Rust-native HAP (P2)** | Planned | Replaces Python `HAP-python` sidecar; expected after operator feedback from 5+ real pairings | | **PyO3 BFLD wheel deployment (ADR-117 P5)** | Pending | Runtime import flip so Python scripts use the Rust BFLD crate; source-built (✅ `cargo check` green) but wheel not yet published | | **Custom characteristic UUIDs for Eve.app (Iter 8 runtime)** | Scaffolded | Design complete; awaiting HAP-python JSON-loader implementation (small follow-up PR) | | **AirPlay 2 voice synthesis (pyatv)** | Network-pending | Requires HomePod visible on Bonjour from the Mac; Shortcuts-as-glue (Tier 2) is the working alternative | --- ## References - [ADR-125 — RuView ↔ Apple Home native HAP bridge](docs/adr/ADR-125-ruview-apple-home-native-hap-bridge.md) — Design spec, privacy rationale, sequencing - [ADR-118 — Beamforming Feedback Layer for Detection](docs/adr/ADR-118-bfld-beamforming-feedback-layer-for-detection.md) — BFLD privacy gate and identity-risk semantics - [ADR-124 — rvagent MCP / RuVector npm integration](docs/adr/ADR-124-rvagent-mcp-ruvector-npm-integration.md) — MCP tool specification - [Issue #796](https://github.com/ruvnet/RuView/issues/796) — Tier 1+2 sprint tracking (close-out comments have per-iter empirical data) - [scripts/macos-shortcuts/README.md](scripts/macos-shortcuts/README.md) — Shortcuts-as-glue setup and troubleshooting - [HomeKit Accessory Protocol (Non-Commercial Version)](https://developer.apple.com/apple-home/) — HAP-1.1 spec - [HAP-python on GitHub](https://github.com/ikalchev/HAP-python) — Implementation library