Send telemetry data to Plexus using HTTP or WebSocket.
┌──────────────────────────────────────────────────────────────────────────┐
│ PLEXUS CLOUD │
├──────────────────────────────────────────────────────────────────────────┤
│ │
│ Frontend (Next.js) PartyKit Server │
│ app.plexus.company plexus-realtime.partykit.dev │
│ ├── /api/ingest POST ├── Device connections │
│ ├── /api/sessions POST/PATCH ├── Browser connections │
│ ├── /api/auth/device POST/GET/PUT └── Real-time relay │
│ └── /api/auth/verify-key GET │
│ │
└──────────────────────────────────────────────────────────────────────────┘
▲ ▲
│ HTTP │ WebSocket
│ (API Key) │ (API Key)
┌────┴────┐ ┌────┴────┐
│ Scripts │ │ Agent │
│ Devices │ Direct HTTP POST │ plexus │
│ IoT │ │ run │
└─────────┘ └─────────┘
Two ways to send data:
| Method | Use Case |
|---|---|
| HTTP POST | Simple scripts, batch uploads, embedded devices |
| WebSocket | Real-time streaming, UI-controlled devices |
Set up your device with one command. Use an API key for fleet provisioning, or a pairing code for single devices:
# With API key (fleet provisioning — get from Settings → Developer)
curl -sL https://app.plexus.company/setup | bash -s -- --key plx_your_api_key
# With pairing code (single device — get from app.plexus.company/devices)
curl -sL https://app.plexus.company/setup | bash -s -- --code ABC123Then control streaming, recording, and configuration from app.plexus.company/devices.
Send data directly via HTTP:
curl -X POST https://app.plexus.company/api/ingest \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"points": [{
"metric": "temperature",
"value": 72.5,
"timestamp": 1699900000,
"source_id": "sensor-001"
}]
}'Plexus uses API keys for all authentication:
| Type | Prefix | Use Case |
|---|---|---|
| API Key | plx_ |
HTTP access and WebSocket device connections |
Option A: Device pairing (recommended for devices)
- Run
plexus pairon your device - Approve the pairing in your browser
- API key is saved to
~/.plexus/config.json
Option B: Manual creation
- Sign up at app.plexus.company
- Go to Settings → Developer
- Create an API key (starts with
plx_)
All requests require an API key in the header:
x-api-key: plx_xxxxx
POST /api/ingest
{
"points": [
{
"metric": "temperature",
"value": 72.5,
"timestamp": 1699900000.123,
"source_id": "sensor-001",
"tags": { "location": "lab" },
"session_id": "test-001"
}
]
}| Field | Type | Required | Description |
|---|---|---|---|
metric |
string | Yes | Metric name (e.g., temperature, motor.rpm) |
value |
any | Yes | See supported value types below |
timestamp |
float | No | Unix timestamp (seconds). Defaults to now |
source_id |
string | Yes | Your source identifier |
tags |
object | No | Key-value labels |
session_id |
string | No | Group data into sessions |
| Type | Example | Use Case |
|---|---|---|
| number | 72.5, -40, 3.14159 |
Numeric readings (most common) |
| string | "error", "idle", "running" |
Status, state, labels |
| boolean | true, false |
On/off, enabled/disabled |
| object | {"x": 1.2, "y": 3.4, "z": 5.6} |
Vector data, structured readings |
| array | [1.0, 2.0, 3.0, 4.0] |
Waveforms, multiple values |
Group related data for analysis and playback.
Create session:
POST /api/sessions
{
"session_id": "test-001",
"name": "Motor Test Run",
"source_id": "sensor-001",
"status": "active"
}End session:
PATCH /api/sessions/{session_id}
{
"status": "completed",
"ended_at": "2024-01-15T10:30:00Z"
}For real-time UI-controlled streaming, devices connect via WebSocket.
- Device connects to PartyKit server
- Device authenticates with API key
- Device reports available sensors
- Dashboard controls streaming via messages
Devices authenticate using an API key:
// Device → Server
{
"type": "device_auth",
"api_key": "plx_xxxxx",
"source_id": "my-device-001",
"platform": "Linux",
"sensors": [
{
"name": "MPU6050",
"description": "6-axis IMU",
"metrics": ["accel_x", "accel_y", "accel_z", "gyro_x", "gyro_y", "gyro_z"],
"sample_rate": 100,
"prefix": "",
"available": true
}
]
}
// Server → Device
{
"type": "authenticated",
"source_id": "my-device-001"
}| Type | Description |
|---|---|
start_stream |
Start streaming sensor data |
stop_stream |
Stop streaming |
start_session |
Start recording to a session |
stop_session |
Stop recording |
configure |
Configure sensor (e.g., sample rate) |
execute |
Run a shell command |
cancel |
Cancel running command |
ping |
Keepalive request |
| Type | Description |
|---|---|
telemetry |
Sensor data points |
session_started |
Confirm session started |
session_stopped |
Confirm session stopped |
output |
Command output |
pong |
Keepalive response |
// Dashboard → Device
{
"type": "start_stream",
"source_id": "my-device-001",
"metrics": ["accel_x", "accel_y", "accel_z"],
"interval_ms": 100
}
// Device → Dashboard (continuous)
{
"type": "telemetry",
"points": [
{ "metric": "accel_x", "value": 0.12, "timestamp": 1699900000123 },
{ "metric": "accel_y", "value": 0.05, "timestamp": 1699900000123 },
{ "metric": "accel_z", "value": 9.81, "timestamp": 1699900000123 }
]
}// Dashboard → Device
{
"type": "start_session",
"source_id": "my-device-001",
"session_id": "session_1699900000_abc123",
"session_name": "Motor Test",
"metrics": [],
"interval_ms": 100
}
// Device → Dashboard
{
"type": "session_started",
"session_id": "session_1699900000_abc123",
"session_name": "Motor Test"
}
// Device streams telemetry with session_id tag
{
"type": "telemetry",
"session_id": "session_1699900000_abc123",
"points": [
{
"metric": "accel_x",
"value": 0.12,
"timestamp": 1699900000123,
"tags": { "session_id": "session_1699900000_abc123" }
}
]
}// Dashboard → Device
{
"type": "configure",
"source_id": "my-device-001",
"sensor": "MPU6050",
"config": {
"sample_rate": 50
}
}// Dashboard → Device
{
"type": "execute",
"id": "cmd-123",
"command": "uname -a"
}
// Device → Dashboard (streamed)
{"type": "output", "id": "cmd-123", "event": "start", "command": "uname -a"}
{"type": "output", "id": "cmd-123", "event": "data", "data": "Linux raspberrypi..."}
{"type": "output", "id": "cmd-123", "event": "exit", "code": 0}import requests
import time
requests.post(
"https://app.plexus.company/api/ingest",
headers={"x-api-key": "plx_xxxxx"},
json={
"points": [{
"metric": "temperature",
"value": 72.5,
"timestamp": time.time(),
"source_id": "sensor-001"
}]
}
)await fetch("https://app.plexus.company/api/ingest", {
method: "POST",
headers: {
"x-api-key": "plx_xxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({
points: [
{
metric: "temperature",
value: 72.5,
timestamp: Date.now() / 1000,
source_id: "sensor-001",
},
],
}),
});package main
import (
"bytes"
"encoding/json"
"net/http"
"time"
)
func main() {
points := map[string]interface{}{
"points": []map[string]interface{}{{
"metric": "temperature",
"value": 72.5,
"timestamp": float64(time.Now().Unix()),
"source_id": "sensor-001",
}},
}
body, _ := json.Marshal(points)
req, _ := http.NewRequest("POST", "https://app.plexus.company/api/ingest", bytes.NewBuffer(body))
req.Header.Set("x-api-key", "plx_xxxxx")
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}#include <WiFi.h>
#include <HTTPClient.h>
void sendToPlexus(const char* metric, float value) {
HTTPClient http;
http.begin("https://app.plexus.company/api/ingest");
http.addHeader("Content-Type", "application/json");
http.addHeader("x-api-key", "plx_xxxxx");
String payload = "{\"points\":[{";
payload += "\"metric\":\"" + String(metric) + "\",";
payload += "\"value\":" + String(value) + ",";
payload += "\"timestamp\":" + String(millis() / 1000.0) + ",";
payload += "\"source_id\":\"esp32-001\"";
payload += "}]}";
http.POST(payload);
http.end();
}#!/bin/bash
API_KEY="plx_xxxxx"
SOURCE_ID="sensor-001"
curl -X POST https://app.plexus.company/api/ingest \
-H "x-api-key: $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"points\": [{
\"metric\": \"temperature\",
\"value\": 72.5,
\"timestamp\": $(date +%s),
\"source_id\": \"$SOURCE_ID\"
}]
}"Plexus supports protocol adapters for ingesting data from various sources.
Read CAN bus data with optional DBC signal decoding:
pip install plexus-agent[can]from plexus.adapters import CANAdapter
from plexus import Plexus
plexus = Plexus(api_key="plx_xxx", source_id="vehicle-001")
adapter = CANAdapter(
interface="socketcan",
channel="can0",
dbc_path="vehicle.dbc", # Optional: decode signals
)
with adapter:
while True:
for metric in adapter.poll():
# Raw: can.raw.0x123 = "DEADBEEF"
# Decoded: engine_rpm = 2500
plexus.send(metric.name, metric.value, tags=metric.tags)Setup virtual CAN for testing (Linux):
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
# Send test frames
cansend vcan0 123#DEADBEEFSupported interfaces: socketcan, pcan, vector, kvaser, slcan, virtual
Bridge MQTT brokers to Plexus:
pip install plexus-agent[mqtt]from plexus.adapters import MQTTAdapter
adapter = MQTTAdapter(
broker="localhost",
topic="sensors/#",
port=1883,
)
adapter.connect()
adapter.run(on_data=my_callback)For Raspberry Pi and other Linux devices, the Python SDK includes sensor drivers:
pip install plexus-agent[sensors]
plexus pair --code YOUR_CODE
plexus run| Sensor | Type | Metrics | I2C Address |
|---|---|---|---|
| MPU6050 | 6-axis IMU | accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z |
0x68, 0x69 |
| MPU9250 | 9-axis IMU | accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z |
0x68 |
| BME280 | Environment | temperature, humidity, pressure |
0x76, 0x77 |
from plexus.sensors import BaseSensor, SensorReading
class MySensor(BaseSensor):
name = "MySensor"
metrics = ["voltage", "current"]
def read(self):
return [
SensorReading("voltage", read_adc(0) * 3.3),
SensorReading("current", read_adc(1) * 0.1),
]| Status | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request (check JSON format) |
| 401 | Invalid or missing API key |
| 403 | API key lacks permissions |
| 404 | Resource not found |
| 410 | Resource expired (e.g., pairing code) |
- Batch points - Send up to 100 points per request for HTTP
- Use timestamps - Always include accurate timestamps
- Consistent source_id - Use the same ID for each physical device/source
- Use tags - Label data for filtering (e.g.,
{"location": "lab"}) - Use sessions - Group related data for easier analysis
- Prefer WebSocket - For real-time UI-controlled devices, use
plexus run