DTS Client Integration API

2026-08-23 08:44:30

Keywords: DTS

This document is for third-party client developers integrating with the DTS device service. It describes HTTP REST and WebSocket usage, request/response parameters, and field meanings.


1. Connection Overview

Item Description
Base URL http://<host>:8088
WebSocket ws://<host>:8088/ws/stream
Data format JSON (UTF-8) for requests and responses
Content-Type Use application/json for POST requests
Authentication See below; OPTIONS preflight does not require a token

Replace <host> with the device IP address. The default port is 8088 (use the actual port if the device is configured differently).

1.1 Authentication

All HTTP and WebSocket requests must include an API token (confirm the value with the device administrator; the default is often glgyzn-dts-token).

Method Example
Authorization header (recommended) Authorization: Bearer glgyzn-dts-token
Custom header X-DTS-Token: glgyzn-dts-token
WebSocket query parameter ws://<host>:8088/ws/stream?token=glgyzn-dts-token

Authentication failure returns 401:

{"ok": false, "error": "unauthorized"}

1.2 Common Responses

Success (HTTP 200) — most POST endpoints:

{"ok": true, "message": "Description text"}

Failure — two common formats:

{"ok": false, "error": "Error description"}
{"ok": false, "message": "Error description"}

Some GET endpoints return business JSON directly without an ok field.

1.3 Recommended Call Sequence

1. GET  /api/v1/health
2. POST /api/v1/connect
3. GET  /api/v1/status
4. GET  /api/v1/config              (optional)
5. POST /api/v1/config              (optional)
6. WebSocket /ws/stream             (subscribe to live data)
7. POST /api/v1/acquisition/start
8. Receive WebSocket frame / alarm messages
9. POST /api/v1/acquisition/stop    (when needed)

Notes:

  • Closing the WebSocket on the client does not stop acquisition; call acquisition/stop explicitly.
  • Multiple clients may connect at the same time without interfering with each other.
  • Calling POST /connect when already connected still returns success and the current version.
  • Calling POST /acquisition/start while acquisition is already running still returns success.

2. Endpoint Summary

Method Path Description
GET /api/v1/health Health check
GET /api/v1/status Connection and acquisition status
POST /api/v1/connect Connect to device
POST /api/v1/disconnect Disconnect from device
GET /api/v1/config Read configuration
POST /api/v1/config Update configuration
POST /api/v1/reload-config Reload configuration
POST /api/v1/acquisition/start Start acquisition
POST /api/v1/acquisition/stop Stop acquisition
GET /api/v1/optical-switch Query optical switch
POST /api/v1/optical-switch Enable/disable optical switch
GET /api/v1/light-source Read laser source parameters
POST /api/v1/light-source Set laser source parameters
GET /api/v1/alarms Read alarm configuration and status
POST /api/v1/alarms Save alarm configuration
POST /api/v1/alarms/acknowledge Acknowledge alarm clearance
POST /api/v1/alarms/mute Mute alarm buzzer
GET /api/v1/relay-linkage Read relay linkage configuration
POST /api/v1/relay-linkage Save relay linkage configuration
GET /api/v1/network/ip Query host IP address
POST /api/v1/network/ip Change host IP address

3. Endpoint Reference

In the examples below:

  • HOST = device IP, e.g. 192.168.68.4
  • TOKEN = API token, e.g. glgyzn-dts-token

GET /api/v1/health

Check whether the service is online.

Request: no body

Response:

{"ok": true}

curl:

curl -s "http://HOST:8088/api/v1/health" \
  -H "Authorization: Bearer TOKEN"

GET /api/v1/status

Query device connection status and acquisition parameters.

Response:

{
  "connected": true,
  "reading": false,
  "version": "V1.2.3.5",
  "samplePoints": 16384,
  "avgCount": 30000
}
Field Type Description
connected bool Whether the acquisition card is connected
reading bool Whether acquisition is in progress
version string Acquisition card firmware version
samplePoints number Current number of sample points
avgCount number Current averaging count

curl:

curl -s "http://HOST:8088/api/v1/status" \
  -H "Authorization: Bearer TOKEN"

POST /api/v1/connect

Connect to the acquisition card and peripherals (laser source, optical switch, etc.). The first connection may take a long time; set the HTTP timeout to 60–90 seconds.

