* feat: happiness scoring pipeline with ESP32 swarm + Cognitum Seed coordinator ADR-065: Hotel guest happiness scoring from WiFi CSI physiological proxies. ADR-066: ESP32 swarm with Cognitum Seed as coordinator for multi-zone analytics. Firmware: - swarm_bridge.c/h: FreeRTOS task on Core 0, HTTP client with Bearer auth, registers with Seed, sends heartbeats (30s) and happiness vectors (5s) - nvs_config: seed_url, seed_token, zone_name, swarm intervals - provision.py: --seed-url, --seed-token, --zone CLI args - esp32-hello-world: capability discovery firmware for 4MB ESP32-S3 variant WASM edge modules: - exo_happiness_score.rs: 8-dim happiness vector from gait speed, stride regularity, movement fluidity, breathing calm, posture, dwell time (events 690-694, 11 tests, ESP32-optimized buffers + event decimation) - ghost_hunter.rs standalone binary: 5.7 KB WASM, feature-gated default pipeline RuView Live: - --mode happiness dashboard with bar visualization - --seed flag for Cognitum Seed bridge (urllib, background POST) - HappinessScorer + SeedBridge classes (stdlib only, no deps) Examples: - seed_query.py: CLI tool (status, search, witness, monitor, report) - provision_swarm.sh: batch provisioning for multi-node deployment - happiness_vector_schema.json: 8-dim vector format documentation Verified live: ESP32 on COM5 (4MB flash) registered with Seed at 10.1.10.236, vectors flowing, witness chain growing (epoch 455, chain 1108). Co-Authored-By: claude-flow <ruv@ruv.net> * ci: raise firmware binary size gate to 1100 KB for HTTP client stack The swarm bridge (ADR-066) adds esp_http_client for Seed communication, which pulls in the HTTP/TLS stack (~150 KB). Binary grew from ~978 KB to ~1077 KB. Raise the gate from 950 KB to 1100 KB. Still fits comfortably in both 4MB (1856 KB OTA slot, 43% free) and 8MB flash variants. Co-Authored-By: claude-flow <ruv@ruv.net>
13 KiB
ADR-065: Hotel Guest Happiness Scoring -- WiFi CSI + Cognitum Seed Bridge
Status: Proposed Date: 2026-03-20 Deciders: @ruvnet Related: ADR-040 (WASM edge modules), ADR-039 (edge intelligence), ADR-042 (CHCI), ADR-064 (multimodal ambient intelligence), ADR-060 (multi-node aggregation)
Context
Hotels lack objective, privacy-preserving methods to measure guest satisfaction in real time. Current approaches (post-stay surveys, NPS scores) are delayed, biased toward extremes, and capture less than 10% of guests. Meanwhile, ambient RF sensing can infer behavioral cues that correlate with comfort and well-being -- without cameras, wearables, or any guest interaction.
Hardware
Two ESP32-S3 variants are deployed:
| Device | Flash | PSRAM | MAC | Port | Notes |
|---|---|---|---|---|---|
| ESP32-S3 (QFN56 rev 0.2) | 4 MB | 2 MB | 1C:DB:D4:83:D2:40 | COM5 | Budget node, uses sdkconfig.defaults.4mb + partitions_4mb.csv |
| ESP32-S3 | 8 MB | 8 MB | -- | COM7 | Full-featured node, existing deployment |
Both run the Tier 2 DSP firmware with presence detection, vitals extraction, fall detection, and gait analysis.
Cognitum Seed Device
A Cognitum Seed unit is deployed on the same network segment:
- Address: 169.254.42.1 (link-local)
- Hardware: Raspberry Pi Zero 2 W
- Firmware: 0.7.0
- Vector store: 398 vectors, dim=8
- API endpoints: 98 (REST, fully documented)
- Sensors: PIR, reed switch (door), vibration, ADS1115 ADC (4-ch analog), BME280 (temp/humidity/pressure)
- Security: Ed25519 custody chain with tamper-evident witness log
The Seed's 8-dimensional vector store and drift detection engine make it a natural aggregation point for behavioral feature vectors extracted from CSI data.
Existing WASM Edge Modules
The following modules already run on-device and produce features relevant to happiness scoring:
| Module | Event IDs | Outputs |
|---|---|---|
exo_emotion_detect.rs |
610-613 | Arousal level, stress index |
med_gait_analysis.rs |
130-134 | Cadence, stride length, regularity |
ret_customer_flow.rs |
410-413 | Entry/exit count, direction |
ret_dwell_heatmap.rs |
420-423 | Dwell time per zone |
Decision
1. New WASM Module: exo_happiness_score.rs
Create a new WASM edge module that fuses outputs from existing modules into an 8-dimensional happiness vector, matching the Seed's vector dimensionality (dim=8).
Event ID registry (690-694):
| Event ID | Name | Description |
|---|---|---|
| 690 | HAPPINESS_VECTOR |
Full 8-dim happiness vector emitted per scoring window |
| 691 | HAPPINESS_TREND |
Windowed trend (rising/falling/stable) over last N vectors |
| 692 | HAPPINESS_ALERT |
Score crossed a configured threshold (low satisfaction) |
| 693 | HAPPINESS_GROUP |
Aggregate score for multi-person zone |
| 694 | HAPPINESS_CALIBRATION |
Baseline recalibration event (new guest check-in) |
2. Happiness Vector Schema (8 Dimensions)
Each dimension is normalized to [0.0, 1.0] where 1.0 = maximal positive signal:
| Dim | Name | Source | Derivation |
|---|---|---|---|
| 0 | gait_speed |
med_gait_analysis (130) |
Normalized walking velocity. Brisk = positive. |
| 1 | stride_regularity |
med_gait_analysis (131) |
Low stride-to-stride variance = relaxed gait. |
| 2 | movement_fluidity |
CSI phase jerk (d3/dt3) | Low jerk = smooth, unhurried movement. |
| 3 | breathing_calm |
Vitals BR extraction | BR 12-18 at rest = calm. Deviation penalized. |
| 4 | posture_openness |
CSI subcarrier spread | Wide phase spread across subcarriers = open posture. |
| 5 | dwell_comfort |
ret_dwell_heatmap (420) |
Moderate dwell in amenity zones = engagement. |
| 6 | direction_entropy |
ret_customer_flow (410) |
Low entropy = purposeful movement. Wandering penalized. |
| 7 | group_energy |
Multi-target CSI clustering | Synchronized movement of 2+ people = social engagement. |
The composite scalar happiness score is the weighted L2 norm:
score = sum(w[i] * v[i] for i in 0..7) / sum(w[i])
Default weights are uniform (all 1.0), configurable via NVS or Seed API.
3. ESP32 to Seed Bridge
ESP32-S3 (CSI) Cognitum Seed (169.254.42.1)
+------------------+ +----------------------------+
| Tier 2 DSP | | |
| + WASM modules | UDP 5555 | /api/v1/store/ingest |
| exo_happiness |──────────────| (POST, 8-dim vector) |
| _score.rs | | |
| | | /api/v1/drift/check |
| |◄─────────────| (drift alerts via webhook) |
| | | |
| | | /api/v1/witness/append |
| | | (Ed25519 audit trail) |
+------------------+ +----------------------------+
Data flow:
- ESP32 runs CSI capture at 20+ Hz and feeds subcarrier data through existing WASM modules.
exo_happiness_score.rscollects outputs from emotion, gait, flow, and dwell modules every scoring window (default: 30 seconds).- The 8-dim happiness vector is packed as a 32-byte payload (8x float32) and sent via UDP to port 5555 on 169.254.42.1.
- A lightweight bridge task on the Seed receives the UDP packet and POSTs it to
/api/v1/store/ingestwith metadata (room ID, timestamp, MAC). - The Seed's drift detection engine monitors the happiness vector stream and flags anomalies (sudden drops, sustained low scores).
- Every ingested vector is appended to the Seed's Ed25519 witness chain, providing a tamper-proof audit trail.
4. Seed Drift Detection for Happiness Trends
The Seed's built-in drift detection compares incoming vectors against a rolling baseline:
- Check-in calibration: When a new guest checks in, event 694 resets the baseline.
- Drift threshold: Configurable (default: cosine distance > 0.3 from baseline triggers alert).
- Trend window: Last 20 vectors (~10 minutes at 30s intervals).
- Alert routing: Seed webhook notifies hotel management system when happiness trend is declining.
5. RuView Live Dashboard Update
ruview_live.py gains a --seed flag:
python ruview_live.py --port COM5 --seed 169.254.42.1 --mode happiness
This mode displays:
- Real-time 8-dim radar chart of the happiness vector
- Scalar happiness score (0-100) with color coding (red/yellow/green)
- Trend sparkline over the last hour
- Seed witness chain status (last hash, chain length)
- Room-level aggregate when multiple ESP32 nodes report
6. Architecture
+------------------------------------------+
| Hotel Room |
| |
| [ESP32-S3] [Cognitum Seed] |
| COM5 or COM7 169.254.42.1 |
| 4MB or 8MB flash Pi Zero 2 W |
| | | |
| | WiFi CSI | PIR, reed, |
| | 20+ Hz | BME280, |
| v | vibration |
| +-----------+ | |
| | Tier 2 DSP| v |
| | presence | +-------------+ |
| | vitals | | Seed API | |
| | gait | | 98 endpoints| |
| | fall det | | 398 vectors | |
| +-----------+ | dim=8 | |
| | +-------------+ |
| v ^ |
| +-----------+ UDP 5555 | |
| | WASM edge |─────────────┘ |
| | happiness | |
| | score | Drift alerts |
| | (690-694) |◄────────────── |
| +-----------+ /api/v1/drift/check |
| |
+------------------------------------------+
|
| MQTT / HTTP
v
+------------------+
| Hotel Management |
| System / RuView |
| Live Dashboard |
+------------------+
7. 4MB Flash Support
The 4MB ESP32-S3 variant (COM5) is officially supported for happiness scoring. The existing partitions_4mb.csv and sdkconfig.defaults.4mb from ADR-265 provide dual OTA slots (1.856 MB each), sufficient for the full Tier 2 DSP firmware plus exo_happiness_score.wasm (estimated < 40 KB).
Build for 4MB variant:
cp sdkconfig.defaults.4mb sdkconfig.defaults
idf.py build
The WASM module loader selects which modules to instantiate based on available heap. On the 4MB/2MB PSRAM variant, happiness scoring runs with a reduced scoring window (60s instead of 30s) to conserve memory.
8. Privacy Considerations
- No cameras. All sensing is RF-based (WiFi subcarrier amplitude/phase).
- No facial recognition. Happiness is inferred from movement patterns, not expressions.
- No audio capture. Breathing rate is extracted from chest wall displacement via RF, not microphone.
- No PII stored on device. Vectors are anonymous; room-to-guest mapping lives only in the hotel PMS.
- Seed witness chain provides auditable proof of what data was collected and when, satisfying GDPR Article 30 record-keeping requirements.
- Guest opt-out: A physical switch on the ESP32 node (GPIO connected to a toggle) disables CSI capture entirely. The Seed's reed switch can also serve as a "privacy mode" trigger (door-mounted magnet removed = sensing paused).
- Data retention: Vectors are retained on the Seed for the duration of the stay plus 24 hours, then purged. The witness chain retains hashes (not vectors) indefinitely for audit.
9. API Integration
Key Cognitum Seed endpoints used:
| Endpoint | Method | Purpose |
|---|---|---|
/api/v1/store/ingest |
POST | Ingest 8-dim happiness vector |
/api/v1/store/query |
POST | Retrieve vectors by room/time range |
/api/v1/drift/check |
GET | Check if current vector drifts from baseline |
/api/v1/drift/configure |
PUT | Set drift threshold and window size |
/api/v1/witness/append |
POST | Append event to Ed25519 custody chain |
/api/v1/witness/verify |
GET | Verify chain integrity |
/api/v1/sensors/bme280 |
GET | Room temperature/humidity (comfort correlation) |
/api/v1/sensors/pir |
GET | PIR presence (cross-validate with CSI) |
Consequences
Positive
- Provides real-time, objective guest satisfaction measurement without surveys or wearables.
- Reuses four existing WASM modules -- the happiness module is a fusion layer, not a rewrite.
- The Seed's 8-dim vector store is a natural fit; no schema changes needed.
- Ed25519 witness chain satisfies hospitality industry audit requirements and GDPR record-keeping.
- Both 4MB and 8MB ESP32-S3 variants are supported, enabling low-cost deployment at scale (~$8 per room for the 4MB node).
- Seed's environmental sensors (BME280, PIR) provide complementary context (room temperature, humidity) that can be correlated with happiness scores.
- No cloud dependency -- all processing is local (ESP32 edge + Seed link-local network).
Negative
- Happiness inference from movement patterns is a proxy, not a direct measurement. Correlation with actual guest satisfaction must be validated empirically.
- The 4MB variant has reduced scoring frequency (60s vs 30s) due to memory constraints.
- UDP transport between ESP32 and Seed is unreliable; packets may be lost. Mitigation: sequence numbers and a small retry buffer on the ESP32 side.
- Link-local addressing (169.254.x.x) limits the Seed to the same network segment as the ESP32. Multi-room deployments need one Seed per subnet or a routed bridge.
- Drift detection thresholds require per-property tuning; a luxury resort has different movement patterns than a budget hotel.
- The system cannot distinguish between guests in a multi-occupancy room without additional multi-target CSI clustering, which is experimental (ADR-064, Tier 3).