2026-08-23 08:44:30
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.
| 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).
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"}
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. 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:
acquisition/stop explicitly.POST /connect when already connected still returns success and the current version.POST /acquisition/start while acquisition is already running still returns success.| 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 |
In the examples below:
HOST = device IP, e.g. 192.168.68.4TOKEN = API token, e.g. glgyzn-dts-token/api/v1/healthCheck whether the service is online.
Request: no body
Response:
{"ok": true}
curl:
curl -s "http://HOST:8088/api/v1/health" \
-H "Authorization: Bearer TOKEN"
/api/v1/statusQuery 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"
/api/v1/connectConnect 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 "{}"
/api/v1/disconnectStop 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 "{}"
/api/v1/acquisition/startStart 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}'
/api/v1/acquisition/stopStop 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 "{}"
/api/v1/configRead 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.
/api/v1/configUpdate configuration. Partial updates are supported (send only the fields you want to change).
Notes:
POST /api/v1/light-source for that.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}'
/api/v1/reload-configReload 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 "{}"
/api/v1/optical-switchQuery 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 |
/api/v1/optical-switchEnable 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}'
/api/v1/light-sourceRead 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 |
/api/v1/light-sourceWrite 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}'
/api/v1/alarmsRead 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 |
/api/v1/alarmsSave 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}]}'
/api/v1/alarms/acknowledgeAcknowledge 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 "{}"
/api/v1/alarms/muteMute 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 "{}"
/api/v1/relay-linkageRead 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) |
/api/v1/relay-linkageSave 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}]}'
/api/v1/network/ipQuery 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 |
/api/v1/network/ipChange 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"}'
ws://HOST:8088/ws/stream?token=TOKEN
Or include in the handshake header: Authorization: Bearer TOKEN
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[].
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.
| 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 |
| 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) |
| 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 |
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}'
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);
}
};
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"])
| 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