Real-time fleet status dashboard using MQTT and WebSockets for instant updates

We implemented a real-time fleet status dashboard for a logistics company with 500 vehicles using Watson IoT Platform, MQTT for device connectivity, and WebSockets for browser updates. Previously, their dashboard refreshed every 60 seconds via polling, causing high latency in fleet visibility.

The new architecture pushes vehicle status updates to the dashboard instantly via WebSockets, reducing latency from 60 seconds to <1 second. We used Node-RED for message routing between MQTT (vehicle telemetry) and WebSockets (dashboard connections).

Key implementation aspects:

  • MQTT topic design for efficient message routing
  • WebSocket connection management for 100+ concurrent dashboard users
  • Node-RED flows for real-time message transformation and routing

The solution improved operational efficiency significantly - dispatchers can now respond to vehicle issues within seconds instead of minutes. Sharing this implementation for others building real-time IoT dashboards.

This is a great use case for WebSockets! How did you handle WebSocket connection scaling? With 100+ concurrent users, you must have implemented connection pooling or load balancing. Did you use a WebSocket gateway or handle connections directly in Node-RED? Also curious about your MQTT topic structure - did you use hierarchical topics per vehicle or consolidated topics?

Excellent implementation! Here’s how we’ve extended similar architectures for enterprise-scale real-time dashboards:

Architecture Overview:

  1. MQTT Topic Design: Hierarchical structure for efficient routing

    • Vehicle telemetry: `fleet/{region}/{vehicle_id}/telemetry
    • Vehicle status: `fleet/{region}/{vehicle_id}/status
    • Vehicle alerts: `fleet/{region}/{vehicle_id}/alerts
    • Benefits: Regional filtering, wildcard subscriptions, scalable routing
  2. Node-RED Message Routing: Central hub between MQTT and WebSockets

    • Subscribe to MQTT topics: fleet/+/+/telemetry, fleet/+/+/status, `fleet/+/+/alerts
    • Transform messages to dashboard format (normalize fields, add metadata)
    • Route to appropriate WebSocket connections based on subscriptions
    • Implement rate limiting (max 10 messages/second per vehicle to prevent flooding)
  3. WebSocket Integration: Real-time push to browser clients

    • Client connects via WebSocket to Node-RED endpoint
    • Client sends subscription message with vehicle IDs of interest
    • Server pushes only subscribed vehicle updates
    • Heartbeat every 30 seconds to detect stale connections

Implementation Details:

MQTT Topic Design:


fleet/
  us-west/
    vehicle-001/
      telemetry -> {speed, fuel, location, timestamp}
      status -> {engine, doors, battery, timestamp}
      alerts -> {type, severity, message, timestamp}
  us-east/
    vehicle-002/
      ...

Benefits:

  • Regional filtering: Dashboard can subscribe to specific regions
  • Message type separation: Different update frequencies (telemetry 1Hz, status 10s, alerts immediate)
  • Scalable: Add new regions/vehicles without restructuring

Node-RED Flow Configuration:

Key nodes:

  1. MQTT In: Subscribe to fleet/+/+/# (all messages)
  2. Function: Parse topic and extract vehicle_id, region, message_type
  3. Function: Transform to dashboard format
  4. Switch: Route based on message_type
  5. Function: Apply rate limiting per vehicle
  6. WebSocket Out: Send to subscribed clients

Rate limiting logic:

// Node-RED function node
var vehicle_id = msg.topic.split('/')[2];
var now = Date.now();
var lastSent = context.get(vehicle_id) || 0;
if (now - lastSent > 100) { // Max 10 msg/sec
    context.set(vehicle_id, now);
    return msg;
}
return null; // Drop message

