Skip to content

SWMx DIDO Controller Integration with ThinkLink

Model catalog

Search for these models in ThinkLink by name or ID.

Model typeNameid_namePlatform model ID
RPC[SWM GET] paraswm_get_22108103860451414118405
RPC[SWM RY1 ACT]swm_ry1_action_22108114414111810285568
RPC[SWM RY2 ACT]swm_ry2_action_22108114414111818674176
RPC[SWM RY3 ACT]swm_ry3_action_22108114414111818674177
RPC[SWM RY4 ACT]swm_ry4_action_22108114414111818674178
RPC[SWM RY5 ACT]swm_ry5_action_22108114414111818674179
RPC[SWM SET] paraswm_set_22108103860187344932869
TemplateSWMx-22108104217259886514181
Thing Model[SWM]swm_22108103857105529737221
Thing Model[SWM-22108-SWM资产] 区域聚合swm_asset_22108119677174411063312
Parameter Thing Model[SWM-PARA]swm_para_22108103858394913312773

Integration Documentation

1. Sensor Overview

SWMx is a DIDO controller from JSDZ, mainly used for digital input status acquisition and relay output control.

In this solution, SWMx is connected to the KC11 collector through RS-485. The built-in EdgeBus in KC11 executes the Modbus RTU acquisition logic and uploads data to the ThinkLink platform through LoRaWAN.

Basic device information:

ItemDescription
Device ModelSWMx
ManufacturerJSDZ
English NameJSDZ
Device TypeDIDO Controller
Business Code22108
ThinkLink TemplateSWMx-22108

2. Product Features

The SWMx DIDO controller supports the following features:

  1. Digital input status acquisition
  2. Relay output control
  3. RS-485 / Modbus RTU communication
  4. LoRaWAN network access through KC11 + EdgeBus
  5. Status parsing, data visualization, and remote control through ThinkLink
  6. Reporting of complete RY / DI status bytes
  7. Parsing of the first 5 RY and DI channels as independent fields
  8. RPC-based configuration of acquisition period, upload period, and Modbus address
  9. RPC-based control of specified relay output status

3. Application Scenarios

This solution is suitable for the following scenarios:

  • Remote relay control
  • Digital input status monitoring
  • Equipment running status acquisition
  • Access control, magnetic door contact, and switch status monitoring
  • Wireless retrofit of DIDO controllers in industrial sites
  • Connecting traditional RS-485 controllers to LoRaWAN / ThinkLink
  • Remote control through MQTT / RPC from third-party platforms

4. Collector Information

4.1 Hardware Information

This solution uses KC11 as the collector.

ItemDescription
Collector ModelKC11
Acquisition InterfaceRS-485
Communication ProtocolModbus RTU
Uplink MethodLoRaWAN
Power Supply220V / 12V
Edge Computing CapabilityEdgeBus supported
Platform AccessThinkLink

KC11 reads Modbus data from SWMx through RS-485, uploads the acquisition results to the gateway through LoRaWAN, and finally sends the data to the ThinkLink platform.

4.2 Wiring Information

Power and communication interface:

Wiring ItemDescription
KC11 Power220V / 12V power supply
SWMx PowerConnect according to the actual SWMx power supply requirements
RS-485 AKC11 RS-485 A connected to SWMx A
RS-485 BKC11 RS-485 B connected to SWMx B
GNDConnect communication reference ground if required on site

Sensor interface:

SWMx itself is a DIDO controller. Sensors or field devices are connected to the DI input terminals of SWMx, while controlled devices are connected to the RY / relay output terminals of SWMx.

In this solution, KC11 does not directly connect to DI signals or relay loads. Instead, it reads and controls SWMx through RS-485.


5. Data Acquisition

In this solution, the following data is read through Modbus:

Data TypeModbus Function CodeDescription
RY Status0x01Read coil status
DI Status0x02Read discrete input status

This acquisition uses Modbus function codes 01 and 02:

  • 0x01: Read RY / Coil status
  • 0x02: Read DI / Discrete Input status

It should be noted that function codes 01 and 02 read data by bit, unlike function codes 03 and 04, which read register data directly. However, in this solution, EBHelper already handles this at the lower layer and automatically combines bit data into bytes.

Therefore, the EB code configuration:

javascript
{ start: "0", end: "15", covType: "HEX" }

means reading 16 bits from bit 0 to bit 15. The lower layer automatically combines the result into 2 bytes for upload.


5.1 Register Definition

