1. Overview
The Acrel DTSD1352 is a three-phase rail-mount multifunction energy meter with RS-485 Modbus RTU output. It measures three-phase voltage, current, active/reactive/apparent power, power factor, frequency, per-phase energy, voltage/current unbalance, zero-sequence current, and DIDO status — 37 electrical parameters in total. Active energy accuracy is Class 0.5S (IEC 62053-22), meeting both trade settlement and industrial metering requirements.
This integration connects the DTSD1352 to ThinkLink via a KC11 LoRaWAN collector over RS-485. The KC11's built-in EdgeBus script handles Modbus RTU polling, data framing, and LoRaWAN uplink, delivering three-phase power data from distribution panels wirelessly to ThinkLink.
Business code: 23112. Template name: DTSD1352.
2. Features
- Reads all 37 electrical parameters from DTSD1352 — voltage, current, power, power factor, energy, frequency, unbalance, and DIDO status
- Connects via RS-485 / Modbus RTU
- KC11 provides wireless LoRaWAN uplink without modifying distribution panel wiring
- Active energy accuracy Class 0.5S (IEC 62053-22); reactive energy Class 2 — suitable for trade settlement
- DIN-rail mounting (7-module DIN, 126×91×74 mm), fits standard distribution enclosures
- Remote CT/PT ratio write via transparent Modbus FC=10 — supports high-voltage/high-current transformer wiring
- Remote configuration of Modbus slave address and collection/upload period — supports multi-meter RS-485 bus
- Class C always-on mode via KC11 (AC mains powered); minimum collection interval 1 second
- Built-in voltage-loss/overvoltage/phase-sequence fault detection; DIDO status readable remotely
3. Use Cases
This integration is suited for any scenario that requires connecting DTSD1352 to ThinkLink or a LoRaWAN network:
- Three-phase power monitoring in industrial plant distribution panels with zonal energy sub-metering
- Remote meter reading in commercial building distribution rooms, replacing manual inspection
- Enterprise energy management and power quality analysis (unbalance, power factor, zero-sequence current)
- Multi-floor / multi-circuit metering with multiple meters on a single RS-485 bus
- Bidirectional metering for sites with distributed solar (four-quadrant active and reactive energy)
- Wireless retrofit of existing power meters without changing original wiring
- MQTT data feed to PLC / SCADA / energy management systems
4. Collector Information
4.1 Hardware
| Item | Details |
|---|---|
| Collector model | KC11 |
| Communication interface | RS-485 |
| Power supply | AC 85–270 V mains (DIN-rail mount) |
| Uplink | LoRaWAN Class C (always-on) |
| EdgeBus | Supported |
| Protocol | Modbus RTU |
| Business code | 23112 |
| Template name | DTSD1352 |
4.2 Wiring
Power and Communication
| Connection | Description |
|---|---|
| KC11 power | AC 85–270 V, tap from the 220 V circuit inside the distribution panel |
| RS-485 A | Connect to DTSD1352 Pin 7 (RS485 A+) |
| RS-485 B | Connect to DTSD1352 Pin 8 (RS485 😎 |
| Termination | KC11 has a built-in 120 Ω resistor; no external terminator needed at the bus end; do not add resistors at mid-bus nodes |
Meter-side Terminals
DTSD1352 rear terminal assignments (RS-485 relevant):
DTSD1352 terminals (rear) KC11 DTU terminals
───────────────────────── ─────────────────────
Pin 7 (RS485 A+) ───→ RS485 A
Pin 8 (RS485 B-) ───→ RS485 B
Voltage inputs (L1/L2/L3/N) ─── Connect to metered circuit (meter self-powers from here)Note: The DTSD1352 self-powers from the metered voltage (L1/N or L1/L2/L3). The KC11 uses a separate AC mains supply; the two power circuits are independent. When multiple meters share one RS-485 bus, each meter must be configured with a unique slave address (1–247) via its front-panel menu.
5. Data Collection
This integration reads the following Modbus register groups from DTSD1352 using FC=03 (Read Holding Registers):
| Group | Start address | Content |
|---|---|---|
| G1 | 0x000AH | Forward active total energy (ep_fwd) |
| G2 | 0x0014H | Reverse active total energy (ep_rev) |
| G3 | 0x0028H | Forward reactive total energy (eq_fwd) |
| G4 | 0x0032H | Reverse reactive total energy (eq_rev) |
| G5 | 0x0061H | Phase A/B/C voltage + Phase A/B/C current (6 items) |
| G6 | 0x0077H | Frequency + Line voltage AB/CB/AC (4 items) |
| G7 | 0x0087H | Per-phase forward active energy ep_a/ep_b/ep_c |
| G8a | 0x008FH | DIDO/voltage-loss status (dido_status) |
| G8b | 0x0092H | Zero-sequence current + voltage unbalance + current unbalance |
| G9 | 0x0164H | Three-phase active/reactive/apparent power + power factor (28 registers; triggers uplink) |
CT/PT ratios (0x008DH/0x008EH) are written via Modbus FC=10 (write multiple registers) transparent pass-through and are not polled periodically.
5.1 Register Definitions
Energy Registers (uint32BE, × 0.01, kWh / kVarh)
| Field | Address | Bytes | Type | Coefficient | Unit |
|---|---|---|---|---|---|
| Forward active total energy | 0x000AH | 4 | uint32BE | 0.01 | kWh |
| Reverse active total energy | 0x0014H | 4 | uint32BE | 0.01 | kWh |
| Forward reactive total energy | 0x0028H | 4 | uint32BE | 0.01 | kVarh |
| Reverse reactive total energy | 0x0032H | 4 | uint32BE | 0.01 | kVarh |
| Phase A forward active energy | 0x0087H | 4 | uint32BE | 0.01 | kWh |
| Phase B forward active energy | 0x0089H | 4 | uint32BE | 0.01 | kWh |
| Phase C forward active energy | 0x008BH | 4 | uint32BE | 0.01 | kWh |
Voltage / Current / Frequency Registers (uint16BE)
| Field | Address | Bytes | Type | Coefficient | Unit |
|---|---|---|---|---|---|
| Phase A voltage | 0x0061H | 2 | uint16BE | 0.1 | V |
| Phase B voltage | 0x0062H | 2 | uint16BE | 0.1 | V |
| Phase C voltage | 0x0063H | 2 | uint16BE | 0.1 | V |
| Phase A current | 0x0064H | 2 | uint16BE | 0.01 | A |
| Phase B current | 0x0065H | 2 | uint16BE | 0.01 | A |
| Phase C current | 0x0066H | 2 | uint16BE | 0.01 | A |
| Frequency | 0x0077H | 2 | uint16BE | 0.01 | Hz |
| Line voltage AB | 0x0078H | 2 | uint16BE | 0.1 | V |
| Line voltage CB | 0x0079H | 2 | uint16BE | 0.1 | V |
| Line voltage AC | 0x007AH | 2 | uint16BE | 0.1 | V |
Power Registers (int32BE two's complement, × 0.001, 3 decimal places)
| Field | Address | Bytes | Type | Coefficient | Unit |
|---|---|---|---|---|---|
| Phase A active power | 0x0164H | 4 | int32BE | 0.001 | kW |
| Phase B active power | 0x0166H | 4 | int32BE | 0.001 | kW |
| Phase C active power | 0x0168H | 4 | int32BE | 0.001 | kW |
| Total active power | 0x016AH | 4 | int32BE | 0.001 | kW |
| Phase A reactive power | 0x016CH | 4 | int32BE | 0.001 | kVar |
| Phase B reactive power | 0x016EH | 4 | int32BE | 0.001 | kVar |
| Phase C reactive power | 0x0170H | 4 | int32BE | 0.001 | kVar |
| Total reactive power | 0x0172H | 4 | int32BE | 0.001 | kVar |
| Phase A apparent power | 0x0174H | 4 | int32BE | 0.001 | kVA |
| Phase B apparent power | 0x0176H | 4 | int32BE | 0.001 | kVA |
| Phase C apparent power | 0x0178H | 4 | int32BE | 0.001 | kVA |
| Total apparent power | 0x017AH | 4 | int32BE | 0.001 | kVA |
| Phase A power factor | 0x017CH | 2 | int16BE | 0.001 | — |
| Phase B power factor | 0x017DH | 2 | int16BE | 0.001 | — |
| Phase C power factor | 0x017EH | 2 | int16BE | 0.001 | — |
| Total power factor | 0x017FH | 2 | int16BE | 0.001 | — |
Status / Diagnostic Registers
| Field | Address | Bytes | Type | Coefficient | Unit |
|---|---|---|---|---|---|
| DIDO/voltage-loss status | 0x008FH | 2 | uint16BE | — | — |
| Zero-sequence current | 0x0092H | 2 | uint16BE | 0.01 | A |
| Voltage unbalance | 0x0093H | 2 | uint16BE | 0.1 | % |
| Current unbalance | 0x0094H | 2 | uint16BE | 0.1 | % |
Configuration Registers (R/W, written via RPC)
| Field | Address | Bytes | Type | Description |
|---|---|---|---|---|
| PT ratio (voltage transformer) | 0x008DH | 2 | uint16BE | 1–9999, default 1 |
| CT ratio (current transformer) | 0x008EH | 2 | uint16BE | 1–9999, default 1 |
5.2 Status Bit Definitions (DIDO/Voltage-loss Register 0x008FH)
| Bit | Meaning |
|---|---|
| Bit0 | Phase A overvoltage |
| Bit1 | Phase B overvoltage |
| Bit2 | Phase C overvoltage |
| Bit3 | Phase A voltage loss |
| Bit4 | Phase B voltage loss |
| Bit5 | Phase C voltage loss |
| Bit6 | Phase A reverse (phase-sequence fault) |
| Bit7 | Phase B reverse |
| Bit8 | Phase C reverse |
| Bit9 | DI status |
| Bit10 | DO status |
6. EdgeBus Model
6.1 EB Configuration
| Parameter | Value |
|---|---|
| Uplink port | 22 |
| Frame version tag | 0x87 |
| Data type tag | 0x31 |
| Upload/collection period slot (upPeriodIndex) | 70 |
| Baud rate | 9600 bps |
| Data bits | 8 |
| Stop bits | 1 |
| Parity | None |
| Power mode | AC mains (Battery=false, Class C) |
| Business code (BzType) | 23112 |
| Business version (BzVersion) | 1 |
| Firmware version (SwVersion) | 31 |
6.2 EB Code
import { Buffer } from "buffer";
import { buildOtaFile } from "@EBSDK/run";
import { EBModel } from "@EBSDK/EBCompiler/EBModel/EBModel";
import { EventInfoItem } from "@EBSDK/EBCompiler/plugins/EBHelper";
import type { UserConfUPItem } from "@EBSDK/EBCompiler/plugins/EBHelper";
import { CheckbitEnum, getOtaConfig } from "@EBSDK/otaConfig";
const eventInfo: UserConfUPItem[] = [
{
name: "dtsd1352",
port: 22,
version: "0x87",
dataType: "0x31",
upPeriodIndex: 70,
quInfo: [
// G1: Forward active total energy ep_fwd (0x000A, uint32BE)
{
protocol: "modbus", addr: "0x01", code: "0x03", periodIndex: 70,
indexAPP: 150, indexCMD: 0, copySize: 1,
listVal: [
{ start: "0x000A", end: "0x000B" }
]
},
// G2: Reverse active total energy ep_rev (0x0014, uint32BE)
{
protocol: "modbus", addr: "0x01", code: "0x03", periodIndex: 70,
indexAPP: 150, indexCMD: 0, copySize: 1,
listVal: [
{ start: "0x0014", end: "0x0015" }
]
},
// G3: Forward reactive total energy eq_fwd (0x0028, uint32BE)
{
protocol: "modbus", addr: "0x01", code: "0x03", periodIndex: 70,
indexAPP: 150, indexCMD: 0, copySize: 1,
listVal: [
{ start: "0x0028", end: "0x0029" }
]
},
// G4: Reverse reactive total energy eq_rev (0x0032, uint32BE)
{
protocol: "modbus", addr: "0x01", code: "0x03", periodIndex: 70,
indexAPP: 150, indexCMD: 0, copySize: 1,
listVal: [
{ start: "0x0032", end: "0x0033" }
]
},
// G5: Three-phase voltage + current (0x0061-0x0066, 6×uint16BE)
{
protocol: "modbus", addr: "0x01", code: "0x03", periodIndex: 70,
indexAPP: 150, indexCMD: 0, copySize: 1,
listVal: [
{ start: "0x0061", end: "0x0061" }, // ua
{ start: "0x0062", end: "0x0062" }, // ub
{ start: "0x0063", end: "0x0063" }, // uc
{ start: "0x0064", end: "0x0064" }, // ia
{ start: "0x0065", end: "0x0065" }, // ib
{ start: "0x0066", end: "0x0066" } // ic
]
},
// G6: Frequency + line voltages (0x0077-0x007A, 4×uint16BE)
{
protocol: "modbus", addr: "0x01", code: "0x03", periodIndex: 70,
indexAPP: 150, indexCMD: 0, copySize: 1,
listVal: [
{ start: "0x0077", end: "0x0077" }, // freq
{ start: "0x0078", end: "0x0078" }, // uab
{ start: "0x0079", end: "0x0079" }, // ucb
{ start: "0x007A", end: "0x007A" } // uac
]
},
// G7: Per-phase energy (0x0087-0x008C, 3×uint32BE)
{
protocol: "modbus", addr: "0x01", code: "0x03", periodIndex: 70,
indexAPP: 150, indexCMD: 0, copySize: 1,
listVal: [
{ start: "0x0087", end: "0x0088" }, // ep_a (uint32BE)
{ start: "0x0089", end: "0x008A" }, // ep_b (uint32BE)
{ start: "0x008B", end: "0x008C" } // ep_c (uint32BE)
]
},
// G8a: Voltage-loss / DIDO status (0x008F, uint16BE)
{
protocol: "modbus", addr: "0x01", code: "0x03", periodIndex: 70,
indexAPP: 150, indexCMD: 0, copySize: 1,
listVal: [
{ start: "0x008F", end: "0x008F" } // dido_status
]
},
// G8b: Zero-sequence current + unbalance (0x0092-0x0094, 3×uint16BE)
{
protocol: "modbus", addr: "0x01", code: "0x03", periodIndex: 70,
indexAPP: 150, indexCMD: 0, copySize: 1,
listVal: [
{ start: "0x0092", end: "0x0092" }, // i0
{ start: "0x0093", end: "0x0093" }, // unbl_u
{ start: "0x0094", end: "0x0094" } // unbl_i
]
},
// G9: Power + power factor (0x0164-0x017F, 12×int32BE + 4×int16BE); triggers uplink
{
protocol: "modbus", addr: "0x01", code: "0x03", periodIndex: 70,
indexAPP: 150, indexCMD: 0, copySize: 1,
isLast: true,
listVal: [
{ start: "0x0164", end: "0x0165" }, // pa (int32BE)
{ start: "0x0166", end: "0x0167" }, // pb (int32BE)
{ start: "0x0168", end: "0x0169" }, // pc (int32BE)
{ start: "0x016A", end: "0x016B" }, // pt (int32BE)
{ start: "0x016C", end: "0x016D" }, // qa (int32BE)
{ start: "0x016E", end: "0x016F" }, // qb (int32BE)
{ start: "0x0170", end: "0x0171" }, // qc (int32BE)
{ start: "0x0172", end: "0x0173" }, // qt (int32BE)
{ start: "0x0174", end: "0x0175" }, // sa (int32BE)
{ start: "0x0176", end: "0x0177" }, // sb (int32BE)
{ start: "0x0178", end: "0x0179" }, // sc (int32BE)
{ start: "0x017A", end: "0x017B" }, // st (int32BE)
{ start: "0x017C", end: "0x017C" }, // pfa (int16BE)
{ start: "0x017D", end: "0x017D" }, // pfb (int16BE)
{ start: "0x017E", end: "0x017E" }, // pfc (int16BE)
{ start: "0x017F", end: "0x017F" } // pft (int16BE)
]
}
]
}
]
let otaConfig = getOtaConfig({
BaudRate: 9600,
StopBits: 1,
DataBits: 8,
Checkbit: CheckbitEnum.NONE,
Battery: false,
ConfirmDuty: 60,
BzType: 23112,
BzVersion: 1
})
const MODBUS_TT = (ebModel: EBModel) => {
for (let i = 0; i < eventInfo.length; i++) {
let event = new EventInfoItem(eventInfo[i]);
event.upEventSetup()
event.eventInstall()
}
return JSON.stringify(ebModel, null, 2)
}
buildOtaFile(__filename, otaConfig, MODBUS_TT)6.3 Description
The EB code contains 9 Modbus query events (G1–G9). After all queries complete, G9 (isLast: true) triggers a single uplink:
- G1–G4: Energy registers at scattered addresses — each reads 2 registers (uint32BE, 4 bytes per group)
- G5: Phase A/B/C voltage (0x0061–0x0063) + phase A/B/C current (0x0064–0x0066), 6 uint16BE registers
- G6: Frequency (0x0077) + line voltages AB/CB/AC (0x0078–0x007A), 4 uint16BE registers
- G7: Per-phase forward active energy ep_a/ep_b/ep_c (0x0087/0x0089/0x008B), 2 registers each (uint32BE)
- G8a: DIDO/voltage-loss status (0x008F), 1 uint16BE register
- G8b: Zero-sequence current (0x0092) + voltage unbalance (0x0093) + current unbalance (0x0094), 3 uint16BE
- G9: Power group, reads 28 consecutive registers at 0x0164–0x017F (12×int32BE + 4×int16BE), triggers uplink
Uplink frame layout (dataLen = 118 bytes):
| Byte offset | Content |
|---|---|
| 0 | Version tag (0x87) |
| 1 | Data type (0x31) |
| 2 | Status byte |
| 3 | Reserved |
| 4 | Battery voltage |
| 5 | Reserved |
| 6–9 | ep_fwd (uint32BE) |
| 10–13 | ep_rev (uint32BE) |
| 14–17 | eq_fwd (uint32BE) |
| 18–21 | eq_rev (uint32BE) |
| 22–23 | ua (uint16BE) |
| 24–25 | ub (uint16BE) |
| 26–27 | uc (uint16BE) |
| 28–29 | ia (uint16BE) |
| 30–31 | ib (uint16BE) |
| 32–33 | ic (uint16BE) |
| 34–35 | freq (uint16BE) |
| 36–37 | uab (uint16BE) |
| 38–39 | ucb (uint16BE) |
| 40–41 | uac (uint16BE) |
| 42–45 | ep_a (uint32BE) |
| 46–49 | ep_b (uint32BE) |
| 50–53 | ep_c (uint32BE) |
| 54–55 | dido_status (uint16BE) |
| 56–57 | i0 (uint16BE) |
| 58–59 | unbl_u (uint16BE) |
| 60–61 | unbl_i (uint16BE) |
| 62–65 | pa (int32BE) |
| 66–69 | pb (int32BE) |
| 70–73 | pc (int32BE) |
| 74–77 | pt (int32BE) |
| 78–81 | qa (int32BE) |
| 82–85 | qb (int32BE) |
| 86–89 | qc (int32BE) |
| 90–93 | qt (int32BE) |
| 94–97 | sa (int32BE) |
| 98–101 | sb (int32BE) |
| 102–105 | sc (int32BE) |
| 106–109 | st (int32BE) |
| 110–111 | pfa (int16BE) |
| 112–113 | pfb (int16BE) |
| 114–115 | pfc (int16BE) |
| 116–117 | pft (int16BE) |
upPeriodIndex = periodIndex = 70: COV is disabled. The upload and collection period share one parameter slot (app_70), defaulting to 60 seconds. The Modbus slave address is injected dynamically into the query frame via app_150 (indexAPP=150, indexCMD=0, copySize=1).
7. Thing Model
7.1 Thing Model Overview
| Type | Name | id_name |
|---|---|---|
| Telemetry thing model | [DTSD1352] | dtsd1352_23112 |
| Parameter thing model | [DTSD1352-PARA] | dtsd1352_para_23112 |
7.2 Uplink Frame Structure (frameInfo)
let frameInfo = {
port: 22,
dataLen: 118,
rssi: true,
battery: 4,
tagList: [
{ index: 0, tag: 0x87 },
{ index: 1, tag: 0x31 }
]
};7.3 Thing Model Scripts
Telemetry Thing Model (dtsd1352_23112)
import {BufferTKL, PayloadParser, Utils} from '#tklHelper';
function payload_parser({device, msg, thingModelId, noticeAttrs}) {
let port = msg?.userdata?.port || null;
if (port !== 22) return null;
let frameInfo = {
port: 22,
dataLen: 118,
rssi: true,
battery: 4,
tagList: [
{ index: 0, tag: 0x87 },
{ index: 1, tag: 0x31 }
]
};
let appInfo = [
{ name: "Forward active total energy", field_name: "ep_fwd", unit: "kWh", index: 6, type: "uint32BE", coefficient: 0.01, decimal: 2 },
{ name: "Reverse active total energy", field_name: "ep_rev", unit: "kWh", index: 10, type: "uint32BE", coefficient: 0.01, decimal: 2 },
{ name: "Forward reactive total energy", field_name: "eq_fwd", unit: "kVarh", index: 14, type: "uint32BE", coefficient: 0.01, decimal: 2 },
{ name: "Reverse reactive total energy", field_name: "eq_rev", unit: "kVarh", index: 18, type: "uint32BE", coefficient: 0.01, decimal: 2 },
{ name: "Phase A voltage", field_name: "ua", unit: "V", index: 22, type: "uint16BE", coefficient: 0.1, decimal: 1 },
{ name: "Phase B voltage", field_name: "ub", unit: "V", index: 24, type: "uint16BE", coefficient: 0.1, decimal: 1 },
{ name: "Phase C voltage", field_name: "uc", unit: "V", index: 26, type: "uint16BE", coefficient: 0.1, decimal: 1 },
{ name: "Phase A current", field_name: "ia", unit: "A", index: 28, type: "uint16BE", coefficient: 0.01, decimal: 2 },
{ name: "Phase B current", field_name: "ib", unit: "A", index: 30, type: "uint16BE", coefficient: 0.01, decimal: 2 },
{ name: "Phase C current", field_name: "ic", unit: "A", index: 32, type: "uint16BE", coefficient: 0.01, decimal: 2 },
{ name: "Frequency", field_name: "freq", unit: "Hz", index: 34, type: "uint16BE", coefficient: 0.01, decimal: 2 },
{ name: "Line voltage AB", field_name: "uab", unit: "V", index: 36, type: "uint16BE", coefficient: 0.1, decimal: 1 },
{ name: "Line voltage CB", field_name: "ucb", unit: "V", index: 38, type: "uint16BE", coefficient: 0.1, decimal: 1 },
{ name: "Line voltage AC", field_name: "uac", unit: "V", index: 40, type: "uint16BE", coefficient: 0.1, decimal: 1 },
{ name: "Phase A fwd active energy", field_name: "ep_a", unit: "kWh", index: 42, type: "uint32BE", coefficient: 0.01, decimal: 2 },
{ name: "Phase B fwd active energy", field_name: "ep_b", unit: "kWh", index: 46, type: "uint32BE", coefficient: 0.01, decimal: 2 },
{ name: "Phase C fwd active energy", field_name: "ep_c", unit: "kWh", index: 50, type: "uint32BE", coefficient: 0.01, decimal: 2 },
{ name: "DIDO/voltage-loss status", field_name: "dido_status", unit: "", index: 54, type: "uint16BE" },
{ name: "Zero-seq current", field_name: "i0", unit: "A", index: 56, type: "uint16BE", coefficient: 0.01, decimal: 2 },
{ name: "Voltage unbalance",field_name: "unbl_u", unit: "%", index: 58, type: "uint16BE", coefficient: 0.1, decimal: 1 },
{ name: "Current unbalance",field_name: "unbl_i", unit: "%", index: 60, type: "uint16BE", coefficient: 0.1, decimal: 1 },
{ name: "Phase A active power", field_name: "pa", unit: "kW", index: 62, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Phase B active power", field_name: "pb", unit: "kW", index: 66, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Phase C active power", field_name: "pc", unit: "kW", index: 70, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Total active power", field_name: "pt", unit: "kW", index: 74, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Phase A reactive power", field_name: "qa", unit: "kVar", index: 78, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Phase B reactive power", field_name: "qb", unit: "kVar", index: 82, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Phase C reactive power", field_name: "qc", unit: "kVar", index: 86, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Total reactive power", field_name: "qt", unit: "kVar", index: 90, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Phase A apparent power", field_name: "sa", unit: "kVA", index: 94, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Phase B apparent power", field_name: "sb", unit: "kVA", index: 98, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Phase C apparent power", field_name: "sc", unit: "kVA", index: 102, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Total apparent power", field_name: "st", unit: "kVA", index: 106, type: "int32BE", coefficient: 0.001, decimal: 3 },
{ name: "Phase A power factor", field_name: "pfa", unit: "", index: 110, type: "int16BE", coefficient: 0.001, decimal: 3 },
{ name: "Phase B power factor", field_name: "pfb", unit: "", index: 112, type: "int16BE", coefficient: 0.001, decimal: 3 },
{ name: "Phase C power factor", field_name: "pfc", unit: "", index: 114, type: "int16BE", coefficient: 0.001, decimal: 3 },
{ name: "Total power factor", field_name: "pft", unit: "", index: 116, type: "int16BE", coefficient: 0.001, decimal: 3 },
];
let payParser = new PayloadParser({ device, msg, frameInfo, appInfo });
let tdata = payParser.telemetry();
if ((tdata?.status & 0x02) === 0x02) {
const status = tdata.status;
tdata = { ...(device.telemetry_data?.[thingModelId] ?? {}) };
tdata.status = status;
}
tdata._modelName = "dtsd1352_23112";
return { telemetry_data: tdata, server_attrs: null, shared_attrs: null };
}Parameter Thing Model (dtsd1352_para_23112)
import {BufferTKL, PayloadParser, Utils} from '#tklHelper';
function payload_parser({device, msg, thingModelId, noticeAttrs}) {
let port = msg?.userdata?.port || null;
const rpcName = "dtsd1352_set_23112";
let paraDef = {
app_20: { name: "TimeOffset", field_name: "TimeOffset", unit: "", index: 20, type: "uint32le" },
app_38: { name: "pwron_delay", field_name: "pwron_delay", unit: "ms", index: 38, type: "uint16le" },
app_70: { name: "period_up", field_name: "period_up", unit: "s", type: "uint32le" },
app_150: { name: "addr_modbus", field_name: "addr_modbus", unit: "", type: "uint8" }
};
if (port !== 214) {
let checkData = Utils.paraCheck(rpcName, device.server_attrs, device.shared_attrs);
return {
server_attrs: checkData.sdata,
actions: checkData.actions
};
}
let pdata = (new PayloadParser({ device, msg, paraInfo: paraDef })).paras();
let checkData = Utils.paraCheck(rpcName, device.server_attrs, pdata);
return {
telemetry_data: pdata,
server_attrs: checkData.sdata,
shared_attrs: pdata,
actions: checkData.actions
};
}8. Third-party Platform Data Subscription
8.1 MQTT Topic
/v32/{Organization Account}/tkl/up/telemetry/{eui}8.2 Sample Payload
{
"eui": "aabbccddeeff0011",
"active_time": "2026-05-24T02:00:00.000Z",
"thingModelId": "111065443795365888",
"thingModelIdName": "dtsd1352_23112",
"telemetry_data": {
"snr": 9.5,
"rssi": -65,
"battery": 3.6,
"status": 0,
"ep_fwd": 12345.67,
"ep_rev": 0.00,
"eq_fwd": 3218.44,
"eq_rev": 0.00,
"ua": 220.3,
"ub": 219.8,
"uc": 221.1,
"ia": 18.52,
"ib": 17.91,
"ic": 19.05,
"freq": 50.01,
"uab": 381.2,
"ucb": 380.7,
"uac": 381.9,
"ep_a": 4115.22,
"ep_b": 4112.89,
"ep_c": 4117.56,
"dido_status": 0,
"i0": 0.15,
"unbl_u": 0.3,
"unbl_i": 1.2,
"pa": 4.076,
"pb": 3.941,
"pc": 4.199,
"pt": 12.216,
"qa": 1.312,
"qb": 1.288,
"qc": 1.356,
"qt": 3.956,
"sa": 4.284,
"sb": 4.146,
"sc": 4.420,
"st": 12.850,
"pfa": 0.951,
"pfb": 0.950,
"pfc": 0.950,
"pft": 0.951
}
}9. RPC
9.1 RPC Names
| Type | Name | id_name |
|---|---|---|
| Parameter set | [DTSD1352 SET] 23112 | dtsd1352_set_23112 |
| Parameter get | [DTSD1352 GET] 23112 | dtsd1352_get_23112 |
9.2 Parameter Definitions
| Slot | field_name | Description | Unit | Type | Range | Notes |
|---|---|---|---|---|---|---|
| app_70 | period_up | Collection / upload period | s | uint32le | 1–3600 | Controls how often data is collected and pushed to the cloud; collection and upload share one period slot because COV is disabled |
| app_150 | addr_modbus | Modbus slave address | — | uint8 | 1–247 | Slave address the DTU targets when polling the meter |
| 0x008EH (device reg) | ct_ratio | CT ratio | — | uint16BE | 1–9999 | Current transformer ratio; written directly to meter via FC=10 transparent pass-through |
| 0x008DH (device reg) | vt_ratio | VT ratio | — | uint16BE | 1–9999 | Voltage transformer ratio; written directly to meter via FC=10 transparent pass-through |
period_upandaddr_modbusare written to DTU parameter slots via the PTL-D01 protocol (port 214) with full read-back confirmation.ct_ratioandvt_ratioare fire-and-forget writes via transparent Modbus FC=10 (port 51) directly to the meter's configuration registers.
9.3 RPC Scripts
Parameter Set RPC (dtsd1352_set_23112)
import {BufferTKL, RPCHelper, Utils} from '#tklHelper'
function rpc_script({device, params, alarms, logger}) {
let classMode = (device?.shared_attrs?.class_mode) || "ClassC";
const rpcName = "dtsd1352_set_23112";
let paraDef = {
app_20: { name: "TimeOffset", field_name: "TimeOffset", unit: "", index: 20, type: "uint32le" },
app_38: { name: "pwron_delay", field_name: "pwron_delay", unit: "ms", index: 38, type: "uint16le" },
app_70: { name: "period_up", field_name: "period_up", unit: "s", type: "uint32le" },
app_150: { name: "addr_modbus", field_name: "addr_modbus", unit: "", type: "uint8" }
};
// ct_ratio/vt_ratio go via transparent Modbus — exclude from PTL-D01 state machine
const ptlFields = ["TimeOffset", "pwron_delay", "period_up", "addr_modbus"];
let ptlParams = {};
ptlFields.forEach(f => { if (params[f] !== undefined) ptlParams[f] = params[f]; });
let msgQue = [];
if (Object.keys(ptlParams).length > 0) {
let frames = RPCHelper.buildFrame({ paraDef, params: ptlParams });
let dnBuffer = Buffer.alloc(frames.writeBuffer.length + frames.readBuffer.length);
frames.writeBuffer.copy(dnBuffer, 0);
frames.readBuffer.copy(dnBuffer, frames.writeBuffer.length);
msgQue = Utils.makeParaSetMSG({
device, classMode, rpcName, params: ptlParams,
paraDownBuffer: dnBuffer.length > 0 ? dnBuffer : undefined,
});
}
let modbusAddr = device?.shared_attrs?.addr_modbus ?? 1;
if (params.ct_ratio !== undefined) {
let ctFrames = RPCHelper.buildmodbusFrame10({
paraDef: {
addr: modbusAddr,
paraList: [{ index: 0x008E, field_name: "ct_ratio", name: "CT ratio", type: "uint16BE" }]
},
params
});
if (ctFrames.writeBuffer.length > 0) {
msgQue.push(RPCHelper.makeMSG({
msgType: Utils.msgType.transParent,
device,
dnBuffer: ctFrames.writeBuffer,
}));
}
}
if (params.vt_ratio !== undefined) {
let vtFrames = RPCHelper.buildmodbusFrame10({
paraDef: {
addr: modbusAddr,
paraList: [{ index: 0x008D, field_name: "vt_ratio", name: "VT ratio", type: "uint16BE" }]
},
params
});
if (vtFrames.writeBuffer.length > 0) {
msgQue.push(RPCHelper.makeMSG({
msgType: Utils.msgType.transParent,
device,
dnBuffer: vtFrames.writeBuffer,
}));
}
}
if (msgQue.length == 0) return null;
return msgQue;
}Parameter Get RPC (dtsd1352_get_23112)
import {BufferTKL, RPCHelper, Utils} from '#tklHelper'
function rpc_script({device, params, alarms, logger}) {
let classMode = (device?.shared_attrs?.class_mode) || "ClassC";
let sleepMs = classMode === "ClassA" ? 500 : 5000;
let paraDef = {
app_20: { name: "TimeOffset", field_name: "TimeOffset", unit: "", index: 20, type: "uint32le" },
app_38: { name: "pwron_delay", field_name: "pwron_delay", unit: "ms", index: 38, type: "uint16le" },
app_70: { name: "period_up", field_name: "period_up", unit: "s", type: "uint32le" },
app_150: { name: "addr_modbus", field_name: "addr_modbus", unit: "", type: "uint8" }
};
let frames = RPCHelper.buildFrame({ paraDef, params });
let msg = RPCHelper.makeMSG({
msgType: Utils.msgType.paras,
device,
dnBuffer: frames.readBuffer,
sleepTime: sleepMs,
});
return [msg];
}10. Template Selection
Search the ThinkLink platform template library for:
- DTSD1352
Or search by business code:
- 23112 / Three-phase rail-mount multifunction energy meter
11. Notes
Modbus Communication Settings
The DTSD1352 ships with default communication parameters: 9600 bps, 8 data bits, 1 stop bit, Even parity (DL/T645 mode). This integration uses Modbus RTU with no parity, so parity must be changed via the front-panel menu before connecting:
Menu path: BUS → Parity → NoneRestart the meter after changing the setting. Configure KC11 to match: 9600 bps, 8N1.
Writing CT/PT Ratios
CT and PT ratios are written to the meter via the SET RPC (dtsd1352_set_23112):
ct_ratio→ meter register 0x008EH (Modbus FC=10)vt_ratio→ meter register 0x008DH (Modbus FC=10)
These are fire-and-forget writes — the platform does not read back the values to confirm. After writing, it is recommended to run the GET RPC (dtsd1352_get_23112) to verify that period_up / addr_modbus are correct, and to use the ThinkLink transparent pass-through RPC (Modbus debug) to read back registers 0x008D/0x008EH and confirm the ratios took effect.
Multi-meter Bus Wiring
Multiple DTSD1352 meters can share one RS-485 bus, each assigned a unique Modbus address (1–247). Configure addr_modbus independently for each device on the ThinkLink platform. The KC11 injects the slave address dynamically into each query frame (indexAPP=150). A 120 Ω termination resistor is required at the far end of the bus; KC11 has one built-in.
Modbus Communication Examples
Read Phase A voltage (FC=03):
Request: 01 03 00 61 00 01 D4 34
Response: 01 03 02 08 9A C0 2A
→ 0x089A = 2202 → 2202 × 0.1 = 220.2 VRead total active power (4-byte int32BE, FC=03):
Request: 01 03 01 6A 00 02 A3 E7
Response: 01 03 04 00 00 04 B0 [CRC]
→ 0x000004B0 = 1200 → 1200 × 0.001 = 1.200 kW