WebSocket Connection Management:

  1. Load Balancing: NGINX with sticky sessions

    
    upstream node_red_cluster {
        ip_hash; // Sticky sessions
        server node-red-1:1880;
        server node-red-2:1880;
        server node-red-3:1880;
    }
    
  2. Subscription-Based Filtering: Reduce bandwidth

    • Dashboard sends: `{“subscribe”: [“vehicle-001”, “vehicle-002”]}
    • Node-RED stores subscription per connection
    • Only forwards messages for subscribed vehicles
    • Result: 90% reduction in WebSocket traffic
  3. Reconnection Handling: Ensure data continuity

    • Buffer last 100 messages per vehicle in Redis
    • Dashboard tracks last received timestamp
    • On reconnect, request: `{“catchup”: {“since”: 1234567890}}
    • Server sends buffered messages since timestamp
  4. Connection Health: Detect and clean up stale connections

    • Client sends heartbeat every 30 seconds
    • Server tracks last heartbeat timestamp
    • Close connections with no heartbeat for >90 seconds
    • Frees resources and prevents memory leaks

Performance Optimization:

  1. Message Batching: Reduce WebSocket overhead

    • Batch up to 10 messages or 100ms window
    • Send single WebSocket frame with array of updates
    • Reduces protocol overhead by 60-70%
  2. Compression: Enable WebSocket compression

    • Use permessage-deflate extension
    • Reduces bandwidth by 40-60% for JSON messages
    • Trade-off: Slight CPU increase for compression
  3. Selective Updates: Send only changed fields

    • Track previous state per vehicle
    • Send delta updates (only changed fields)
    • Reduces message size by 80% for status updates

Monitoring and Alerting:

Key metrics:

  • Active WebSocket connections (gauge)
  • MQTT messages received (counter)
  • WebSocket messages sent (counter)
  • Message latency (histogram): MQTT receive → WebSocket send
  • Connection churn rate (gauge): connects + disconnects per minute

Alert conditions:

  • WebSocket connections drop >20%: Indicates client issues or server problems
  • Message latency >500ms: Processing bottleneck or network issues
  • Connection churn >50/min: Network instability or client bugs
  • MQTT message rate drop >30%: Vehicle connectivity issues

Results:

This architecture delivers:

  • <1 second latency from vehicle to dashboard (99th percentile)
  • Supports 500+ vehicles and 100+ concurrent dashboard users
  • 99.9% message delivery reliability
  • Scales horizontally by adding Node-RED instances
  • Handles network disruptions gracefully with reconnection logic

Operational Benefits:

  • Dispatchers respond to vehicle issues 60x faster (1s vs. 60s)
  • Reduced fuel costs: Real-time route optimization based on traffic/conditions
  • Improved customer satisfaction: Accurate ETAs updated in real-time
  • Enhanced safety: Immediate alerts for vehicle malfunctions or accidents
  • Better resource utilization: Dynamic vehicle assignment based on real-time location

This real-time dashboard architecture has become the foundation for our fleet management platform, demonstrating the power of combining MQTT, Node-RED, and WebSockets for instant IoT data visualization.

We used hierarchical MQTT topics: fleet/{vehicle_id}/status for each vehicle. Node-RED subscribes to fleet/+/status (wildcard) to receive all vehicle updates. For WebSocket scaling, we deployed multiple Node-RED instances behind an NGINX load balancer with sticky sessions. Each instance handles 30-40 WebSocket connections. NGINX distributes new connections round-robin. This architecture scales to 200+ concurrent users without performance degradation.

Nice architecture! One optimization suggestion: implement message filtering in Node-RED so dashboards only receive relevant updates. If a dispatcher is viewing 10 specific vehicles, don’t send updates for all 500 vehicles. We implemented subscription-based filtering where the dashboard sends a list of vehicle IDs it’s interested in, and Node-RED only forwards matching messages. This reduces WebSocket bandwidth by 90% and improves dashboard responsiveness.

How do you handle WebSocket disconnections and reconnections? Network issues can cause frequent disconnects, and you need to ensure the dashboard doesn’t miss critical updates during reconnection. We implement a message queue on the server side that buffers the last 100 messages per vehicle. When a dashboard reconnects, it requests missed messages based on last received timestamp. This ensures data continuity even with unreliable connections.