RY Status Acquisition

ItemDescription
ProtocolModbus RTU
Function Code0x01
Read ObjectCoil / relay status
Start Address0
End Address15
Data Length16 bits, combined into 2 bytes by the lower layer
Upload FormatHEX
Change TriggerSupported, covType: "HEX"

Corresponding EB configuration:

javascript
{
  protocol: "modbus",
  code: "0x01",
  periodIndex: 74,
  indexAPP: 150,
  indexCMD: 0,
  copySize: 1,
  isLast: false,
  listVal: [
    { start: "0", end: "15", covType: "HEX" }
  ]
}

DI Status Acquisition

ItemDescription
ProtocolModbus RTU
Function Code0x02
Read ObjectDiscrete Input / digital input status
Start Address0
End Address15
Data Length16 bits, combined into 2 bytes by the lower layer
Upload FormatHEX
Change TriggerSupported, covType: "HEX"

Corresponding EB configuration:

javascript
{
  protocol: "modbus",
  code: "0x02",
  periodIndex: 74,
  indexAPP: 150,
  indexCMD: 0,
  copySize: 1,
  isLast: false,
  listVal: [
    { start: "0", end: "15", covType: "HEX" }
  ]
}

5.2 Status Bit Definition

In this solution, the thing model parses both the complete status word and the first 5 channel statuses.

RY Status Bit Definition

Field Namefield_nameData PositionTypeDescription
RYry_status_hexindex 6hexbe2RY 2-byte status value, HEX string
RY1ry1index 6 bit0bitLE0-0Relay channel 1 status
RY2ry2index 6 bit1bitLE1-1Relay channel 2 status
RY3ry3index 6 bit2bitLE2-2Relay channel 3 status
RY4ry4index 6 bit3bitLE3-3Relay channel 4 status
RY5ry5index 6 bit4bitLE4-4Relay channel 5 status

DI Status Bit Definition

Field Namefield_nameData PositionTypeDescription
DIdi_status_hexindex 8hexbe2DI 2-byte status value, HEX string
DI1di1index 8 bit0bitLE0-0DI channel 1 status
DI2di2index 8 bit1bitLE1-1DI channel 2 status
DI3di3index 8 bit2bitLE2-2DI channel 3 status
DI4di4index 8 bit3bitLE3-3DI channel 4 status
DI5di5index 8 bit4bitLE4-4DI channel 5 status

6. EdgeBus Model

In this solution, SWMx is an RS-485 / Modbus RTU device rather than a native LoRaWAN device. Therefore, the built-in EdgeBus in KC11 is required to execute the acquisition logic.

EdgeBus is responsible for:

  1. Periodically reading the RY status of SWMx
  2. Periodically reading the DI status of SWMx
  3. Reading bit status using Modbus function codes 01 / 02
  4. Encapsulating the reading results into LoRaWAN uplink data
  5. Supporting change-triggered upload logic
  6. Supporting parameter modification through platform RPC
  7. Supporting relay output control through platform RPC

6.1 EB Configuration Parameters

ParameterDescription
port22
dataType0x86
version0x08
upPeriodIndex70
readPeriodIndex74
Modbus address parameter index150
Modbus baud rate9600
Data bits8
Stop bits1
ParityNONE
Business type22108
Business version13
EB software version31
Battery devicefalse

Parameter description:

Parameter IndexFieldDescription
70period_upUpload period, in seconds
74period_readAcquisition period, in seconds
150addr_modbusSWMx Modbus address