Request body: empty object {} or no body

Response:

{
  "ok": true,
  "message": "Connected, version: V1.2.3.5"
}
Field Description
ok Whether the operation succeeded
message Result description; on failure, contains the reason; peripheral failures may still return ok=true with details in message

curl:

curl -s -X POST "http://HOST:8088/api/v1/connect" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d "{}"

POST /api/v1/disconnect

Stop acquisition and disconnect from the device.

Request body:

{}

Response:

{"ok": true}

curl:

curl -s -X POST "http://HOST:8088/api/v1/disconnect" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d "{}"

POST /api/v1/acquisition/start

Start temperature acquisition. Data is pushed over WebSocket.

Prerequisites: connect succeeded, and both samplePoints and avgCount are greater than 0.

Request body:

{
  "samplePoints": 16384,
  "avgCount": 30000
}
Field Type Required Description
samplePoints number No Number of sample points; omit to use current value
avgCount number No Averaging count; omit to use current value

Response:

{
  "ok": true,
  "message": "Acquisition started"
}

curl:

curl -s -X POST "http://HOST:8088/api/v1/acquisition/start" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"samplePoints":16384,"avgCount":30000}'

POST /api/v1/acquisition/stop

Stop acquisition.

Request body:

{}

Response:

{"ok": true}

curl:

curl -s -X POST "http://HOST:8088/api/v1/acquisition/stop" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d "{}"

GET /api/v1/config

Read the current configuration.

Response example:

{
  "samplePoints": 16384,
  "avgCount": 30000,
  "refTemp": 34.3,
  "meterPerPoint": 0.4,
  "attenEnabled": true,
  "attenuations": [
    {"channel": 1, "segStart": 0, "segEnd": 1000, "alphaDiff": 0.001, "offsetK": 0.0}
  ],
  "calibrations": [
    {"channel": 1, "position": 100, "sensitivity": 0.4, "compTemp": 25.0}
  ],
  "channels": [
    {
      "channel": 1,
      "startPos": 0,
      "endPos": 5920,
      "zeroMeter": 0,
      "measureOffsetM": 0.0,
      "meterPerPoint": 0.4,
      "refTemp": 34.3,
      "enabled": true,
      "alias": "Channel 1"
    }
  ],
  "lightSource": {
    "mode": 1,
    "laserOn": 1,
    "current": 40000,
    "power": 2500,
    "pulseWidth": 10,
    "frequency": 10
  },
  "opticalSwitch": {"enabled": true},
  "forwardTempEnabled": false,
  "forwardTempUrl": "http://127.0.0.1:8080/api/temperature"
}

See Section 5 — Configuration Fields for field definitions.


POST /api/v1/config

Update configuration. Partial updates are supported (send only the fields you want to change).

Notes:

  • Does not write laser source parameters to hardware; use POST /api/v1/light-source for that.
  • While acquisition is running, samplePoints and avgCount cannot be hot-updated; stop acquisition first.

Request body example (channels and calibration):

{
  "refTemp": 34.3,
  "meterPerPoint": 0.4,
  "channels": [
    {
      "channel": 1,
      "startPos": 0,
      "endPos": 5920,
      "zeroMeter": 0,
      "measureOffsetM": 0.0,
      "meterPerPoint": 0.4,
      "refTemp": 34.3,
      "enabled": true,
      "alias": "Channel 1"
    }
  ],
  "calibrations": [
    {"channel": 1, "position": 100, "sensitivity": 0.4, "compTemp": 25.0}
  ]
}

Response:

{"ok": true, "message": "Configuration saved"}

curl:

curl -s -X POST "http://HOST:8088/api/v1/config" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"samplePoints":16384,"avgCount":30000,"refTemp":34.3}'

POST /api/v1/reload-config

Reload configuration from the device.

Request body:

{}

Response:

{"ok": true, "message": "Configuration loaded"}

curl:

curl -s -X POST "http://HOST:8088/api/v1/reload-config" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d "{}"

GET /api/v1/optical-switch

Query optical switch status.

Response:

{
  "ok": true,
  "enabled": true,
  "connected": true,
  "serialPort": "/dev/ttyS1",
  "baudRate": 9600,
  "currentChannel": 2,
  "channelValid": true
}
Field Description
enabled Whether multi-channel optical switch mode is enabled
connected Whether the serial port is connected
currentChannel Current channel number (0 = unknown)
channelValid Whether currentChannel is valid

