产品定价 立即试用
云平台
欧洲地区
文档 > 集成 > TCP
入门
指南 API 常见问题
目录

TCP集成

文档信息图标
ThingsBoard PE 功能

专业版支持Platform Integrations功能。
请使用ThingsBoard Cloud自行安装平台实例。

TCP集成可从采用TCP传输协议的设备向ThingsBoard流式传输数据,并将这些设备的负载转换为ThingsBoard格式。

文档信息图标

请注意:TCP集成只能以远程集成方式启动。可在运行TB实例的同一台机器上启动,也可在能通过网络访问TB实例的另一台机器上启动。

请参阅集成示意图了解更多。

image

前置条件

本教程将使用:

  • ThingsBoard Professional Edition实例 — eu.thingsboard.cloud;

  • 在外部运行且已连接云端ThingsBoard PE实例的TCP集成;
  • echo命令,用于显示一行文本并将其输出重定向到netcatnc)工具;
  • netcatnc)工具,用于建立TCP连接、接收数据并传输;

假设我们有一台正在发送当前温度和湿度读数的传感器。 传感器设备SN-002将其温度和湿度读数发布到运行TCP集成的机器的10560端口。

为便于演示,我们假设设备能够以3种不同负载类型发送数据:

可根据设备能力和业务场景选择负载类型:

此情况下,payload 格式如下:

1
SN-002,default,temperature,25.7\n\rSN-002,default,humidity,69

此情况下,payload 格式如下:

1
2
3
4
5
6
7
8
[
  {
    "deviceName": "SN-002",
    "deviceType": "default",
    "temperature": 25.7,
    "humidity": 69
  }
]

此情况下,payload 格式如下:

1
\x30\x30\x30\x30\x11\x53\x4e\x2d\x30\x30\x32\x64\x65\x66\x61\x75\x6c\x74\x32\x35\x2e\x37\x00\x00\x00

该 payload 中各字节说明如下:

  • 0-3 字节 - \x30\x30\x30\x30 - 占位字节,用于演示如何跳过 payload 中的前缀字节;
  • 4 字节 - \x11 - payload 长度,转为十进制为 17,即本例 payload 从入站 TCP 帧中取 17 字节;
  • 5-10 字节 - \x53\x4e\x2d\x30\x30\x32 - 设备名称,转为文本为 SN-002
  • 11-17 字节 - \x64\x65\x66\x61\x75\x6c\x74 - 设备类型,转为文本为 default
  • 18-21 字节 - \x32\x35\x2e\x37 - 温度遥测,转为文本为 25.7
  • 22-24 字节 - \x00\x00\x00 - 占位字节,因 payload 大小为 17 字节(第 521 字节)将忽略;
文档信息图标

请注意
在运行TCP集成的机器上,必须开放10560端口以接收入站连接——nc工具需能连接到TCP socket。若在本地运行,一般无需额外修改。

添加TCP集成

1.基本设置

进入“Integrations center”的“Integrations”页面,点击“plus”按钮开始添加新集成。选择“TCP”类型并点击“Next”;

image


2.上行数据转换器

上行转换器是用于解析并将TCP集成接收的数据转换为ThingsBoard可消费格式的脚本。 deviceNamedeviceType为必填,attributestelemetry为可选。attributestelemetry为扁平键值对象,不支持嵌套对象。

选择设备负载类型以配置解码器:

可使用 TBEL(TBEL)或 JavaScript 开发用户自定义函数。 建议使用 TBEL,其在ThingsBoard 中的执行效率远高于 JS。

请复制以下 TBEL 脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/** Decoder **/

// decode payload to string
var strArray = decodeToString(payload);
var payloadArray = strArray.replaceAll("\"", "").replaceAll("\\\\n", "").split(',');

var telemetryPayload = {};
for (var i = 2; i < payloadArray.length; i = i + 2) {
    var telemetryKey = payloadArray[i];
    var telemetryValue = parseFloat(payloadArray[i + 1]);
    telemetryPayload[telemetryKey] = telemetryValue;
}

// Result object with device attributes/telemetry data
var result = {
    deviceName: payloadArray[0],
    deviceType: payloadArray[1],
    telemetry: telemetryPayload,
    attributes: {}
};

/** Helper functions 'decodeToString' and 'decodeToJson' are already built-in **/

return result;


若使用 JavaScript decoder function,请使用以下脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/** Decoder **/

