Skip to content

websocket api

Valtronics Team edited this page May 4, 2026 · 1 revision

WebSocket API Documentation

Complete API reference for real-time WebSocket communication


Overview

The WebSocket API provides real-time bidirectional communication between clients and the Valtronics server. This API enables live data streaming, instant notifications, and real-time updates for devices, telemetry, alerts, and system events.


WebSocket Endpoints

Primary WebSocket Endpoint

ws://localhost:8000/ws

Specialized Endpoints

  • Telemetry Stream: ws://localhost:8000/ws/telemetry
  • Alert Notifications: ws://localhost:8000/ws/alerts
  • System Status: ws://localhost:8000/ws/system
  • Device Status: ws://localhost:8000/ws/devices

Connection Process

1. Establish Connection

const ws = new WebSocket('ws://localhost:8000/ws');

ws.onopen = function(event) {
    console.log('WebSocket connected');
};

2. Authentication

After connection, authenticate with JWT token:

ws.send(JSON.stringify({
    type: 'auth',
    token: 'your-jwt-token'
}));

3. Subscribe to Channels

Subscribe to specific data channels:

ws.send(JSON.stringify({
    type: 'subscribe',
    channel: 'telemetry',
    device_id: 1
}));

Message Formats

Authentication Message

{
  "type": "auth",
  "token": "jwt-token-string"
}

Subscription Message

{
  "type": "subscribe",
  "channel": "channel-name",
  "device_id": 1,
  "filters": {
    "metrics": ["temperature", "humidity"]
  }
}

Unsubscription Message

{
  "type": "unsubscribe",
  "channel": "channel-name",
  "device_id": 1
}

Ping Message (Keep-alive)

{
  "type": "ping",
  "timestamp": "2024-01-01T12:00:00Z"
}

Available Channels

1. Telemetry Channel

Receive real-time telemetry data updates.

Channel: telemetry

Subscription Options:

  • device_id: Specific device ID (optional)
  • metrics: Array of metric names (optional)
  • frequency: Update frequency (optional)

Message Format:

{
  "type": "telemetry_update",
  "channel": "telemetry",
  "device_id": 1,
  "telemetry": {
    "temperature": {
      "value": 23.5,
      "unit": "°C",
      "timestamp": "2024-01-01T12:00:00Z"
    },
    "humidity": {
      "value": 45.2,
      "unit": "%",
      "timestamp": "2024-01-01T12:00:00Z"
    }
  }
}

Example Subscription:

ws.send(JSON.stringify({
    type: 'subscribe',
    channel: 'telemetry',
    device_id: 1,
    filters: {
        metrics: ['temperature', 'humidity'],
        frequency: 'real-time'
    }
}));

2. Alerts Channel

Receive real-time alert notifications.

Channel: alerts

Subscription Options:

  • severity: Alert severity filter (optional)
  • device_id: Specific device ID (optional)
  • alert_type: Alert type filter (optional)

Message Format:

{
  "type": "alert",
  "channel": "alerts",
  "alert_id": 123,
  "device_id": 1,
  "severity": "critical",
  "title": "High Temperature Alert",
  "message": "Temperature exceeds safe threshold",
  "timestamp": "2024-01-01T12:00:00Z",
  "metadata": {
    "threshold_value": 30.0,
    "actual_value": 32.5
  }
}

Example Subscription:

ws.send(JSON.stringify({
    type: 'subscribe',
    channel: 'alerts',
    filters: {
        severity: ['critical', 'warning'],
        device_id: 1
    }
}));

3. Device Status Channel

Receive real-time device status updates.

Channel: devices

Subscription Options:

  • device_id: Specific device ID (optional)
  • status_types: Array of status types to monitor

Message Format:

{
  "type": "device_status_update",
  "channel": "devices",
  "device_id": 1,
  "old_status": "online",
  "new_status": "offline",
  "timestamp": "2024-01-01T12:00:00Z",
  "reason": "Connection lost",
  "metadata": {
    "last_seen": "2024-01-01T11:45:00Z"
  }
}

