ruvnet / ruvnet/RuView

ESP32-S3 CSI UDP packets reach sensing-server but no data appears in Web UI

Open
#1,725 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug firmware
Dominant language
Rust
Stars
94.5k
Forks
12.5k
Avg merge
21h 27m
Merged PRs (30d)
43

Description

Problem

I am trying to run the RuView WiFi DensePose sensing pipeline using two ESP32-S3 CSI nodes.

The ESP32 devices are successfully connected to WiFi and are continuously transmitting UDP packets to the RuView sensing server. The packets are confirmed to reach the host, and the sensing server is configured to listen on the LAN interface.

However, the sensing server does not register either ESP32 node, /api/v1/nodes remains empty, /api/v1/sensing/latest reports no data yet, and the Web UI shows no live sensing values.

The WebSocket connection itself is established successfully.

I suspect that something is missing in the sensing-server processing/decoding path between the UDP CSI receiver on port 5005 and the data exposed to the API/WebSocket/UI.

Environment
OS: Ubuntu Linux
Architecture: x86_64
Python: 3.12
ESP32 target: ESP32-S3
RuView: v2
Sensing server: Rust/Axum
UDP port: 5005
HTTP port: 3000
WebSocket port: 3001
ESP32 nodes

I have two ESP32-S3 CSI nodes connected to the same local network as the RuView host.

Both nodes are continuously sending UDP traffic to the RuView host on:

<HOST_IP>:5005

The exact local IP addresses and MAC addresses are omitted for privacy.

CSI firmware configuration

The firmware source contains:

CONFIG_ESP_WIFI_CSI_ENABLED=y

This is present in:

firmware/esp32-csi-node/sdkconfig.defaults
firmware/esp32-csi-node/sdkconfig.defaults.template
firmware/esp32-csi-node/sdkconfig.defaults.s3-fair

Therefore CSI is enabled in the firmware configuration.

Sensing server configuration

Initially, the sensing server was listening only on loopback:

127.0.0.1:5005

I changed the configuration to allow LAN UDP input:

./target/release/sensing-server
--source esp32
--udp-port 5005
--udp-bind 0.0.0.0
--udp-allow <LOCAL_NETWORK_CIDR>
--http-port 3000
--ws-port 3001
--ui-path ../ui

The UDP socket is now confirmed to be listening on all interfaces:

0.0.0.0:5005

Therefore the UDP bind/interface issue appears to be resolved.

UDP packets are definitely reaching the host

Using:

sudo tcpdump -ni <NETWORK_INTERFACE> udp port 5005

I can continuously see packets from both ESP32-S3 nodes:

<ESP32_NODE_1> > :5005: UDP, length 276
<ESP32_NODE_2> > :5005: UDP, length 276

There are also occasional smaller packets of approximately 32, 48, and 60 bytes.

A captured packet has a UDP payload beginning with:

01 00 11 c5 03 01 80 00 ...

The first four bytes:

01 00 11 c5

correspond to the little-endian value:

0xC5110001

This appears to match the ADR-018 CSI magic documented by the current v2 parser.

The packet also contains a substantial amount of structured CSI data.

No packet loss at the host

The tcpdump capture reports:

packets captured
packets received by filter
0 packets dropped by kernel

Therefore the Linux host is successfully receiving the UDP traffic.

Current API result

Despite continuous UDP traffic, the server reports no nodes:

curl -s http://localhost:3000/api/v1/nodes

Result:

{
"nodes": [],
"total": 0
}

The latest sensing endpoint reports:

curl -s http://localhost:3000/api/v1/sensing/latest

Result:

{
"status": "no data yet"
}
WebSocket/UI

The sensing server successfully establishes WebSocket connections:

WebSocket client connected (sensing)
WebSocket client connected (pose)

The Web UI therefore successfully connects to the backend.

However, no sensing frames appear to be delivered to the UI.

The live UI remains approximately:

Connection: Connected
RSSI: -- dBm
Variance: 0
Motion Band: 0
Breathing Band: 0
Spectral Power: 0
Classification: ABSENT
Confidence: 0%
Parser investigation

I found the ESP32 CSI parser at:

v2/crates/wifi-densepose-hardware/src/esp32_parser.rs

and the sensing-server CSI parser at:

v2/crates/wifi-densepose-sensing-server/src/csi.rs

The v2 source documents the ADR-018 raw CSI frame magic as:

0xC511_0001

The captured UDP packet starts with:

01 00 11 c5

which corresponds to:

0xC5110001

Therefore the packet appears to contain the expected CSI frame magic.

However, the server still does not register the ESP32 nodes or produce sensing data.

Expected behavior

I expect the sensing server to process the UDP CSI frames through the following pipeline:

ESP32-S3 CSI nodes
|
| UDP CSI
v
UDP :5005
|
| CSI frame parsing
v
RuView sensing pipeline
|
+------> /api/v1/nodes
|
+------> /api/v1/sensing/latest
|
+------> WebSocket :3001
|
v
Web UI

The ESP32-to-host UDP portion is confirmed to be working.

The WebSocket connection from the UI is also confirmed to be working.

The missing part appears to be processing, decoding, validation, or registration of the received CSI frames.

Actual behavior
ESP32 WiFi connection WORKING
ESP32 CSI enabled WORKING
ESP32 UDP transmission WORKING
UDP packets reach host WORKING
UDP server bind 0.0.0.0:5005 WORKING
Expected CSI magic present APPEARS VALID
WebSocket connection WORKING

ESP32 node registration NOT WORKING
/api/v1/nodes nodes: []
/api/v1/sensing/latest no data yet
Live sensing frames NOT RECEIVED
Web UI sensing values ZERO/EMPTY
Request for help

Could someone please help identify what is missing between the UDP CSI receiver and the sensing pipeline/UI?

Specifically:

Are these UDP packets valid ESP32 CSI frames for the current ADR-018 implementation?
Is the current v2 esp32_parser.rs expected to decode this packet format?
Is there additional configuration required for ESP32 node registration?
Is there a firmware/protocol version mismatch between firmware/esp32-csi-node and the v2 sensing server?
Is the sensing server receiving the UDP datagrams but silently rejecting them during parsing or validation?
Is there a debug/logging option that can show why an incoming CSI frame is rejected?
What is the expected path from a successfully parsed ESP32 CSI frame to /api/v1/nodes, /api/v1/sensing/latest, and the WebSocket stream?
Is there any additional step required to convert the received CSI frames into the sensing frames consumed by the Web UI?

The main goal is to get the ESP32-S3 CSI frames successfully processed by the sensing server and displayed as live sensing data in the RuView Web UI.

I can provide the full raw UDP packet, firmware version, build configuration, server logs, and relevant parser output if required.

I have intentionally omitted the exact local IP addresses and MAC addresses from this issue.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with v2/crates/wifi-densepose-hardware/src/esp32_parser.rs and v2/crates/wifi-densepose-sensing-server/src/csi.rs, then trace how UDP port 5005 input reaches node registration and the sensing APIs. Compare the captured ADR-018 packet format with parser expectations and inspect the server output while packets arrive. Done means valid ESP32 frames register in /api/v1/nodes and produce data for /api/v1/sensing/latest and the WebSocket/UI.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend-api-design, embedded-iot
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.