WebSocket API
The Apollon API provides a WebSocket endpoint for real-time data broadcasts from the Peplink GPS router. Clients subscribe to named channels and receive structured JSON messages.
Endpoint
GET /ws?token=<token>
Upgrades to a WebSocket connection. Requires a valid API token as query parameter. Returns 503 Service Unavailable if the server is shutting down.
Channels
| Channel | Mode | Description |
|---|---|---|
speed | Polled | Speed in 4 units (km/h, m/s, mph, knots) |
gps | Polled | Location, heading, and DOP (dilution of precision) |
trips | Event-driven | Trip lifecycle events (started, completed, cancelled) |
Connection Flow
Client Server
| |
| --- WebSocket Upgrade (?token=xxx) --> |
| <-- 101 Switching Protocols ---------- |
| |
| --- Subscribe ["speed","gps"] -------> |
| <-- Ack { subscribed: [...] } -------- |
| |
| <-- Speed message ------------------- | (on change, at interval)
| <-- GPS message --------------------- | (on change, at interval)
| <-- Trip event ---------------------- | (when trip state changes)
| |
| <-- Ping ---------------------------- | (every 30 seconds)
| --- Pong ---------------------------> |
| |
| --- Unsubscribe ["speed"] ----------> |
| <-- Ack { unsubscribed: [...] } ----- |
| |
| --- Close --------------------------> |
| <-- Close --------------------------- |
Subscribe / Unsubscribe Protocol
Subscribe
Send a JSON message to subscribe to one or more channels:
{
"action": "subscribe",
"channels": ["speed", "gps"]
}
The server responds with an acknowledgement:
{
"type": "subscribed",
"channels": ["speed", "gps"]
}
Wildcard Subscribe
Subscribe to all available channels at once:
{
"action": "subscribe",
"channels": ["*"]
}
Unsubscribe
{
"action": "unsubscribe",
"channels": ["speed"]
}
The server responds:
{
"type": "unsubscribed",
"channels": ["speed"]
}
Error Handling
If a client sends an invalid message or references an unknown channel, the server responds with an error:
{
"type": "error",
"message": "Unknown channel: invalid_channel"
}
Errors do not close the connection. The client can continue sending valid messages.
Message Formats
Speed Channel
Broadcast when the speed value changes.
{
"type": "speed",
"data": {
"speed_kmh": 45.2,
"speed_mps": 12.56,
"speed_mph": 28.09,
"speed_knots": 24.41
}
}
| Field | Type | Description |
|---|---|---|
speed_kmh | f64 | Current speed in km/h |
speed_mps | f64 | Current speed in meters per second |
speed_mph | f64 | Current speed in miles per hour |
speed_knots | f64 | Current speed in knots |
GPS Channel
Broadcast when the GPS position or heading changes.
{
"type": "gps",
"data": {
"latitude": 52.5200,
"longitude": 13.4050,
"altitude": 34.5,
"heading": 182.3,
"pdop": 1.2,
"hdop": 0.9,
"vdop": 0.8,
"timestamp": "2026-06-10T12:34:56Z"
}
}
| Field | Type | Description |
|---|---|---|
latitude | f64 | Latitude in decimal degrees |
longitude | f64 | Longitude in decimal degrees |
altitude | f64 | Altitude in meters above sea level |
heading | f64 | Heading in degrees (0-360) |
pdop | f64 | Position dilution of precision |
hdop | f64 | Horizontal dilution of precision |
vdop | f64 | Vertical dilution of precision |
timestamp | string | ISO 8601 timestamp of the GPS fix |
Trips Channel
Event-driven messages when trip state changes.
{
"type": "trips",
"data": {
"event": "started",
"tripId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"trip": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "ACTIVE",
"senderId": "...",
"receiverId": "..."
}
}
}
| Field | Type | Description |
|---|---|---|
event | string | Event type: started, completed, cancelled |
tripId | string | UUID of the affected trip |
trip | object | Trip snapshot at the time of the event |
Configuration
WebSocket behavior is configured via the websocket section in the config file or APOLLON__WEBSOCKET__* environment variables:
| Config Key | Env Var | Default | Description |
|---|---|---|---|
websocket.path | APOLLON__WEBSOCKET__PATH | /ws | WebSocket endpoint path |
websocket.speed_interval_ms | APOLLON__WEBSOCKET__SPEED_INTERVAL_MS | 1000 | Speed broadcast interval in milliseconds |
websocket.gps_interval_ms | APOLLON__WEBSOCKET__GPS_INTERVAL_MS | 1000 | GPS broadcast interval in milliseconds |
JavaScript Client Example
const ws = new WebSocket('ws://localhost:3000/ws?token=YOUR_API_TOKEN');
ws.onopen = () => {
console.log('Connected to Apollon WebSocket');
// Subscribe to speed and GPS channels
ws.send(JSON.stringify({
action: 'subscribe',
channels: ['speed', 'gps', 'trips'],
}));
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
switch (message.type) {
case 'subscribed':
console.log('Subscribed to:', message.channels);
break;
case 'speed':
console.log(`Speed: ${message.data.speed_kmh} km/h`);
break;
case 'gps':
console.log(`Position: ${message.data.latitude}, ${message.data.longitude}`);
break;
case 'trips':
console.log(`Trip ${message.data.event}: ${message.data.tripId}`);
break;
case 'error':
console.error('Server error:', message.message);
break;
}
};
ws.onclose = (event) => {
console.log(`Disconnected: code=${event.code}`);
};
ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
Architecture
PeplinkRouter / MockProvider
|
v
GPS Provider (shared)
| |
v v
SpeedBroadcaster GpsBroadcaster (poll GPS at interval)
| |
v v
speed::broadcast gps::broadcast (tokio broadcast channels, capacity: 256)
| |
+------+------+ TripBroadcaster (event-driven)
| |
v v
WsServer ---- trips::broadcast (tokio broadcast channel)
| |
Client Client (each subscribes to selected channels)
SpeedBroadcaster
Runs as a tokio task that polls the GPS provider at the configured interval, compares the new speed to the last broadcast, and only sends if the value changed. Stores the last broadcast for greeting new subscribers.
GpsBroadcaster
Runs as a tokio task that polls the GPS provider at the configured interval, compares the new position/heading/DOP to the last broadcast, and only sends if any value changed. Stores the last broadcast for greeting new subscribers.
TripBroadcaster
Publishes trip lifecycle events (started, completed, cancelled) to the trips broadcast channel. Events are fired by the trip management endpoints when trip state changes.
WsServer
Manages client connections, channel subscriptions, and broadcast distribution. Rejects new connections during shutdown (503). Each client connection spawns a tokio task that listens for broadcasts on subscribed channels, pings, and client messages concurrently via tokio::select!.