← Back to Plugins
Tools

Ruview Presence

DevvGwardo By DevvGwardo 👁 18 views ▲ 0 votes

OpenClaw plugin for presence-aware agent behavior powered by RuView WiFi sensing

GitHub

Install

openclaw plugins install ./openclaw-ruview-presence

Configuration Example

{
  // Plugin configuration (runtime logic)
  "plugins": {
    "entries": {
      "ruview-presence": {
        "enabled": true,
        "config": {
          "ruviewUrl": "http://localhost:3000",
          "confidenceThreshold": 0.3,
          "debounceCount": 2,
          "enableDigest": true
        }
      }
    }
  },

  // Skill configuration (agent instructions)
  "skills": {
    "entries": {
      "ruview-presence": {
        "enabled": true,
        "env": {
          "RUVIEW_API_URL": "http://localhost:3000"
        }
      }
    }
  }
}

README

<p align="center">
  <img src="https://img.shields.io/badge/OpenClaw-Plugin-blueviolet?style=for-the-badge" alt="OpenClaw Plugin">
  <img src="https://img.shields.io/badge/RuView-WiFi%20Sensing-orange?style=for-the-badge" alt="RuView WiFi Sensing">
  <img src="https://img.shields.io/badge/License-MIT-green?style=for-the-badge" alt="MIT License">
</p>

# OpenClaw RuView Presence

**Presence-aware AI agents powered by WiFi sensing.** No cameras. No wearables. Just physics.

Your OpenClaw agents detect whether you're physically present using WiFi signals. When you leave, they queue messages. When you return, they greet you with a digest of everything that happened while you were away.

---

## How It Works

```
                  WiFi Signals
                      |
              +-------v--------+
              |    RuView      |     Detects presence via
              | WiFi Sensing   |     Channel State Information (CSI)
              +-------+--------+
                      |
              GET /api/v1/pose/current
                      |
              +-------v--------+
              | ruview-presence |     State machine:
              |   (this plugin) |     present -> away -> returned
              +-------+--------+
                      |
              +-------v--------+
              |    OpenClaw     |     Agents adapt behavior
              |    Agents       |     based on your presence
              +----------------+
```

| State | What Happens |
|:------|:-------------|
| **Present** | Agents operate normally |
| **Away** | Non-urgent messages are queued; urgent ones sent immediately |
| **Returned** | Agents deliver a welcome-back digest, then resume normal operation |

---

## Quick Start

### 1. Start RuView

```bash
docker run -d -p 3000:3000 --name ruview ruvnet/wifi-densepose:latest
```

Verify it's running:

```bash
curl -s http://localhost:3000/health/live
# {"status":"alive","uptime":4}
```

> Works in simulation mode out of the box — no WiFi hardware needed for testing. The `source` field in API responses will show `"simulate"` (synthetic data) vs `"csi"` (real hardware).

### 2. Install the Plugin

```bash
# From local clone
git clone https://github.com/DevvGwardo/openclaw-ruview-presence.git
openclaw plugins install ./openclaw-ruview-presence

# Or link for development
openclaw plugins install -l ./openclaw-ruview-presence
```

### 3. Configure

Add to your `openclaw.json`:

```jsonc
{
  // Plugin configuration (runtime logic)
  "plugins": {
    "entries": {
      "ruview-presence": {
        "enabled": true,
        "config": {
          "ruviewUrl": "http://localhost:3000",
          "confidenceThreshold": 0.3,
          "debounceCount": 2,
          "enableDigest": true
        }
      }
    }
  },

  // Skill configuration (agent instructions)
  "skills": {
    "entries": {
      "ruview-presence": {
        "enabled": true,
        "env": {
          "RUVIEW_API_URL": "http://localhost:3000"
        }
      }
    }
  }
}
```

### 4. Install the Bundled Skill

```bash
cp -r skills/ruview-presence ~/.openclaw/skills/ruview-presence
```

That's it. Your agents will start checking presence on their next heartbeat. You'll see this in the logs confirming the skill was picked up:

```
config change detected; evaluating reload (skills)
config change applied (dynamic reads: skills)
```

---

## Configuration Reference

| Option | Type | Default | Description |
|:-------|:-----|:--------|:------------|
| `ruviewUrl` | `string` | `http://localhost:3000` | RuView API base URL |
| `pollIntervalMs` | `number` | `10000` | How often to poll RuView (ms) |
| `confidenceThreshold` | `number` | `0.3` | Minimum detection confidence to count as "present" |
| `debounceCount` | `number` | `2` | Consecutive empty readings before marking as "away" |
| `enableDigest` | `boolean` | `true` | Show a summary digest when the user returns |
| `enableZoneAwareness` | `boolean` | `false` | Track which room/zone the user is in |

All options can also be set via environment variables:

| Environment Variable | Maps To |
|:---------------------|:--------|
| `RUVIEW_API_URL` | `ruviewUrl` |
| `RUVIEW_API_KEY` | Auth token (if RuView auth is enabled) |

---

## RuView API Data

These are the actual responses from RuView that the plugin works with.

### Pose Detection (`GET /api/v1/pose/current`)

This is the primary endpoint used for presence detection.