POST /api/v1/optical-switch

Enable or disable the optical switch.

Request body:

{
  "enabled": true
}
Field Type Required Description
enabled bool Yes true = enable, false = disable

Response:

{
  "ok": true,
  "enabled": true,
  "connected": true,
  "currentChannel": 1,
  "channelValid": true,
  "message": "Optical switch enabled"
}

curl:

curl -s -X POST "http://HOST:8088/api/v1/optical-switch" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true}'

GET /api/v1/light-source

Read current laser source parameters.

Response:

{
  "ok": true,
  "connected": true,
  "dataValid": true,
  "laserOn": 1,
  "mode": 1,
  "current": 40000,
  "power": 2500,
  "pulseWidth": 10,
  "frequency": 10,
  "readCurrent": 39500,
  "readPower": 2480,
  "moduleTemp": 34.5
}
Field Description
laserOn 0 = off, 1 = on
mode 0 = ACC, 1 = APC
current Set current
power Set power
pulseWidth Pulse width (ns)
frequency Frequency (kHz)
readCurrent / readPower / moduleTemp Read-back values (may be absent when dataValid=false)
dataValid Whether live hardware read-back succeeded

POST /api/v1/light-source

Write laser source parameters to hardware.

Request body:

{
  "laserOn": 1,
  "mode": 1,
  "current": 40000,
  "power": 2500,
  "pulseWidth": 10,
  "frequency": 10
}
Field Type Required Description
laserOn int No 0 = off, 1 = on
mode int No 0 = ACC, 1 = APC
current int No Set current
power int No Set power
pulseWidth int No Pulse width (ns)
frequency int No Frequency (kHz)

Response:

{
  "ok": true,
  "message": "Laser source parameters written",
  "connected": true,
  "dataValid": true,
  "laserOn": 1,
  "mode": 1,
  "current": 40000,
  "power": 2500,
  "pulseWidth": 10,
  "frequency": 10,
  "readCurrent": 39500,
  "readPower": 2480,
  "moduleTemp": 34.5
}

curl:

curl -s -X POST "http://HOST:8088/api/v1/light-source" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"laserOn":1,"mode":1,"current":40000,"power":2500,"pulseWidth":10,"frequency":10}'

GET /api/v1/alarms

Read temperature alarm configuration and current alarm state.

Response:

{
  "ok": true,
  "enabled": true,
  "channels": [
    {"channel": 1, "enabled": true},
    {"channel": 2, "enabled": false}
  ],
  "partitions": [
    {
      "channel": 1,
      "partitionId": 1,
      "name": "Zone A",
      "startM": 150.0,
      "endM": 4000.0,
      "fixedTempEnabled": true,
      "fixedTempThreshold": 60.0,
      "diffTempEnabled": true,
      "diffTempThreshold": 10.0,
      "diffTempInterval": 3
    }
  ],
  "state": {"active": false}
}
Field Description
enabled Global alarm enable flag
channels[] Per-channel alarm enable flags
partitions[] Alarm zones; see 5.2 partitions[]
state.active Whether an alarm is currently active

POST /api/v1/alarms

Save alarm configuration. Partial updates are supported. The state field is ignored.

Request body example:

{
  "enabled": true,
  "channels": [
    {"channel": 1, "enabled": true}
  ],
  "partitions": [
    {
      "channel": 1,
      "partitionId": 1,
      "name": "Zone A",
      "startM": 150.0,
      "endM": 4000.0,
      "fixedTempEnabled": true,
      "fixedTempThreshold": 60.0,
      "diffTempEnabled": true,
      "diffTempThreshold": 10.0,
      "diffTempInterval": 3
    }
  ]
}

Response:

{"ok": true, "message": "Alarm configuration saved"}

curl:

curl -s -X POST "http://HOST:8088/api/v1/alarms" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true,"partitions":[{"channel":1,"partitionId":1,"name":"Zone A","startM":150,"endM":4000,"fixedTempEnabled":true,"fixedTempThreshold":60,"diffTempEnabled":false,"diffTempThreshold":10,"diffTempInterval":3}]}'

