Hardware Integration
Plexus can receive telemetry from any device that can make an HTTP request.
| Path | Best for |
|---|---|
| Python SDK | Raspberry Pi, Jetson, Linux-based boards |
| HTTP (Microcontrollers) | ESP32, Arduino, bare-metal, any platform |
Both paths use the same source_id to identify a device and the same ingest
endpoint — the SDK is a thin wrapper that adds batching, retries, and
connection management.
Specs, Tips and Limits
Metric + Event Limits
| Maximum | |
|---|---|
| Sustained message rate | 500/sec per WebSocket connection |
| Burst capacity | 2,000 messages per WebSocket connection |
| Batches per source | 2,000/sec |
| Points per batch | 10,000 |
| Tags per point | 16 |
| Metric name / tag key / tag value length | 256 characters |
| Event value (JSON object or array) | 4,096 bytes |
| HTTP body | 5 MB |
The per-connection limits are a token bucket on the WebSocket path only —
they don't apply to HTTP /ingest. Burst is the bucket's capacity, not a
rate: you get one burst of 2,000 messages, refilling at 500/s. The per-source
cap counts batches (messages), not points, so batching more points per send
buys headroom. It's enforced as a 0.5 ms minimum inter-message interval —
two batches sent back-to-back can drop the second even at low average rates,
so space out tight flush loops. HTTP batches dropped by the per-source
limiter still return 200 — check the count field in the response; it
comes back lower than what you sent.
Metrics and events share the same rate limit — px.event() calls draw from
the same budget as px.send().
Video
Recommended: 1280×720, quality 85, ≤20 FPS. Good image quality with comfortable headroom under the 1 MB frame limit.
Maximum: 1920×1080 at quality 85 (~500–800 KB per frame).
Each frame has a hard limit of 1 MB — frames above ~750 KB are adaptively
re-encoded by the SDK before send. There is no server-side frame-rate cap:
the frame rate is whatever the viewer requests via max_fps (0 = unlimited).
The dashboard UI requests at most 60 FPS and defaults to 10.
Video is relayed live: the gateway drops unwatched frames and stores nothing by default. The exception is Recording — dashboards can opt in per stream, and recorded video is saved to cloud storage under Data → Recordings.
Time handling
Let Plexus handle timing. The SDK timestamps each point on send and corrects automatically for source system clock drift — no configuration needed.
If your device has a reliable real-time clock and you need data timestamped at the moment of measurement rather than send, pass an explicit value in Unix seconds:
import time
px.send(metric="battery.voltage", value=12.4, timestamp=time.time())The most important case is source-side buffering. If your device queues
readings locally — during a connectivity gap, for example — and flushes them
later, omitting timestamp would mark every point with the flush time, losing
the original measurement timeline. Capture the timestamp at the moment of
measurement and include it on send:
# At measurement time
reading_time = time.time()
# Later, when flushing the buffer
px.send_batch(
points=[
("battery.voltage", 12.4),
("sensor.temperature_c", 23.5),
("motor.rpm", 1200),
],
timestamp=reading_time, # Unix seconds — when these were measured
)On the HTTP path, values below 1e12 are treated as seconds and converted to
milliseconds automatically. Values at or above 1e12 are passed through as-is.
Metric naming
Use <subsystem>.<metric> for all metric names:
battery.voltage motor.rpm sensor.temperature_c
imu.accel_x gps.latitude system.uptime_sConsistent naming makes it easy to query a subsystem (battery.*), build
dashboards, and set alerts without renaming metrics later.
source_id format
source_id must be lowercase and match [a-z0-9][a-z0-9._-]* — letters,
digits, dots, hyphens, and underscores, starting with a letter or digit.