typescript
import { Buffer } from "buffer";
import { buildOtaFile } from "@EBSDK/run";
import {
    ActionAfertExpr, CalcData,
    CrcMode,
    CvtRule,
    EBBuffer,
    EBModel,
    ExprCondition,
    LoraUpEvent,
    QueryEvent, SetUpCovDataType,QuItemBase,
    UserConfUPItem, EventInfoItem, QuItemModBus, UserConfQueryItem, EventConfig, Utils
} from "@EBSDK/EBCompiler/all_variable";
import { CheckbitEnum, getOtaConfig, HwTypeEnum, UpgrdTypeEnum } from "@EBSDK/otaConfig";
////////////////////////////////////////////////////////////////////////////////////////
//01,02 是按bit读取的,EBHelper会自动组合成字节。start: "0", end: "15" 实际为2字节
//covType 如何是 HEX,那么会将采集到的数据与上次数据做对比,如果有差异则触发上传
const eventInfo:UserConfUPItem[]=[
   {
        name:"swm",dataType:"0x86", port:22, version:"0x08",upPeriodIndex:70,//upPeriod:"300s",
        quInfo:[
            {
            protocol:"modbus",code:"0x01", periodIndex:74,//period:"300s",
                 indexAPP:150, indexCMD:0, copySize:1,isLast:false,
            listVal:[{ start: "0", end: "15",covType:"HEX"}]
            },
            {
                protocol:"modbus", code:"0x02",periodIndex:74, //period:"30s",
                indexAPP:150, indexCMD:0, copySize:1,isLast:false,
                listVal:[
                    { start: "0", end: "15",covType:"HEX"}
                ]
            }
        ]
    }
]
let otaConfig = getOtaConfig({
    SwVersion:31,
    BaudRate: 9600,
    StopBits: 1,
    DataBits: 8,
    Checkbit: CheckbitEnum.NONE,
    Battery: false,
    ConfirmDuty: 60,
    BzType: 22108,
    BzVersion: 13
})
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(import.meta.url, otaConfig, MODBUS_TT)

6.2 EB Code

typescript
import { Buffer } from "buffer";
import { buildOtaFile } from "@EBSDK/run";
import {
  ActionAfertExpr, CalcData,
  CrcMode,
  CvtRule,
  EBBuffer,
  EBModel,
  ExprCondition,
  LoraUpEvent,
  QueryEvent, SetUpCovDataType, QuItemBase,
  UserConfUPItem, EventInfoItem, QuItemModBus, UserConfQueryItem, EventConfig, Utils
} from "@EBSDK/EBCompiler/all_variable";
import { CheckbitEnum, getOtaConfig, HwTypeEnum, UpgrdTypeEnum } from "@EBSDK/otaConfig";

////////////////////////////////////////////////////////////////////////////////////////
// Function codes 01 and 02 read data by bit. EBHelper automatically combines bits into bytes.
// start: "0", end: "15" means reading 16 bits, uploaded as 2 bytes.
// If covType is HEX, the acquired data will be compared with the previous data.
// If there is any difference, an upload will be triggered.

const eventInfo: UserConfUPItem[] = [
  {
    name: "swm",
    dataType: "0x86",
    port: 22,
    version: "0x08",
    upPeriodIndex: 70,
    quInfo: [
      {
        protocol: "modbus",
        code: "0x01",
        periodIndex: 74,
        indexAPP: 150,
        indexCMD: 0,
        copySize: 1,
        isLast: false,
        listVal: [
          { start: "0", end: "15", covType: "HEX" }
        ]
      },
      {
        protocol: "modbus",
        code: "0x02",
        periodIndex: 74,
        indexAPP: 150,
        indexCMD: 0,
        copySize: 1,
        isLast: false,
        listVal: [
          { start: "0", end: "15", covType: "HEX" }
        ]
      }
    ]
  }
];

let otaConfig = getOtaConfig({
  SwVersion: 31,
  BaudRate: 9600,
  StopBits: 1,
  DataBits: 8,
  Checkbit: CheckbitEnum.NONE,
  Battery: false,
  ConfirmDuty: 60,
  BzType: 22108,
  BzVersion: 13
});

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);
};

6.3 Description

Current EB logic:

  1. KC11 connects to SWMx through RS-485.
  2. EdgeBus reads SWMx data according to the configured period.
  3. Modbus function code 0x01 is used to read RY status.
  4. Modbus function code 0x02 is used to read DI status.
  5. start: "0", end: "15" means reading 16 bits.
  6. EBHelper automatically combines the 16-bit result into 2 bytes at the lower layer.
  7. The thing model uploads the RY status as ry_status_hex.
  8. The thing model uploads the DI status as di_status_hex.
  9. RY1–RY5 and DI1–DI5 are also parsed as independent status fields.
  10. When covType is set to HEX, the acquisition result is compared with the previous data. If the data changes, an upload is triggered.
  11. RPC can be used to configure the acquisition period, upload period, and Modbus address.
  12. RPC can be used to control specified relay switches.

7. Thing Model

7.1 Basic Thing Model Information

ItemDescription
Thing Model NameSWMx-22108
idNameswm_22108
Business Code22108
Data Uplink Port22
Parameter Port214
Transparent Transmission Port51
Data Length9
Parse RSSIYes
Battery Field Index4
Data Identifier0x86
Version Identifier0x08