POST /api/v1/alarms/acknowledge

Acknowledge alarm clearance and reset alarm state. WebSocket clients receive a broadcast with active: false.

Request body:

{}

Response:

{"ok": true, "message": "Alarm cleared"}

curl:

curl -s -X POST "http://HOST:8088/api/v1/alarms/acknowledge" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d "{}"

POST /api/v1/alarms/mute

Mute the alarm buzzer. Alarm state remains unchanged.

Request body:

{}

Response:

{"ok": true, "message": "Alarm muted"}

curl:

curl -s -X POST "http://HOST:8088/api/v1/alarms/mute" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d "{}"

GET /api/v1/relay-linkage

Read relay linkage configuration.

Response:

{
  "ok": true,
  "enabled": true,
  "serialPort": "/dev/ttyS0",
  "baudRate": 115200,
  "connected": true,
  "states": [0, 1, 0, 0, 0, 0, 0, 0],
  "rules": [
    {
      "relay": 1,
      "alarmType": "Fire",
      "channel": 1,
      "startM": 0.0,
      "endM": 4000.0
    }
  ]
}
Field Description
enabled Whether relay linkage is enabled
connected Whether the relay board is connected
states 8 relay states: 0 = off, 1 = on, -1 = unknown
rules[] Linkage rule list
rules[].relay Relay number 1–8
rules[].alarmType Alarm type label
rules[].channel Fiber channel number
rules[].startM / endM Valid distance range (m)

POST /api/v1/relay-linkage

Save relay linkage configuration. Do not send the connected field.

Request body example:

{
  "enabled": true,
  "rules": [
    {
      "relay": 1,
      "alarmType": "Fire",
      "channel": 1,
      "startM": 0.0,
      "endM": 4000.0
    }
  ]
}

Response:

{"ok": true, "message": "Relay configuration saved"}

curl:

curl -s -X POST "http://HOST:8088/api/v1/relay-linkage" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true,"rules":[{"relay":1,"alarmType":"Fire","channel":1,"startM":0,"endM":4000}]}'

GET /api/v1/network/ip

Query the device host IP address.

Response:

{
  "ok": true,
  "interface": "enp2s0",
  "address": "192.168.68.4/24",
  "gateway": "",
  "available": true
}
Field Description
interface Network interface name
address IPv4 address in CIDR notation
gateway Default gateway (may be empty)
available Whether the address was read successfully

POST /api/v1/network/ip

Change the device host IP address. The HTTP response returns immediately; the network may be interrupted briefly. Reconnect using the new IP.

Request body:

{
  "address": "192.168.68.4/24",
  "gateway": "192.168.68.1"
}
Field Type Required Description
address string Yes CIDR notation, e.g. 192.168.68.4/24
gateway string No Default gateway; omit to leave unset

Response:

{
  "ok": true,
  "message": "Network configuration saved..."
}

curl:

curl -s -X POST "http://HOST:8088/api/v1/network/ip" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"address":"192.168.68.4/24","gateway":"192.168.68.1"}'

4. WebSocket Live Data

4.1 Connection

ws://HOST:8088/ws/stream?token=TOKEN

Or include in the handshake header: Authorization: Bearer TOKEN

4.2 Temperature frame (type = "frame")

Pushed after acquisition/start succeeds and a sample completes:

{
  "type": "frame",
  "channel": 1,
  "channelIndex": 0,
  "timestamp": "2026-08-20T08:30:15",
  "startPos": 0,
  "meterPerPoint": 0.4,
  "fiberLengthM": 5181.2,
  "temperature": [34.1, 34.2],
  "asCurve": [120.5, 118.3],
  "rawA": [1000, 1002],
  "rawB": [800, 798]
}
Field Description
channel Channel number
channelIndex Index in the channels configuration array
timestamp Sample time (ISO8601, no milliseconds)
startPos Curve start point index
meterPerPoint Meters per point
fiberLengthM Detected fiber length (m); -1 on failure
temperature Temperature array (°C)
asCurve AS curve
rawA / rawB Stokes / Anti-Stokes raw curves

Distance calculation:

distanceM = (startPos + i - zeroMeter) * meterPerPoint

zeroMeter and meterPerPoint come from the channel entry in channels[].

4.3 Alarm message (type = "alarm")

