WebSocket Protocol

Reference guide for connecting IoT devices and access control hardware.

Endpoint

ws://<your-host>/ws

All clients (devices and admin dashboards) connect to the same endpoint. The server differentiates roles based on the first message sent.

Client → Server Messages

register

// Device sends on connect to authenticate
{ "type": "register", "device_id": "<UUID>", "token": "tok_your_secret_token" }

telemetry

// Device pushes sensor readings
{ "type": "telemetry", "device_id": "<UUID>", "payload": { "temperature": 23.5, "humidity": 61 } }

event

// Device reports lifecycle events
{ "type": "event", "device_id": "<UUID>", "event_type": "door_opened", "payload": {} }

ping

// Heartbeat — server replies with { "type": "pong" }
{ "type": "ping" }

subscribe

// Admin dashboard joins broadcast group
{ "type": "subscribe", "role": "admin" }

command

// Admin sends a command to a device
{ "type": "command", "device_id": "<UUID>", "command": "unlock", "payload": {} }

Server → Client Messages

registeredSent to device after successful registration
pongHeartbeat reply to ping
device_statusBroadcast to admins when a device goes online/offline
telemetryBroadcast to admins when a device pushes telemetry
eventBroadcast to admins when a device emits an event
commandSent to device when an admin issues a command
errorSent when authentication fails or message is malformed

XML Protocol (Biometric / Access Control)

SmackBio/ZK-compatible biometric devices can connect using XML messages. The server auto-detects XML vs JSON.

register

<!-- Biometric device registers on connect -->
<Request>
  <Operation>Register</Operation>
  <DeviceSerialNo>FK628001</DeviceSerialNo>
  <CloudId>cloud_001</CloudId>
</Request>

<!-- Server responds with session token -->
<Response>
  <Result>success</Result>
  <Session>sess_1234567890_abc123</Session>
  <DeviceSerialNo>FK628001</DeviceSerialNo>
</Response>

timelog

<!-- Device sends attendance punch (TimeLog_v2) -->
<Request>
  <Operation>TimeLog_v2</Operation>
  <LogId>LOG001</LogId>
  <UserId>EMP123</UserId>
  <PunchTime>2026-05-12T09:15:30</PunchTime>
  <GMT>8</GMT>
  <AttendStat>0</AttendStat>
  <APStat>1</APStat>
  <Action>FP</Action>
  <JobCode>0</JobCode>
  <Photo>base64_encoded_photo...</Photo>
  <Latitude>40.7128</Latitude>
  <Longitude>-74.0060</Longitude>
</Request>

adminlog

<!-- Device sends admin action (AdminLog_v2) -->
<Request>
  <Operation>AdminLog_v2</Operation>
  <LogId>ADMIN001</LogId>
  <AdminId>ADMIN</AdminId>
  <UserId>EMP456</UserId>
  <Action>EnrollFP</Action>
  <Time>2026-05-12T10:30:00</Time>
</Request>

keepalive

<!-- Heartbeat to keep connection alive -->
<Request>
  <Operation>KeepAlive</Operation>
</Request>

HTTP/HTTPS Protocol (CloudSolution 3.0)

Devices that don't support WebSocket (legacy networks, HTTP-only firmware) can use HTTP POST requests. Every request gets a JSON response. Use checklive as a heartbeat.

Endpoint

POST https://<your-host>/api/device-http

register

// CloudSolution Protocol 3.0 — HTTP Device Registration
POST /api/device-http
Content-Type: application/json

{
  "cmd": "reg",
  "sn": "ZX12345678",
  "cpusn": "123456789",
  "devinfo": {
    "modelname": "tfs30",
    "usersize": 3000,
    "fpsize": 3000,
    "firmware": "th600wv6.1",
    "mac": "00-01-A9-01-00-01"
  }
}

Response:
{
  "ret": "reg",
  "result": true,
  "cloudtime": "2026-06-12T10:30:00Z",
  "nosenduser": true
}

sendlog