Example Subscription:

ws.send(JSON.stringify({
    type: 'subscribe',
    channel: 'devices',
    filters: {
        device_id: [1, 2, 3],
        status_types: ['online', 'offline', 'warning']
    }
}));

4. System Status Channel

Receive real-time system status updates.

Channel: system

Subscription Options:

  • metrics: System metrics to monitor
  • frequency: Update frequency

Message Format:

{
  "type": "system_status_update",
  "channel": "system",
  "metrics": {
    "cpu_usage": 45.2,
    "memory_usage": 67.8,
    "disk_usage": 23.1,
    "active_connections": 15
  },
  "timestamp": "2024-01-01T12:00:00Z"
}

Example Subscription:

ws.send(JSON.stringify({
    type: 'subscribe',
    channel: 'system',
    filters: {
        metrics: ['cpu_usage', 'memory_usage', 'active_connections'],
        frequency: '30s'
    }
}));

Client Implementation Examples

JavaScript Client

class ValtronicsWebSocket {
    constructor(url, token) {
        this.url = url;
        this.token = token;
        this.ws = null;
        this.subscriptions = new Map();
        this.reconnectAttempts = 0;
        this.maxReconnectAttempts = 5;
        this.reconnectInterval = 1000;
    }

    connect() {
        this.ws = new WebSocket(this.url);
        
        this.ws.onopen = () => {
            console.log('WebSocket connected');
            this.authenticate();
            this.reconnectAttempts = 0;
        };

        this.ws.onmessage = (event) => {
            this.handleMessage(JSON.parse(event.data));
        };

        this.ws.onclose = () => {
            console.log('WebSocket disconnected');
            this.reconnect();
        };

        this.ws.onerror = (error) => {
            console.error('WebSocket error:', error);
        };
    }

    authenticate() {
        this.send({
            type: 'auth',
            token: this.token
        });
    }

    subscribe(channel, filters = {}) {
        const subscription = {
            type: 'subscribe',
            channel: channel,
            ...filters
        };
        
        this.send(subscription);
        this.subscriptions.set(channel, filters);
    }

    unsubscribe(channel) {
        const subscription = {
            type: 'unsubscribe',
            channel: channel
        };
        
        this.send(subscription);
        this.subscriptions.delete(channel);
    }

    send(message) {
        if (this.ws && this.ws.readyState === WebSocket.OPEN) {
            this.ws.send(JSON.stringify(message));
        }
    }

    handleMessage(data) {
        switch (data.type) {
            case 'auth_response':
                this.handleAuthResponse(data);
                break;
            case 'telemetry_update':
                this.handleTelemetryUpdate(data);
                break;
            case 'alert':
                this.handleAlert(data);
                break;
            case 'device_status_update':
                this.handleDeviceStatusUpdate(data);
                break;
            case 'system_status_update':
                this.handleSystemStatusUpdate(data);
                break;
            case 'pong':
                // Handle keep-alive response
                break;
            default:
                console.log('Unknown message type:', data.type);
        }
    }

    handleTelemetryUpdate(data) {
        // Handle telemetry updates
        console.log('Telemetry update:', data);
        if (this.onTelemetryUpdate) {
            this.onTelemetryUpdate(data);
        }
    }

    handleAlert(data) {
        // Handle alert notifications
        console.log('Alert received:', data);
        if (this.onAlert) {
            this.onAlert(data);
        }
    }

    handleDeviceStatusUpdate(data) {
        // Handle device status updates
        console.log('Device status update:', data);
        if (this.onDeviceStatusUpdate) {
            this.onDeviceStatusUpdate(data);
        }
    }

    handleSystemStatusUpdate(data) {
        // Handle system status updates
        console.log('System status update:', data);
        if (this.onSystemStatusUpdate) {
            this.onSystemStatusUpdate(data);
        }
    }