Alarm triggered:

{
  "type": "alarm",
  "active": true,
  "hits": [
    {
      "channel": 1,
      "partitionId": 1,
      "name": "Zone A",
      "distanceM": 320.5,
      "temperature": 62.3,
      "fixedTemp": true,
      "threshold": 60.0
    }
  ]
}

Alarm cleared:

{
  "type": "alarm",
  "active": false,
  "hits": []
}
Field Description
active Whether an alarm is active
hits[].channel Channel number
hits[].partitionId Zone ID
hits[].name Zone name
hits[].distanceM Alarm location (m)
hits[].temperature Current temperature (°C)
hits[].fixedTemp true = fixed-temperature alarm, false = differential alarm
hits[].threshold Trigger threshold (°C)

When the client receives active: true, update the UI; after user confirmation, call POST /api/v1/alarms/acknowledge.


5. Configuration Fields

5.1 channels[] — fiber channels

Field Type Description
channel int Channel number
startPos int Calculation start point index
endPos int Calculation end point index (0 = to end)
zeroMeter int Point index corresponding to 0 m
measureOffsetM number Armoring start offset (m)
meterPerPoint number Meters per point
refTemp number Reference temperature (°C)
enabled bool Whether the channel participates in multi-channel polling
alias string Channel display name

5.2 partitions[] — alarm zones

Field Type Description
channel int Channel number
partitionId int Zone ID
name string Zone name
startM / endM number Alarm range (m)
fixedTempEnabled bool Enable fixed-temperature alarm
fixedTempThreshold number Fixed-temperature threshold (°C)
diffTempEnabled bool Enable differential-temperature alarm
diffTempThreshold number Differential threshold (°C)
diffTempInterval int Differential comparison interval (consecutive samples)

5.3 Other configuration fields

Field Description
samplePoints Number of sample points
avgCount Averaging count
refTemp Global reference temperature (°C)
meterPerPoint Global meters per point
attenEnabled Enable attenuation compensation
attenuations[] Attenuation segments: channel, segStart, segEnd, alphaDiff, offsetK
calibrations[] Calibration points: channel, position, sensitivity, compTemp
forwardTempEnabled Forward temperature data to a third-party URL
forwardTempUrl Forward destination URL

6. Integration Examples

6.1 Full curl workflow

HOST="192.168.68.4"
TOKEN="glgyzn-dts-token"

# 1. Health check
curl -s "http://${HOST}:8088/api/v1/health" -H "Authorization: Bearer ${TOKEN}"

# 2. Connect
curl -s -X POST "http://${HOST}:8088/api/v1/connect" \
  -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -d "{}"

# 3. Query status
curl -s "http://${HOST}:8088/api/v1/status" -H "Authorization: Bearer ${TOKEN}"

# 4. Start acquisition
curl -s -X POST "http://${HOST}:8088/api/v1/acquisition/start" \
  -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" \
  -d '{"samplePoints":16384,"avgCount":30000}'

6.2 JavaScript WebSocket

const host = "192.168.68.4";
const token = "glgyzn-dts-token";
const ws = new WebSocket(`ws://${host}:8088/ws/stream?token=${encodeURIComponent(token)}`);

ws.onmessage = (ev) => {
  const msg = JSON.parse(ev.data);
  if (msg.type === "frame") {
    console.log(`Channel ${msg.channel}, temperature points: ${msg.temperature.length}`);
  } else if (msg.type === "alarm") {
    console.log(`Alarm active=${msg.active}`, msg.hits);
  }
};

6.3 Python — read configuration

import json, urllib.request

host, token = "192.168.68.4", "glgyzn-dts-token"
req = urllib.request.Request(
    f"http://{host}:8088/api/v1/config",
    headers={"Authorization": f"Bearer {token}"},
)
with urllib.request.urlopen(req) as r:
    cfg = json.load(r)
print(cfg["samplePoints"], cfg["channels"])

7. FAQ

Issue Explanation
401 unauthorized Invalid or missing token
connect timeout First connection is slow; increase HTTP timeout (60–90 s recommended)
404 not found Wrong path or HTTP method
Cannot connect after IP change Reconnect using the new IP address
reading still true after stop acquisition/stop is asynchronous; poll GET /status until reading=false

Document version: 2026-08-23

Related Content