Skip to main content

๐ŸŒ WebSocket Integration

The DEJA.js server exposes a WebSocket interface for real-time bidirectional communication. This is the same protocol used by the Monitor, Throttle, and Cloud apps โ€” so your custom scripts get the same live data stream as the official DEJA.js frontends.

Use WebSocket integration when you want to:

  • ๐Ÿ–ฅ๏ธ Build custom dashboards or control panels
  • ๐Ÿ“Š Log DCC commands and device data to a file or database
  • ๐Ÿค– Write automation scripts that react to layout events in real time
  • ๐Ÿ”Œ Bridge DEJA.js with other home automation or IoT platforms

๐Ÿ”— Connection

Connect to the DEJA.js WebSocket server at:

ws://host:8082
ParameterDefaultEnv Variable
Hostlocalhostโ€”
Port8082VITE_WS_PORT

If the server is behind a Cloudflare Tunnel or served over HTTPS, use wss:// instead:

wss://your-tunnel.example.com

๐Ÿ’ก The WebSocket server must be enabled on the DEJA server with ENABLE_WS=true (this is the default).


๐Ÿค Connection Handshake

When you connect, the server sends two messages automatically โ€” no request needed:

1๏ธโƒฃ ack โ€” Connection Acknowledgment

Sent immediately on connect. Confirms the server identity and which layout it's managing.

{
  "action": "ack",
  "payload": {
    "layoutId": "tamarack",
    "serverId": "DEJA.js"
  }
}

2๏ธโƒฃ wsconnected โ€” Client Identification

Sent right after ack. Contains your client's IP address as seen by the server.

{
  "action": "wsconnected",
  "payload": {
    "ip": "192.168.1.42",
    "serverId": "DEJA.js"
  }
}

Once you receive both messages, the connection is fully established and you can send commands or listen for broadcasts.


๐Ÿ“ค Sending Commands

Send JSON messages to the server with an action and payload:

{
  "action": "string",
  "payload": {}
}

Common Client-to-Server Actions

ActionPayloadDescription
listPorts{}Request a list of available serial ports
getStatus{}Request current server status
ping{}Ping the server (returns status)
subscribe-device{ "deviceId": "device-name" }Subscribe to serial data for a specific device
unsubscribe-device{ "deviceId": "device-name" }Unsubscribe from a device's serial data

๐Ÿ“ฅ Broadcast Messages from Server

These messages are broadcast to all connected WebSocket clients:

dcc โ€” DCC Command Log

Every DCC-EX command sent to the serial port is broadcast. Great for building a live command monitor.

{
  "action": "dcc",
  "payload": "t 3 50 1"
}

connected โ€” Serial Port Connected

Broadcast when the server establishes a serial connection to a DCC-EX CommandStation.

{
  "action": "connected",
  "payload": {
    "baudRate": 115200,
    "device": "CommandStation",
    "path": "/dev/tty.usbmodem1101"
  }
}

portList โ€” Available Serial Ports

Broadcast in response to a listPorts command.

{
  "action": "portList",
  "payload": [
    "/dev/tty.usbmodem1101",
    "/dev/tty.usbserial-110"
  ]
}

status โ€” Server Status

Broadcast in response to getStatus, status, or ping.

{
  "action": "status",
  "payload": {
    "client": "dejaJS",
    "isConnected": true
  }
}

serial-data โ€” Device Serial I/O

Sent only to clients subscribed to a specific device (see below).

{
  "action": "serial-data",
  "payload": {
    "deviceId": "tj-eagle-nest-pico",
    "data": "<p1>",
    "timestamp": "2025-01-15T14:30:22.123Z",
    "direction": "incoming"
  }
}

The direction field is either "incoming" (device โ†’ server) or "outgoing" (server โ†’ device).


๐Ÿ” Device Serial Monitoring

You can subscribe to a specific hardware device's serial I/O stream. This is useful for debugging, logging, or building device-specific dashboards.

Subscribe to a Device

{
  "action": "subscribe-device",
  "deviceId": "tj-eagle-nest-pico"
}

โœ… Server response:

{
  "action": "device-subscribed",
  "payload": {
    "deviceId": "tj-eagle-nest-pico",
    "success": true
  }
}

Unsubscribe from a Device

{
  "action": "unsubscribe-device",
  "deviceId": "tj-eagle-nest-pico"
}

โœ… Server response:

{
  "action": "device-unsubscribed",
  "payload": {
    "deviceId": "tj-eagle-nest-pico",
    "success": true
  }
}

๐Ÿ’ก You can subscribe to multiple devices simultaneously. When you disconnect, the server automatically cleans up all your subscriptions.


๐Ÿš€ Example: JavaScript WebSocket Client

Here's a complete example that connects to the DEJA server, listens for DCC commands, and subscribes to a device's serial stream.

Browser

const ws = new WebSocket('ws://localhost:8082')

ws.onopen = () => {
  console.log('๐Ÿ”— Connected to DEJA server')

  // Subscribe to a device's serial data
  ws.send(JSON.stringify({
    action: 'subscribe-device',
    deviceId: 'tj-thunder-city-pico'
  }))
}

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data)

  switch (msg.action) {
    case 'ack':
      console.log(`๐Ÿค Server ack โ€” layout: ${msg.payload.layoutId}`)
      break

    case 'wsconnected':
      console.log(`๐ŸŒ Connected as ${msg.payload.ip}`)
      break

    case 'dcc':
      console.log(`๐Ÿš‚ DCC command: ${msg.payload}`)
      break

    case 'device-subscribed':
      console.log(`๐Ÿ“ก Subscribed to ${msg.payload.deviceId}`)
      break

    case 'serial-data':
      const { deviceId, data, direction } = msg.payload
      const arrow = direction === 'incoming' ? 'โฌ…๏ธ' : 'โžก๏ธ'
      console.log(`${arrow} ${deviceId}: ${data}`)
      break

    case 'connected':
      console.log(`๐Ÿ”Œ Serial connected: ${msg.payload.path}`)
      break

    case 'status':
      console.log(`๐Ÿ“Š Status: connected=${msg.payload.isConnected}`)
      break

    default:
      console.log(`๐Ÿ“จ ${msg.action}:`, msg.payload)
  }
}

ws.onclose = () => console.log('โŒ Disconnected from DEJA server')
ws.onerror = (err) => console.error('โš ๏ธ WebSocket error:', err)

Node.js

npm install ws
import { WebSocket } from 'ws'

const ws = new WebSocket('ws://localhost:8082')

ws.on('open', () => {
  console.log('๐Ÿ”— Connected to DEJA server')

  // Request server status
  ws.send(JSON.stringify({ action: 'getStatus', payload: {} }))

  // Subscribe to a device
  ws.send(JSON.stringify({
    action: 'subscribe-device',
    deviceId: 'tj-eagle-nest-pico'
  }))
})

ws.on('message', (raw) => {
  const msg = JSON.parse(raw.toString())
  console.log(`[${msg.action}]`, JSON.stringify(msg.payload))
})

ws.on('close', () => console.log('Disconnected'))
ws.on('error', (err) => console.error('Error:', err.message))

๐Ÿงช Testing Your Integration

  1. Start the DEJA server โ€” Make sure ENABLE_WS=true (default)
  2. Open a WebSocket connection โ€” Use the examples above or a tool like websocat:
    websocat ws://localhost:8082
    
  3. Watch the handshake โ€” You should immediately see ack and wsconnected messages
  4. Send a ping โ€” Type {"action":"ping","payload":{}} and confirm you get a status response
  5. Subscribe to a device โ€” Send a subscribe-device message and watch for serial-data events

๐Ÿ“š Next Steps