    reconnect() {
        if (this.reconnectAttempts < this.maxReconnectAttempts) {
            this.reconnectAttempts++;
            setTimeout(() => {
                console.log(`Reconnecting... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
                this.connect();
            }, this.reconnectInterval * this.reconnectAttempts);
        }
    }

    disconnect() {
        if (this.ws) {
            this.ws.close();
            this.ws = null;
        }
    }
}

// Usage example
const wsClient = new ValtronicsWebSocket('ws://localhost:8000/ws', 'jwt-token');

wsClient.onTelemetryUpdate = (data) => {
    console.log('New telemetry data:', data.telemetry);
};

wsClient.onAlert = (data) => {
    console.log('New alert:', data.title);
    showNotification(data);
};

wsClient.connect();
wsClient.subscribe('telemetry', { device_id: 1 });
wsClient.subscribe('alerts', { severity: ['critical', 'warning'] });

Python Client

import asyncio
import json
import websockets
from datetime import datetime

class ValtronicsWebSocketClient:
    def __init__(self, url, token):
        self.url = url
        self.token = token
        self.websocket = None
        self.subscriptions = {}
        self.running = False

    async def connect(self):
        """Connect to WebSocket server"""
        try:
            self.websocket = await websockets.connect(self.url)
            await self.authenticate()
            self.running = True
            print("WebSocket connected successfully")
        except Exception as e:
            print(f"Failed to connect: {e}")
            raise

    async def authenticate(self):
        """Authenticate with JWT token"""
        auth_message = {
            "type": "auth",
            "token": self.token
        }
        await self.send_message(auth_message)
        
        # Wait for authentication response
        response = await self.websocket.recv()
        data = json.loads(response)
        
        if data.get("type") == "auth_response" and data.get("success"):
            print("Authentication successful")
        else:
            raise Exception("Authentication failed")

    async def subscribe(self, channel, filters=None):
        """Subscribe to a channel"""
        subscription = {
            "type": "subscribe",
            "channel": channel
        }
        if filters:
            subscription["filters"] = filters
        
        await self.send_message(subscription)
        self.subscriptions[channel] = filters
        print(f"Subscribed to {channel}")

    async def unsubscribe(self, channel):
        """Unsubscribe from a channel"""
        unsubscription = {
            "type": "unsubscribe",
            "channel": channel
        }
        await self.send_message(unsubscription)
        self.subscriptions.pop(channel, None)
        print(f"Unsubscribed from {channel}")

    async def send_message(self, message):
        """Send message to WebSocket"""
        if self.websocket:
            await self.websocket.send(json.dumps(message))

    async def listen(self):
        """Listen for incoming messages"""
        try:
            while self.running:
                message = await self.websocket.recv()
                data = json.loads(message)
                await self.handle_message(data)
        except websockets.exceptions.ConnectionClosed:
            print("WebSocket connection closed")
        except Exception as e:
            print(f"Error listening for messages: {e}")

    async def handle_message(self, data):
        """Handle incoming messages"""
        message_type = data.get("type")
        
        if message_type == "telemetry_update":
            await self.handle_telemetry_update(data)
        elif message_type == "alert":
            await self.handle_alert(data)
        elif message_type == "device_status_update":
            await self.handle_device_status_update(data)
        elif message_type == "system_status_update":
            await self.handle_system_status_update(data)
        elif message_type == "pong":
            # Handle keep-alive response
            pass
        else:
            print(f"Unknown message type: {message_type}")

    async def handle_telemetry_update(self, data):
        """Handle telemetry updates"""
        device_id = data.get("device_id")
        telemetry = data.get("telemetry")
        print(f"Telemetry update for device {device_id}: {telemetry}")

    async def handle_alert(self, data):
        """Handle alert notifications"""
        alert_id = data.get("alert_id")
        severity = data.get("severity")
        title = data.get("title")
        print(f"Alert [{severity}]: {title} (ID: {alert_id})")

    async def handle_device_status_update(self, data):
        """Handle device status updates"""
        device_id = data.get("device_id")
        old_status = data.get("old_status")
        new_status = data.get("new_status")
        print(f"Device {device_id} status changed: {old_status} -> {new_status}")

    async def handle_system_status_update(self, data):
        """Handle system status updates"""
        metrics = data.get("metrics")
        print(f"System status update: {metrics}")

    async def ping(self):
        """Send ping message (keep-alive)"""
        ping_message = {
            "type": "ping",
            "timestamp": datetime.utcnow().isoformat()
        }
        await self.send_message(ping_message)

    async def disconnect(self):
        """Disconnect from WebSocket"""
        self.running = False
        if self.websocket:
            await self.websocket.close()
            print("WebSocket disconnected")

# Usage example
async def main():
    client = ValtronicsWebSocket("ws://localhost:8000/ws", "jwt-token")
    
    try:
        await client.connect()
        
        # Subscribe to channels
        await client.subscribe("telemetry", {"device_id": 1})
        await client.subscribe("alerts", {"severity": ["critical", "warning"]})
        await client.subscribe("devices")
        
        # Listen for messages
        await client.listen()
        
    except KeyboardInterrupt:
        print("Interrupted by user")
    finally:
        await client.disconnect()

if __name__ == "__main__":
    asyncio.run(main())

Error Handling

Connection Errors

ws.onerror = function(error) {
    console.error('WebSocket error:', error);
    // Implement error handling logic
    switch (error.code) {
        case 1006:
            console.log('Connection lost - attempting to reconnect');
            break;
        case 1000:
            console.log('Normal closure');
            break;
        default:
            console.log('Unknown error code:', error.code);
    }
};

Authentication Errors

function handleAuthResponse(data) {
    if (!data.success) {
        console.error('Authentication failed:', data.message);
        // Handle authentication failure
        if (data.error === 'invalid_token') {
            // Refresh token or redirect to login
            refreshToken();
        }
    }
}

Message Processing Errors

function handleMessage(data) {
    try {
        // Validate message structure
        if (!data.type) {
            throw new Error('Missing message type');
        }
        
        // Process message
        processMessage(data);
        
    } catch (error) {
        console.error('Error processing message:', error);
        // Send error report to server
        sendErrorReport(error, data);
    }
}

Performance Optimization

Connection Pooling

class WebSocketPool {
    constructor(maxConnections = 5) {
        this.connections = [];
        this.maxConnections = maxConnections;
        this.currentIndex = 0;
    }

    getConnection() {
        if (this.connections.length < this.maxConnections) {
            const ws = new WebSocket('ws://localhost:8000/ws');
            this.connections.push(ws);
            return ws;
        }
        
        // Round-robin selection
        const ws = this.connections[this.currentIndex];
        this.currentIndex = (this.currentIndex + 1) % this.connections.length;
        return ws;
    }
}

Message Batching

class MessageBatcher {
    constructor(ws, batchSize = 10, batchTimeout = 100) {
        this.ws = ws;
        this.batchSize = batchSize;
        this.batchTimeout = batchTimeout;
        this.messageQueue = [];
        this.batchTimer = null;
    }

    send(message) {
        this.messageQueue.push(message);
        
        if (this.messageQueue.length >= this.batchSize) {
            this.flushBatch();
        } else if (!this.batchTimer) {
            this.batchTimer = setTimeout(() => this.flushBatch(), this.batchTimeout);
        }
    }

    flushBatch() {
        if (this.messageQueue.length > 0) {
            const batch = {
                type: 'batch',
                messages: [...this.messageQueue]
            };
            
            this.ws.send(JSON.stringify(batch));
            this.messageQueue = [];
        }
        
        if (this.batchTimer) {
            clearTimeout(this.batchTimer);
            this.batchTimer = null;
        }
    }
}

Security Considerations

Token Validation

  • Always validate JWT tokens before allowing connections
  • Implement token refresh mechanisms
  • Monitor for suspicious connection patterns

Message Validation

  • Validate all incoming message structures
  • Implement rate limiting per connection
  • Sanitize message content

Connection Security

  • Use WSS (WebSocket Secure) in production
  • Implement origin validation
  • Monitor connection attempts

Rate Limiting

Connection Limits

  • Maximum 100 concurrent connections per user
  • Maximum 1000 total concurrent connections
  • Connection rate limited to 10 per minute

Message Limits

  • Maximum 100 messages per second per connection
  • Maximum 1KB message size
  • Batch messages limited to 50 items

Monitoring and Logging

Connection Monitoring

class ConnectionMonitor {
    constructor() {
        this.connections = new Map();
        this.stats = {
            totalConnections: 0,
            activeConnections: 0,
            messagesReceived: 0,
            messagesSent: 0
        };
    }

    addConnection(connectionId, ws) {
        this.connections.set(connectionId, {
            ws: ws,
            connectedAt: new Date(),
            messagesReceived: 0,
            messagesSent: 0
        });
        
        this.stats.totalConnections++;
        this.stats.activeConnections++;
    }

    removeConnection(connectionId) {
        this.connections.delete(connectionId);
        this.stats.activeConnections--;
    }

    getStats() {
        return {
            ...this.stats,
            averageConnectionDuration: this.calculateAverageDuration(),
            messagesPerConnection: this.calculateMessagesPerConnection()
        };
    }
}

Message Logging

function logMessage(direction, message) {
    const logEntry = {
        timestamp: new Date().toISOString(),
        direction: direction, // 'sent' or 'received'
        type: message.type,
        size: JSON.stringify(message).length,
        channel: message.channel
    };
    
    console.log('WebSocket message:', logEntry);
    
    // Send to logging service
    sendToLoggingService(logEntry);
}

Best Practices

Connection Management

  • Implement proper connection lifecycle management
  • Handle reconnection logic gracefully
  • Monitor connection health and performance
  • Implement connection pooling for high-load scenarios

Message Handling

  • Validate all message structures
  • Implement proper error handling
  • Use message batching for high-frequency updates
  • Implement message deduplication when necessary

Performance Optimization

  • Use binary message formats for large data
  • Implement message compression
  • Optimize message size and frequency
  • Use connection pooling and load balancing

Security

  • Always use WSS in production
  • Implement proper authentication and authorization
  • Validate and sanitize all messages
  • Monitor for suspicious activity

Troubleshooting

Common Issues

Connection Failures

  • Check WebSocket server status
  • Verify JWT token validity
  • Check network connectivity
  • Verify WebSocket URL and port

Authentication Issues

  • Ensure JWT token is not expired
  • Check token format and structure
  • Verify token permissions
  • Check server authentication logs

Message Issues

  • Validate message JSON format
  • Check message size limits
  • Verify channel subscriptions
  • Check server message processing logs

Debugging Tools

// WebSocket debugging utility
class WebSocketDebugger {
    constructor(ws) {
        this.ws = ws;
        this.enabled = true;
        this.logLevel = 'info'; // debug, info, warn, error
    }

    log(level, message, data = null) {
        if (!this.enabled || !this.shouldLog(level)) return;
        
        const timestamp = new Date().toISOString();
        const logEntry = {
            timestamp,
            level: level.toUpperCase(),
            message,
            data
        };
        
        console.log(`[WebSocket] ${timestamp} ${logEntry.level}: ${message}`, data);
    }

    shouldLog(level) {
        const levels = ['debug', 'info', 'warn', 'error'];
        return levels.indexOf(level) >= levels.indexOf(this.logLevel);
    }

    enable() {
        this.enabled = true;
    }

    disable() {
        this.enabled = false;
    }

    setLogLevel(level) {
        this.logLevel = level;
    }
}

Support

For WebSocket API support:


© 2024 Software Customs Auto Bot Solution. All Rights Reserved.
WebSocket API Documentation v1.0

Clone this wiki locally