// CloudSolution Protocol 3.0 — Send Attendance Logs
POST /api/device-http
Content-Type: application/json

{
  "cmd": "sendlog",
  "sn": "ZX12345678",
  "count": 2,
  "logindex": 10,
  "record": [
    {
      "enrollid": 1,
      "time": "2026-06-12T09:15:30",
      "mode": 1,
      "inout": 0,
      "event": 0,
      "temp": 36.5,
      "image": "base64_encoded_photo"
    },
    {
      "enrollid": 2,
      "time": "2026-06-12T09:20:15",
      "mode": 0,
      "inout": 1,
      "event": 0,
      "temp": 36.8
    }
  ]
}

Response:
{
  "ret": "sendlog",
  "result": true,
  "count": 2,
  "cloudtime": "2026-06-12T09:25:00Z",
  "access": 1
}

checklive

// CloudSolution Protocol 3.0 — Heartbeat (HTTP Only)
POST /api/device-http
Content-Type: application/json

{
  "cmd": "checklive",
  "sn": "ZX12345678",
  "time": "2026-06-12T09:30:00"
}

Response:
{
  "ret": "checklive",
  "result": true,
  "cloudtime": "2026-06-12T09:30:15Z"
}

Example: Python Device

import requests
import json
import time

HOST = "https://your-host"
SN = "ZX12345678"  # Device serial number
TOKEN = "your-token"

def register():
    """Register the device on startup"""
    payload = {
        "cmd": "reg",
        "sn": SN,
        "cpusn": "123456789",
        "devinfo": {
            "modelname": "device-1",
            "usersize": 1000,
            "firmware": "v1.0.0",
            "mac": "00:11:22:33:44:55"
        }
    }
    resp = requests.post(f"{HOST}/api/device-http", json=payload)
    print("Register:", resp.json())

def send_logs(records):
    """Send attendance logs"""
    payload = {
        "cmd": "sendlog",
        "sn": SN,
        "count": len(records),
        "logindex": 0,
        "record": records
    }
    resp = requests.post(f"{HOST}/api/device-http", json=payload)
    print("SendLog:", resp.json())

def heartbeat():
    """Send heartbeat every 60 seconds"""
    payload = {
        "cmd": "checklive",
        "sn": SN,
        "time": time.strftime("%Y-%m-%dT%H:%M:%S")
    }
    resp = requests.post(f"{HOST}/api/device-http", json=payload)
    print("Heartbeat:", resp.json())

# Usage
if __name__ == "__main__":
    register()
    time.sleep(1)
    
    # Send some logs
    send_logs([{
        "enrollid": 1,
        "time": "2026-06-12T09:15:00",
        "mode": 1,  # Fingerprint
        "inout": 0,  # In
        "event": 0
    }])
    
    # Heartbeat every minute
    while True:
        time.sleep(60)
        heartbeat()

Example Device (Node.js / JSON)

import WebSocket from "ws"

let ws
let retries = 0

function connect() {
  ws = new WebSocket("ws://your-host/ws")

  ws.on("open", () => {
    retries = 0
    // Authenticate
    ws.send(JSON.stringify({
      type: "register",
      device_id: process.env.DEVICE_ID,
      token: process.env.DEVICE_TOKEN,
    }))
  })

  ws.on("message", (data) => {
    const msg = JSON.parse(data)
    if (msg.type === "command") {
      console.log("Received command:", msg.command)
      // Execute command …
    }
    if (msg.type === "ping") {
      ws.send(JSON.stringify({ type: "pong" }))
    }
  })

  ws.on("close", () => {
    // Exponential backoff reconnect
    const delay = Math.min(1000 * 2 ** retries, 30000)
    retries++
    setTimeout(connect, delay)
  })
}

connect()

// Send telemetry every 5 seconds
setInterval(() => {
  if (ws?.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify({
      type: "telemetry",
      device_id: process.env.DEVICE_ID,
      payload: { temperature: readTemp(), humidity: readHumidity() },
    }))
  }
}, 5000)

Dashboard WebSocket

disconnected