
1. 传感器简介
DSOD705 是一款 非接触式水面溢油检测传感器 ,由地森合志 / DISEN 提供。设备基于 紫外荧光检测原理,通过向水面发射紫外脉冲,激发油类物质产生荧光,并通过光电接收与数据处理模块判断水面是否存在油污。
该传感器主要用于实时检测水面油污、漏油、溢油和浮油,可检测原油、柴油、燃料油、机油、润滑油、汽油、航空煤油等多种石油类物质。设备支持 RS-485 / Modbus RTU 输出,可通过 KC11 采集器接入 LoRaWAN 网络,再由 ThinkLink 平台完成数据解析、展示、告警和第三方系统转发。
2. 产品特点
DSOD705 的主要特点如下:
- 非接触式检测
传感器安装在水面上方,无需直接接触被测水体,可减少油污附着、生物附着和人工清洗维护。 - 紫外荧光检测原理
利用油类物质的天然荧光特性进行检测,适合识别水面石油类污染物。 - 高灵敏度
可检测低至约 1 μm 厚度的油膜,适合早期溢油预警。 - 全天候在线监测
支持 24 小时连续监测,不受白天或夜晚光照条件限制。 - RS-485 / Modbus RTU 输出
便于接入工业现场采集系统、监控系统或通过 KC11 转换为 LoRaWAN 上报。 - 支持报警联动
设备本体支持继电器输出,可用于本地报警或联动控制。 - 高防护等级
说明书中描述设备具有 IP66/IP67 或 IP68 高防护能力,适合户外和复杂工业环境使用。 - 低功耗运行
设备功耗低,说明书中标注直流功耗小于 2 W,部分说明中也提到低功耗运行小于 10 W。
3. 适用范围
DSOD705 适用于工业与环境领域的水面油污在线监测,典型应用场景包括:
- 石油开采企业
- 船舶
- 海上平台
- 港口码头
- 石油化工厂
- 储油站、油库
- 电力站 / 发电厂
- 气体压缩站
- 污水处理厂
- 河道、湖泊
- 工业排水口
- 水环境安全监测场景
4. 采集器信息
4.1 硬件信息
本方案采用 KC11 作为 RS-485 数据采集与 LoRaWAN 接入设备。
|--------|--------------------------|
| 项目 | 内容 |
| 采集设备型号 | KC11 |
| 接口类型 | RS-485 |
| 上行通信 | LoRaWAN |
| 供电方式 | 220 V 供电 |
| 接入传感器 | DSOD705 水面溢油检测传感器 |
| 协议 | Modbus RTU |
| 默认串口参数 | 9600 bps,8 数据位,1 停止位,无校验 |
4.2 接线信息
电源与通讯接口
DSOD705 传感器线缆定义如下:
|------|------------------|
| 线色 | 功能 |
| 红色线 | 电源 +,+24 VDC |
| 黑色线 | 电源 -,GND |
| 黄绿色线 | RS-485 A / 485_A |
| 白色线 | RS-485 B / 485_B |
| 蓝色线 | 继电器 + |
| 绿色线 | 继电器 - |
| 棕色线 | 4-20 mA + |
| 灰色线 | 4-20 mA - |
| 裸露线 | 屏蔽层 |
本方案中主要使用以下接口:
|------------|-------------------|
| DSOD705 | KC11 / 外部电源 |
| 红色线 +24 V | 外部 24 VDC 电源正极 |
| 黑色线 GND | 外部 24 VDC 电源负极 |
| 黄绿色线 485_A | KC11 RS-485 A |
| 白色线 485_B | KC11 RS-485 B |
| 屏蔽层 | 建议接地或按现场 EMC 要求处理 |
传感器接口
本方案使用 DSOD705 的 RS-485 / Modbus RTU 接口进行数据采集。
4-20 mA 和继电器接口在本方案中不作为主要数据采集链路使用,可根据现场需求独立接入本地控制或报警系统。
5. 数据采集
本方案中,通过 Modbus 读取以下寄存器:
|------|------|--------|-------|----------------------------|-----------|
| 采集内容 | 功能码 | 起始地址 | 寄存器数量 | 数据类型 | 说明 |
| 传感器值 | 0x04 | 0x0000 | 2 | Float,DCBA / Little Endian | 读取水面溢油检测值 |
KC11 通过 EdgeBus 逻辑周期性读取 DSOD705 的输入寄存器 0x0000 ~ 0x0001,读取结果按照 FloatLE 方式解析,并作为 oil 字段上报至 ThinkLink。
5.1 寄存器定义
只读寄存器
|--------|----|----|-------------|--------------|
| 寄存器地址 | 长度 | 读写 | 数据类型 | 内容说明 |
| 0x0000 | 2 | R | Float(DCBA) | 读取传感器值 |
| 0x0001 | 2 | R | Float(DCBA) | 读取传感器温度 |
| 0x0010 | 6 | R | ASCII-HEX | 读取传感器 SN 值 |
| 0x0016 | 2 | R | HEX | 读取传感器硬件和软件版本 |
注:对接代码中实际读取的是 0x0000 ~ 0x0001,即读取 2 个寄存器组成一个浮点数,用于得到油污检测值。
保持寄存器
|--------|----|-----|-------------|----------------------------------------------------|
| 寄存器地址 | 长度 | 读写 | 数据类型 | 内容说明 |
| 0x0000 | 1 | R/W | Short | 读取 / 设置当前传感器地址,范围 1-247 |
| 0x0001 | 1 | R/W | Short | 波特率:0=4800,1=9600,2=19200,3=56000,4=57600,5=115200 |
| 0x0002 | 1 | R/W | Short | 检测间隔时间,单位 ms |
| 0x0006 | 2 | R/W | Float(DCBA) | 传感器到水面距离,单位 m |
| 0x0010 | 1 | R/W | Short | 继电器控制开关,0=关闭,1=开启 |
| 0x0012 | 2 | R/W | Float(DCBA) | 继电器控制最大值 |
| 0x0014 | 2 | R/W | Float(DCBA) | 继电器控制最小值 |
| 0x0016 | 2 | R/W | Float(DCBA) | 继电器动作延迟时间,单位 ms |
| 0x0020 | 1 | R/W | Short | 4-20 mA 输出模式 |
| 0x0022 | 2 | R/W | Float(DCBA) | 电流 4 mA 对应传感器值 |
| 0x0024 | 2 | R/W | Float(DCBA) | 电流 20 mA 对应传感器值 |
| 0x0026 | 1 | R/W | Short | 电流 4 mA 校准值,范围 7900-9900 |
| 0x0027 | 1 | R/W | Short | 电流 20 mA 校准值,范围 1700-3700 |
| 0x0030 | 2 | R/W | Float(DCBA) | 传感器 K 值 |
| 0x0032 | 2 | R/W | Float(DCBA) | 传感器 B 值 |
5.2 状态位定义
本方案中,EdgeBus / PayloadParser 会产生状态字段 status。当前脚本中使用以下状态判断:
|------|----------------------------|-------------|
| 状态位 | 判断方式 | 含义 |
| bit1 | (status & 0x02) === 0x02 | Modbus 采集超时 |
当检测到超时状态时,物模型脚本会保留设备上一帧遥测数据,仅更新 status 状态字段,避免因本次采集超时导致平台侧业务数据被清空。
6. EdgeBus 模型
DSOD705 本身是 RS-485 / Modbus RTU 传感器,不是原生 LoRaWAN 设备,因此需要通过 KC11 内置 EdgeBus 逻辑完成 Modbus 采集和 LoRaWAN 上报。
6.1 EB 配置参数
|----------------|------------------|
| 参数 | 值 |
| EB 名称 | dsod705 |
| LoRaWAN Port | 22 |
| Version | 0x86 |
| DataType | 0x07 |
| 业务代码 BzType | 22107 |
| 业务版本 BzVersion | 11 |
| 串口波特率 | 9600 |
| 数据位 | 8 |
| 停止位 | 1 |
| 校验位 | NONE |
| Modbus 功能码 | 0x04 |
| Modbus 地址 | 保存于 APP 参数地址 150 |
| 上传周期参数 | APP 参数地址 70 |
| 采集周期参数 | APP 参数地址 74 |
| COV 参数 | APP 参数地址 110 |
| 采集寄存器 | 0x0000 ~ 0x0001 |
| COV 类型 | FloatLE |
参数说明:
- 上传周期和采集周期分开设置。
- 上传周期保存在 APP 参数地址
70。 - 采集周期保存在 APP 参数地址
74。 - 需要保证采集周期小于上传周期。
- COV 参数保存在 APP 参数地址
110。 - Modbus 地址保存在 APP 参数地址
150。
6.2 EB 代码
import {Buffer} from "buffer";
import {buildOtaFile} from "@EBSDK/run";
import {EBModel, EventInfoItem, LoraUpEvent, UpgrdTypeEnum, UserConfUPItem} from "@EBSDK/EBCompiler/all_variable";
import {CheckbitEnum, getOtaConfig, HwTypeEnum} from "@EBSDK/otaConfig";
////////////////////////////////////////////////////////////////////////////////////////
const eventInfo:UserConfUPItem[]=[
{
name:"dsod705",
port:22,
version:"0x86",
dataType:"0x07",
upPeriodIndex:70,
quInfo:[
{
protocol:"modbus",
code:"0x04",
periodIndex:74,
// addr:"0x01",
indexAPP:150,
indexCMD:0,
copySize:1,
isLast:false,
// period:"900s",
// payIndex:3,
// ackAddrIndex:0,
listVal:[
{
start: "0x0000",
end: "0x0001",
covType:"FloatLE",
covAppIndex:110
},
]
}
]
}
]
let otaConfig = getOtaConfig({
BaudRate: 9600,
StopBits: 1,
DataBits: 8,
Checkbit: CheckbitEnum.NONE,
Battery: false,
ConfirmDuty: 60,
BzType: 22107,
BzVersion: 11
})
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 说明
当前 EB 逻辑说明:
- KC11 通过 RS-485 接口与 DSOD705 通信。
- 串口参数为
9600, 8N1,即 9600 bps、8 数据位、1 停止位、无校验。 - EB 逻辑使用 Modbus 功能码
0x04读取输入寄存器。 - 读取地址范围为
0x0000 ~ 0x0001,共 2 个寄存器,用于解析一个 FloatLE 数据。 - 采集结果作为溢油检测值,通过 LoRaWAN Port 22 上报。
- 上传周期由 APP 参数地址
70控制。 - 采集周期由 APP 参数地址
74控制。 - COV 变化阈值由 APP 参数地址
110控制。 - Modbus 从站地址由 APP 参数地址
150控制。 - 业务代码为
22107,业务版本为11。
7. 物模型
7.1 物模型基本信息
数据物模型
|--------------|------------|
| 项目 | 内容 |
| 名称 | DSOD705 |
| id Name | dsod_22107 |
| LoRaWAN Port | 22 |
| 数据长度 | 16 |
| RSSI | 支持 |
| 电池字段 | index 4 |
| 业务标识 Tag | 0x86 |
| 数据类型 Tag | 0x07 |
参数物模型
|-----------|------------------------|
| 项目 | 内容 |
| 名称 | DSOD705-PARA |
| id Name | dsod705_para_22107 |
| 参数上报 Port | 214 |
| RPC 名称 | dsod705_set_para_22107 |
7.2 上行帧结构
数据上行帧
|---------|-----------------------|
| 字节位置 | 内容 |
| index 0 | Tag:0x86 |
| index 1 | Tag:0x07 |
| index 4 | Battery |
| index 6 | oil,FloatLE |
| 其他 | EdgeBus 状态、RSSI 等辅助字段 |
数据字段定义:
|-----|------------|----|-------|---------|----|-----|
| 字段名 | field_name | 单位 | index | 类型 | 系数 | 小数位 |
| oil | oil | % | 6 | floatLE | 1 | 2 |
参数字段定义
|----------|-------------|-------------|----|----------|--------------|
| APP 参数地址 | 字段名 | field_name | 单位 | 类型 | 说明 |
| 70 | period_up | period_up | S | uint32le | 上传周期 |
| 74 | period_read | period_read | S | uint32le | 采集周期 |
| 110 | cov_oil | cov_oil | % | floatLE | 溢油检测值 COV 阈值 |
| 150 | addr_modbus | addr_modbus | | uint8 | Modbus 从站地址 |
7.3 物模型脚本
数据物模型脚本
let port = msg?.userdata?.port || null;
if (port != 22) return null
let frameInfo = {
port: 22,
dataLen: 16,
rssi: true,
battery: 4,
tagList: [
{ index: 0, tag: 0x86 },
{ index: 1, tag: 0x07 }
]
}
let appInfo = [
{
name: "oil",
field_name: "oil",
unit: "%",
index: 6,
type: "floatLE",
coefficient: 1,
decimal: 2
},
]
let payParser = new PayloadParser({
device: device,
msg: msg,
frameInfo: frameInfo,
appInfo: appInfo,
})
let tdata = payParser.telemetry()
if (tdata == undefined) {
return null
}
if ((tdata?.status & 0x02) === 0x02) { // time out, just update the status.
const status = tdata.status
tdata = { ...(device.telemetry_data?.[thingModelId] ?? {}) }
tdata.status = status
}
return {
telemetry_data: tdata,
server_attrs: null,
shared_attrs: null
}
参数物模型脚本
let port = msg?.userdata?.port || null;
const rpcName = "dsod705_set_para_22107";
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_110: {
name: "cov_oil",
field_name: "cov_oil",
unit: "%",
type: "floatLE",
decimal: 1
},
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,
action: checkData.action,
}
}
let pdata = (new PayloadParser({
device: device,
msg: msg,
paraInfo: paraDef,
})).paras()
let checkData = Utils.paraCheck(rpcName, pdata)
return {
telemetry_data: pdata,
server_attrs: checkData.sdata,
shared_attrs: pdata,
action: checkData.action,
}
8. 第三方平台数据订阅
8.1 MQTT Topic
/v32/{Organization Account}/tkl/up/telemetry/{eui}
8.2 上报示例数据
{
"eui": "6353012af10a9331",
"active_time": "2026-02-05T08:35:48.000Z",
"thingModelId": "dsod_22107",
"thingModelIdName": "DSOD705",
"telemetry_data": {
"snr": 13.5,
"rssi": -51,
"battery": 3.37,
"oil": 12.34,
"status": 0
}
}
字段说明:
|------------------|-----------------------|
| 字段 | 含义 |
| eui | LoRaWAN 终端 EUI |
| active_time | 数据上报时间 |
| thingModelId | 物模型 ID |
| thingModelIdName | 物模型名称 |
| snr | LoRaWAN 信噪比 |
| rssi | LoRaWAN 信号强度 |
| battery | 设备电池 / 电源状态字段 |
| oil | DSOD705 溢油检测值,单位 % |
| status | EdgeBus / Modbus 采集状态 |
9. RPC
9.1 RPC 名称
本方案包含两个 RPC:
|--------|------------------|-------------------|
| RPC 功能 | 名称 | id Name |
| 设置参数 | DSOD705 SET para | dsod705_set_22107 |
| 读取参数 | DSOD705 GET para | dsod705_get_22107 |
其中设置参数使用的内部 RPC 名称为:
dsod705_set_para_22107
9.2 参数定义
|-------------|-------------|--------|----|----------|--------------|
| 参数 | field_name | APP 地址 | 单位 | 类型 | 说明 |
| period_up | period_up | 70 | S | uint32le | 上传周期 |
| period_read | period_read | 74 | S | uint32le | 采集周期 |
| cov_oil | cov_oil | 110 | % | floatLE | 油污检测值 COV 阈值 |
| addr_modbus | addr_modbus | 150 | | uint8 | Modbus 从站地址 |
参数设置建议:
period_read应小于period_up。addr_modbus应与 DSOD705 传感器实际 Modbus 地址一致。cov_oil用于控制油污检测值变化上报阈值,可根据现场油污检测灵敏度需求配置。
9.3 RPC 代码
设置参数 RPC
let classMode = (device && device.shared_attrs && device.shared_attrs.class_mode) || "ClassA";
const rpcName = "dsod705_set_para_22107"
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_110: {
name: "cov_oil",
field_name: "cov_oil",
unit: "%",
type: "floatLE",
decimal: 1
},
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
读取参数 RPC
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_110: {
name: "cov_oil",
field_name: "cov_oil",
unit: "%",
type: "floatLE",
decimal: 1
},
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: 0,
})
return [msg]
10. 模板选择
在 ThinkLink 平台中搜索模板:
DSOD705
或搜索物模型 id Name:
dsod_22107
参数物模型可搜索:
dsod705_para_22107
RPC 可搜索:
dsod705_set_22107
dsod705_get_22107
或按业务类型查找:
水面溢油检测
非接触式溢油检测
RS-485 溢油传感器
Modbus RTU 水质 / 环境监测
LoRaWAN 工业传感器接入