```json
{
  "timestamp": 1773088911.824,
  "source": "simulate",
  "total_persons": 1,
  "persons": [
    {
      "id": 1,
      "confidence": 0.78,
      "zone": "zone_1",
      "bbox": { "x": 270.4, "y": 133.2, "width": 136.6, "height": 235.1 },
      "keypoints": [
        { "name": "nose", "confidence": 0.59, "x": 336.5, "y": 151.8, "z": -0.22 },
        { "name": "left_eye", "confidence": 0.61, "x": 326.1, "y": 146.0, "z": -0.22 },
        { "name": "right_eye", "confidence": 0.66, "x": 346.1, "y": 143.2, "z": -0.22 },
        { "name": "left_shoulder", "confidence": 0.77, "x": 311.3, "y": 185.6, "z": -0.22 },
        { "name": "right_shoulder", "confidence": 0.74, "x": 360.6, "y": 186.9, "z": -0.22 }
      ]
    }
  ]
}
```

Each person includes 17 DensePose-compatible keypoints: nose, left/right eye, left/right ear, left/right shoulder, left/right elbow, left/right wrist, left/right hip, left/right knee, left/right ankle.

### Zone Summary (`GET /api/v1/pose/zones/summary`)

```json
{
  "zones": {
    "zone_1": { "person_count": 1, "status": "monitored" },
    "zone_2": { "person_count": 0, "status": "clear" },
    "zone_3": { "person_count": 0, "status": "clear" },
    "zone_4": { "person_count": 0, "status": "clear" }
  }
}
```

### Vital Signs (`GET /api/v1/vital-signs`)

```json
{
  "vital_signs": {
    "breathing_rate_bpm": 9.4,
    "breathing_confidence": 0.83,
    "heart_rate_bpm": 44.4,
    "heartbeat_confidence": 0.67,
    "signal_quality": 0.52
  },
  "source": "simulate",
  "tick": 19612
}
```

### Full Sensing Data (`GET /api/v1/sensing/latest`)

Returns everything above plus raw signal features (mean RSSI, spectral power, motion/breathing band power), per-sensor subcarrier amplitudes, RF tomography voxel grid, and classification:

```json
{
  "classification": {
    "presence": true,
    "motion_level": "present_still",
    "confidence": 0.78
  },
  "features": {
    "mean_rssi": -37.0,
    "variance": 15.1,
    "spectral_power": 249.0,
    "dominant_freq_hz": 1.85,
    "breathing_band_power": 16.4,
    "motion_band_power": 13.7,
    "change_points": 8
  }
}
```

### Health Check (`GET /health/live`)

```json
{ "status": "alive", "uptime": 1961 }
```

---

## Architecture

### Plugin Layer (`index.ts`)

Hooks into OpenClaw's `before_prompt_build` lifecycle event to poll RuView and manage state transitions. When the user returns after being away, the plugin prepends a digest summary to the agent's context.

Types match the actual RuView API response format — `RuViewPoseResponse`, `RuViewZoneSummary`, `RuViewVitalSigns`, and `RuViewSensingLatest` are all typed to the real payloads.

### Skill Layer (`skills/ruview-presence/`)

Provides standing orders that agents follow during heartbeat cycles. The skill gives agents explicit instructions for presence-aware behavior — checking the API, interpreting results, and acting on state changes. Includes the actual JSON response format so agents can parse responses correctly.

### Gateway RPC Methods

The plugin exposes two methods on the OpenClaw gateway for programmatic access:

| Method | Returns |
|:-------|:--------|
| `ruview.presence` | `{ state, zone, awaySince, queuedEvents, detectedPersons, source }` |
| `ruview.queueEvent` | `{ queued: true, total: <count> }` |

---

## Hardware Options

RuView runs in simulation mode by default (`source: "simulate"` in responses). For real-world presence detection (`source: "csi"`):

| Option | Hardware | Cost | Capability |
|:-------|:---------|:-----|:-----------|
| **No hardware** | Any computer | $0 | Simulation mode (synthetic data) |
| **Basic** | Any WiFi laptop | $0 | RSSI-only presence (coarse) |
| **Recommended** | 3-6x ESP32-S3 + router | ~$54 | Full CSI: pose, breathing, heartbeat, motion |
| **Research** | Intel 5300 / Atheros AR9580 | ~$50-100 | Full CSI with 3x3 MIMO |

---

## Fault Tolerance

- If RuView is unreachable, the plugin **keeps the last known state** and retries on the next heartbeat
- The debounce mechanism prevents false "away" triggers from momentary signal drops (requires 2 consecutive empty readings by default)
- Urgent messages are always delivered immediately, regardless of presence state
- The `source` field in RuView responses distinguishes simulation from real hardware data

---

## Troubleshooting

| Problem | Solution |
|:--------|:---------|
| Agent says "rate limit reached" | Your model provider is rate-limited. Switch to a different model with `openclaw models set <model>` |
| Agent tries to use `read()` tools | The Chat Completions API doesn't support tool calls. Send the agent the data directly or use the Responses API |
| Port 3000 is already in use | Map to a different port: `docker run -d -p 3002:3000 --name ruview ruvnet/wifi-densepose:latest` and update `ruviewUrl` in config |
| Skill not detected | Check `openclaw logs` for `config change detected; evaluating reload (skills)` — if missing, restart the gateway |
| Always shows "present" | In simulation mode, RuView always returns a synthetic person. Use real CSI hardware for actual presence/absence detection |

---

## Project Structure

```
openclaw-ruview-presence/
  index.ts                 Plugin entry point (state machine, polling, digest)
  openclaw.plugin.json     Plugin manifest and config schema
  package.json             Package definition
  skills/
    ruview-presence/
      SKILL.md             Agent standing orders with API response formats
      HEARTBEAT.md         Heartbeat trigger
```

---

## Requirements

- [OpenClaw](https://openclaw.com) agent runtim

... (truncated)
tools

Comments

Sign in to leave a comment

Loading comments...