// decode payload to string
var strArray = decodeToString(payload);
var payloadArray = strArray.replace(/\"/g, "").replace(/\s/g, "").split(',');

var telemetryKey = payloadArray[2];
var telemetryValue = payloadArray[3];

var telemetryPayload = {};
telemetryPayload[telemetryKey] = telemetryValue;

// Result object with device attributes/telemetry data
var result = {
    deviceName: payloadArray[0],
    deviceType: payloadArray[1],
    telemetry: telemetryPayload,
    attributes: {}
};

/** Helper functions **/

function decodeToString(payload) {
    return String.fromCharCode.apply(String, payload);
}

return result;


将复制的脚本粘贴到 decoder function 区域,然后点击「Next」;

image

可使用 TBEL(TBEL)或 JavaScript 开发用户自定义函数。 建议使用 TBEL,其在ThingsBoard 中的执行效率远高于 JS。

请复制以下 TBEL 脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/** Decoder **/

// decode payload to JSON
var data = decodeToJson(payload);

// Result object with device/asset attributes/telemetry data

var deviceName = data.deviceName;
var deviceType = data.deviceType;
var result = {
    deviceName: deviceName,
    deviceType: deviceType,
    attributes: {},
    telemetry: {
        temperature: data.temperature,
        humidity: data.humidity
    }
};

/** Helper functions 'decodeToString' and 'decodeToJson' are already built-in **/

return result;


若使用 JavaScript decoder function,请使用以下脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/** Decoder **/

// decode payload to JSON
var data = decodeToJson(payload);

// Result object with device/asset attributes/telemetry data

var deviceName = data.deviceName;
var deviceType = data.deviceType;
var result = {
    deviceName: deviceName,
    deviceType: deviceType,
    attributes: {},
    telemetry: {
        temperature: data.temperature,
        humidity: data.humidity
    }
};

/** Helper functions **/

function decodeToString(payload) {
    return String.fromCharCode.apply(String, payload);
}

function decodeToJson(payload) {
    // covert payload to string.
    var str = decodeToString(payload);

    // parse string to JSON
    var data = JSON.parse(str);
    return data;
}

return result;


将复制的脚本粘贴到 decoder function 区域,然后点击「Next」;

image

可使用 TBEL(TBEL)或 JavaScript 开发用户自定义函数。 建议使用 TBEL,其在ThingsBoard 中的执行效率远高于 JS。

请复制以下 TBEL 脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/** Decoder **/

// decode payload to string
var payloadStr = decodeToString(payload);

// decode payload to JSON
// var data = decodeToJson(payload);

var deviceName = payloadStr.substring(0,6);
var deviceType = payloadStr.substring(6,13);

// Result object with device/asset attributes/telemetry data
var result = {
    deviceName: deviceName,
    deviceType: deviceType,
    attributes: {},
    telemetry: {
        temperature: parseFloat(payloadStr.substring(13,17))
    }
};

/** Helper functions 'decodeToString' and 'decodeToJson' are already built-in **/

return result;


若使用 JavaScript decoder function,请使用以下脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/** Decoder **/

// decode payload to string
var payloadStr = decodeToString(payload);

// decode payload to JSON
// var data = decodeToJson(payload);

var deviceName = payloadStr.substring(0,6);
var deviceType = payloadStr.substring(6,13);

// Result object with device/asset attributes/telemetry data
var result = {
   deviceName: deviceName,
   deviceType: deviceType,
   attributes: {},
   telemetry: {
       temperature: parseFloat(payloadStr.substring(13,17))
   }
};

/** Helper functions **/

function decodeToString(payload) {
   return String.fromCharCode.apply(String, payload);
}

function decodeToJson(payload) {
   // covert payload to string.
   var str = decodeToString(payload);

   // parse string to JSON
   var data = JSON.parse(str);
   return data;
}

return result;


将复制的脚本粘贴到 decoder function 区域,然后点击「Next」;

image

文档信息图标

注意
尽管Debug mode对开发和故障排查很有用,但在生产模式下长期启用会大幅增加数据库占用的磁盘空间,因所有调试数据都会存储其中。强烈建议调试完成后关闭Debug mode。

3.下行数据转换器

在添加下行转换器步骤,可选择已有或新建下行转换器。此处保持“Downlink data converter”为空。点击“Skip”;

image


4.连接

如前所述,“Execute remotely”选项已勾选且不可修改——TCP集成只能为remote类型。

默认情况下TCP集成使用10560端口,您可根据需要改为任意可用端口。

请记录Integration keyIntegration secret——后续在远程TCP集成配置中将使用这些值。

选择Handler Configuration的设备负载类型

image

为正确解析 payload,请确保设置以下值:

  • Max Frame Length:解码帧的最大长度,超出此值将抛出异常;本示例保持默认 128 即可;
  • Strip Delimiter:是否从解码帧中去除分隔符;勾选后将从 payload 中去掉换行符;
  • Message Separator:指定为 System Line Separator,此时将使用换行符作为分隔符;

image

image


image

image

为正确解析 payload,请确保设置以下值:

  • Max Frame Length:解码帧的最大长度,超出此值将抛出异常;本示例保持默认 128 即可;
  • Length Field Offset:length 字段的偏移。本例中 length 字段为 payload 的第 5 字节 \x30\x30\x30\x30 \x11 \x53…,设为 4
  • Length Field Length:length 字段的长度。本例为 1 字节 …\x30 \x11 \x53…,设为 1
  • Length Adjustment:length 字段的补偿值。本例 length 字段为 17 字节,无需补偿,保持 0
  • Number of first bytes to strip out from the decoded frame:从解码帧中去除的首字节数。需跳过前 5 字节以获取数据 \x30\x30\x30\x30\x11 \x53\x4e\x2d\x30…,设为 5

image

其他选项保持默认,简要说明如下:

  • Max number of pending connects on the socket — 入站连接请求队列的最大长度。若队列已满时收到连接请求,连接将被拒绝;
  • Size of the buffer for inbound socket — socket数据接收缓冲区的KB大小;
  • Size of the buffer for outbound socket — socket数据发送缓冲区的KB大小;
  • Enable sending of keep-alive messages on connection-oriented sockets — 标识是否定期向对端socket发送探测以保持连接存活;
  • Forces a socket to send the data without buffering (disable Nagle’s buffering algorithm) — 禁用socket上的Nagle算法,该算法会延迟发送直到累积一定数据量。

点击“Add”完成TCP集成添加。

安装并运行外部TCP集成

请参阅远程集成指南,在本地或单独机器上安装TCP集成服务。

请使用上文中的Integration keyIntegration secret配置您的TCP集成。

发送上行消息

创建ThingsBoard TCP集成后,TCP服务启动并等待设备数据。

选择设备负载类型以发送上行消息

进入“Devices”页面,应能看到由TCP集成配置的SN-002设备。 点击设备,进入“Latest telemetry”标签可查看“temperature”键及其值(25.7)。

image

若负载包含“humidity”遥测,也应能看到“humidity”键及其值(69)。

高级用法:下行

要从ThingsBoard向设备发送下行消息,需定义下行转换器。

添加下行转换器

以下示例为发送属性更新消息。可使用我们的示例下行转换器,或根据您的配置自行编写。

可使用 TBEL(TBEL)或 JavaScript 开发用户自定义函数。 建议使用 TBEL,其在ThingsBoard 中的执行效率远高于 JS。

将下行数据转换器添加到TCP集成的步骤:

  • 进入“Integrations”页面,点击TCP集成打开详情,点击“pencil”图标进入编辑模式;

  • 输入下行数据转换器名称并点击“Create new converter”;

  • 将脚本粘贴到encoder function区域,点击“Add”;

  • 应用更改。

文档信息图标

可选配置Cache SizeCache time to live in minutes——用于在存储连接时避免内存泄漏(仅TCP下行支持)。
Cache Size — TCP客户端消息的最大数量。
Cache time to live in minutes — 消息存储时长(分钟)。

修改Root Rule Chain

集成配置就绪后,需进入“Rule Chains”页面并配置“Root Rule Chain”,使“Attributes updated”消息转发到下行数据转换器。

  • 打开“Root Rule Chain”,找到“integration downlink”节点并拖入规则链。命名为“TCP integration downlink”,指定TCP integration,点击“Add”;

  • 此后,点击“message type switch”规则节点右侧灰色圆圈,拖拽到“integration downlink”左侧,选择Attributes Updated,点击“Add”并保存Root Rule Chain。

测试下行

要测试下行,请在设备上创建shared attribute

  • 进入“Devices”页面。点击SN-002设备,进入“Attributes”标签。选择“Shared attributes”,点击“plus”图标;

  • 输入属性名及其值(例如键名为“firmware”、值为“v1.1”)并点击“Save”;

要接收下行消息,需设置响应超时-w60(该选项决定等待响应的时长)并再次发送上行消息:

1
echo -e 'SN-002,default,temperature,25.7\nSN-002,default,humidity,69' | nc -w60 127.0.0.1 11560

终端中应能看到ThingsBoard的如下响应:

image

接收和发送的数据可在下行转换器中查看。在“Events”标签的“In”块中查看入站数据,“Out”字段显示发给设备的消息。

文档信息图标

注意
使用TCP集成且连接建立较长时间时,您将只收到一条下行消息。其余消息将保存在服务端,并在下次上行时发送。

下一步