In this solution, SWMx data is uploaded through LoRaWAN port 22.

javascript
let frameInfo = {
    port: 22,
    dataLen: 9,
    rssi: true,
    battery: 4,
    tagList: [
        { index: 0, tag: 0x86 },
        { index: 1, tag: 0x08 }
    ]
};

Uplink data structure:

IndexContentDescription
00x86Data type
10x08Protocol version
4batteryBattery or power status field
6~7RY status2-byte HEX
8~9DI status2-byte HEX

Note: According to the provided thing model script, dataLen is configured as 9, RY is parsed from index 6 with 2 bytes, and DI is parsed from index 8 with 2 bytes. During actual deployment, it is recommended to verify whether the frame length needs adjustment based on the real uplink payload.


7.3 Thing Model Script

javascript
let port = msg?.userdata?.port || null;

if (port === 51) {
    let retval = Utils.paraCheck(Utils.msgType.transParent, device.server_attrs, { device: device, msg: msg });
    return {
        telemetry_data: retval.tdata,
        server_attrs: retval.sdata,
        shared_attrs: retval.pdata,
        actions: retval.actions
    };
}

if (port !== 22) return null;

let frameInfo = {
    port: 22,
    dataLen: 9,
    rssi: true,
    battery: 4,
    tagList: [
        { index: 0, tag: 0x86 },
        { index: 1, tag: 0x08 }
    ]
};

let appInfo = [
    { name: "RY", field_name: "ry_status_hex", unit: "", index: 6, type: "hexbe2" },
    { name: "DI", field_name: "di_status_hex", unit: "", index: 8, type: "hexbe2" },

    { name: "RY1", field_name: "ry1", unit: "", index: 6, type: "bitLE0-0" },
    { name: "RY2", field_name: "ry2", unit: "", index: 6, type: "bitLE1-1" },
    { name: "RY3", field_name: "ry3", unit: "", index: 6, type: "bitLE2-2" },
    { name: "RY4", field_name: "ry4", unit: "", index: 6, type: "bitLE3-3" },
    { name: "RY5", field_name: "ry5", unit: "", index: 6, type: "bitLE4-4" },

    { name: "DI1", field_name: "di1", unit: "", index: 8, type: "bitLE0-0" },
    { name: "DI2", field_name: "di2", unit: "", index: 8, type: "bitLE1-1" },
    { name: "DI3", field_name: "di3", unit: "", index: 8, type: "bitLE2-2" },
    { name: "DI4", field_name: "di4", unit: "", index: 8, type: "bitLE3-3" },
    { name: "DI5", field_name: "di5", unit: "", index: 8, type: "bitLE4-4" }
];

let payParser = new PayloadParser({
    device: device,
    msg: msg,
    frameInfo: frameInfo,
    appInfo: appInfo,
});

let tdata = payParser.telemetry();

if ((tdata?.status & 0x02) === 0x02) {
    // time out, only update status
    const status = tdata.status;
    tdata = { ...(device.telemetry_data?.[thingModelId] ?? {}) };
    tdata.status = status;
}

return {
    telemetry_data: tdata,
    server_attrs: null,
    shared_attrs: null
};

8. Third-Party Platform Data Subscription

8.1 MQTT Topic

A third-party platform can subscribe to ThinkLink uplink data through the following topic:

latex
/v32/{Organization Account}/tkl/up/telemetry/{eui}

Where:

ParameterDescription
Organization AccountThinkLink organization account
euiLoRaWAN device EUI
json
{
    "eui": "6353012af10a9331",
    "active_time": "2026-02-05T08:35:48.000Z",
    "thingModelId": "88304368717139973",
    "thingModelIdName": "swm_22108",
    "telemetry_data": {
        "snr": 13.5,
        "rssi": -51,
        "battery": 3.37,
        "ry_status_hex": "001F",
        "di_status_hex": "000B",
        "ry1": 1,
        "ry2": 1,
        "ry3": 1,
        "ry4": 1,
        "ry5": 1,
        "di1": 1,
        "di2": 1,
        "di3": 0,
        "di4": 1,
        "di5": 0,
        "status": 0
    }
}

Field description:

FieldDescription
ry_status_hexRY status 2-byte HEX string
di_status_hexDI status 2-byte HEX string
ry1ry5Relay channel 1–5 status
di1di5DI input channel 1–5 status
batteryBattery or power status field
rssiLoRaWAN RSSI
snrLoRaWAN SNR
statusData status

9. RPC

This solution supports the following RPC functions:

  1. Parameter configuration
  2. Parameter reading
  3. Relay control

9.1 RPC Names

RPC FunctionRPC Name
Parameter configurationswm_set_22108
Parameter readingswm_get_22108
Relay 1 controlswm_ry1_action_22108
Relay 2 controlswm_ry2_action_22108
Relay 3 controlswm_ry3_action_22108
Relay 4 controlswm_ry4_action_22108
Relay 5 controlswm_ry5_action_22108

Each relay channel has its own dedicated control RPC (one per channel, independent of each other), which simplifies per-channel permissioning and single-channel operation.

9.2 Parameter Definition

Parameter configuration definition:

javascript
let paraDef = {
    app_70: {
        name: "period_up",
        field_name: "period_up",
        unit: "s",
        type: "uint32LE"
    },
    app_74: {
        name: "period_read",
        field_name: "period_read",
        unit: "s",
        type: "uint32LE"
    },
    app_150: {
        name: "addr_modbus",
        field_name: "addr_modbus",
        unit: "",
        type: "uint8"
    }
};

Parameter table:

Parameterfield_nameTypeUnitDescription
app_70period_upuint32LEsUpload period
app_74period_readuint32LEsAcquisition period
app_150addr_modbusuint8-SWMx Modbus address

Relay control parameters — each relay channel is a dedicated RPC with a single boolean parameter. When the form opens, the field is auto-populated from the device shared attribute (ryN) with the last commanded state.

RPCParameterTypeDescription
swm_ry1_action_22108switch_ry1booleanRelay channel 1: true close / turn on, false open / turn off
swm_ry2_action_22108switch_ry2booleanRelay channel 2
swm_ry3_action_22108switch_ry3booleanRelay channel 3
swm_ry4_action_22108switch_ry4booleanRelay channel 4
swm_ry5_action_22108switch_ry5booleanRelay channel 5

Each RPC sends one Modbus FC05 frame (coil address = channel number − 1, e.g. ry1→0, ry5→4). On success, that channel's state is written back to both telemetry ryN and shared attribute ryN, used to auto-populate the form next time it is opened.

Example (close channel 1, by calling swm_ry1_action_22108):

json
{
    "switch_ry1": true
}

9.3 RPC Code

9.3.1 Parameter Configuration RPC

javascript
let classMode = (device && device.shared_attrs && device.shared_attrs.class_mode) || "ClassA";
let intervalms = classMode === "ClassA" ? 0 : 2000;

const rpcName = "swm_set_22108";

let paraDef = {
    app_70: { name: "period_up", field_name: "period_up", unit: "s", type: "uint32LE" },
    app_74: { name: "period_read", field_name: "period_read", unit: "s", type: "uint32LE" },
    app_150: { name: "addr_modbus", field_name: "addr_modbus", unit: "", type: "uint8" }
};

let frames = RPCHelper.buildFrame({
    paraDef: paraDef,
    params: params
});

let redoBuffer = RPCHelper.redo();

let dnBuffer = Buffer.alloc(frames.writeBuffer.length + frames.readBuffer.length);
frames.writeBuffer.copy(dnBuffer, 0);
frames.readBuffer.copy(dnBuffer, frames.writeBuffer.length);

logger.info("set para");

let msgQue = Utils.makeParaSetMSG({
    device: device,
    classMode: classMode,
    rpcName: rpcName,
    params: params,
    paraDownBuffer: dnBuffer,
    extraAppBuffer: redoBuffer
});

if (msgQue.length == 0) return null;

return msgQue;

9.3.2 Parameter Reading RPC

javascript
let classMode = (device && device.shared_attrs && device.shared_attrs.class_mode) || "ClassA";
let sleepMs = classMode === "ClassA" ? 500 : 5000;

let paraDef = {
    app_70: { name: "period_up", field_name: "period_up", unit: "s", type: "uint32LE" },
    app_74: { name: "period_read", field_name: "period_read", unit: "s", type: "uint32LE" },
    app_150: { name: "addr_modbus", field_name: "addr_modbus", unit: "", type: "uint8" }
};

let frames = RPCHelper.buildFrame({
    paraDef: paraDef,
    params: params
});

let msg = RPCHelper.makeMSG({
    msgType: Utils.msgType.paras,
    device: device,
    dnBuffer: frames.readBuffer,
    sleepTime: sleepMs,
});

return [msg];

9.3.3 Relay Control RPC

The five relay channels are split into five independent RPCs (swm_ry1_action_22108~swm_ry5_action_22108), each controlling a single channel with one boolean parameter switch_ryN (default_from: shared_attrs, populated from ryN). Each RPC sends one Modbus function-code-05 frame (coil address = channel number − 1), verifies the coil value against the device echo, and on success writes that channel's state back to both telemetry ryN and shared attribute ryN (used to auto-populate the form next time it is opened).

Example for channel 1, swm_ry1_action_22108 (other channels differ only in rpcName, switch_ryN, coil address and field name):

javascript
let classMode = (device?.shared_attrs?.class_mode) || "ClassA";
let addr_modbus = device.shared_attrs?.addr_modbus ?? 1;
let rpcName = "swm_ry1_action_22108";

// Relay channel 1: form field switch_ry1 (boolean), default_from:shared_attrs ry1.
// One Modbus FC05 single-coil write: coil address = channel-1 = 0; 0xFF00=close / 0x0000=open.
if (params.switch_ry1 === undefined) return null;
let on = params.switch_ry1 ? 1 : 0;
let checkVal = params.switch_ry1 ? 0xFF00 : 0x0000;
let dnBuffer = RPCHelper.modbusAction(addr_modbus, 5, 0, checkVal);

// FC05 echo is 8 bytes: [addr][05][coilH][coilL][valH][valL][crcL][crcH]
// Echoed coil value = uint16BE @ 4; bytes 6-7 are the CRC, never use them for verification.
let appInfo = [{field_name: "ry1", index: 4, type: "uint16BE", val: checkVal}];
let checkInfo = {
    frameInfo: {port: 51, dataLen: dnBuffer.length},
    appInfo: appInfo,
    // telemetry_data.ry1 is numeric 0/1 (telemetry model ry1 type:number);
    // shared_attrs.ry1 is boolean (form switch_ry1 type:boolean, populated with same type, KB-21).
    telemetry_data: {ry1: on},
    server_attrs: null,
    shared_attrs: {ry1: params.switch_ry1}
};
let msgQue = Utils.makeParaSetMSG({
    msgType: Utils.msgType.transParent,
    checkInfo: checkInfo,
    device: device,
    classMode: classMode,
    rpcName: rpcName,
    params: params,
    paraDownBuffer: dnBuffer,
    timeout: 3000,
    maxRetries: 3
});
if (msgQue.length === 0) return null;
return msgQue;

Control logic description:

ItemDescription
Modbus Function Code05 (single channel, single frame)
Control ObjectOne relay channel (one per RPC)
ON Value0xFF00
OFF Value0x0000
Form Fieldsswitch_ryN (boolean, one per RPC)
Coil Addresschannel − 1 (ry1→0 … ry5→4)
Write-back on Successtelemetry ryN + shared attribute ryN (for form populate)

10. Template Selection

Search for the following template in the ThinkLink platform:

latex
SWMx-22108

Or search by business type:

latex
22108

Recommended template information:

ItemDescription
Template NameSWMx-22108
Device TypeDIDO Controller
ManufacturerJSDZ
Business Code22108
Access MethodKC11 + RS-485 + EdgeBus + LoRaWAN
Data UploadRY status, DI status
Control CapabilityRelay RPC control supported
Parameter ConfigurationUpload period, acquisition period, and Modbus address configuration supported

11. Integration Summary

This solution connects the SWMx DIDO controller to the IoT platform through KC11 + EdgeBus + LoRaWAN + ThinkLink.

Key features:

  1. KC11 connects to SWMx through RS-485.
  2. EdgeBus uses Modbus function code 01 to read RY status.
  3. EdgeBus uses Modbus function code 02 to read DI status.
  4. Function codes 01 / 02 read data by bit, and EBHelper already handles the differences from function codes 03 / 04 at the lower layer.
  5. RY and DI statuses are uploaded as 2-byte HEX strings.
  6. The platform parses RY1–RY5 and DI1–DI5 status at the same time.
  7. RPC is supported for modifying the upload period, acquisition period, and Modbus address.
  8. Each relay channel has its own dedicated RPC (swm_ry1_action_22108~swm_ry5_action_22108), controlling that relay through Modbus function code 05, with state written back to shared attributes for form populate.

This solution is suitable for quickly upgrading traditional RS-485 DIDO controllers into LoRaWAN wireless devices and connecting them to ThinkLink for remote monitoring, remote control, and third-party platform data subscription.