ThingsBoard允许您在服务端应用与设备之间进行远程过程调用(RPC)的双向通信。 简而言之,该功能允许您向设备发送命令或从设备接收命令,并获取命令执行结果。 本指南介绍ThingsBoard的RPC能力。阅读后将熟悉以下主题:
- RPC类型;
- 基本RPC使用场景;
- RPC客户端与服务端API;
- RPC部件。
ThingsBoard的RPC功能可根据远程过程调用的发起方分为两种类型:设备发起和服务端发起的RPC。 为便于理解,我们将设备发起的RPC调用称为客户端RPC,服务端发起的RPC称为服务端RPC。
客户端RPC
客户端RPC功能允许您从设备向平台发送请求,并将响应返回给设备。
让我们了解客户端RPC调用的典型使用场景:
- 灌溉系统通过平台从在线服务获取天气预报。
- 无系统时钟的受限设备向平台请求当前时间戳。
- 门禁读卡器向第三方安防系统发送请求,以决定是否开门并记录访问。
在底层,设备向平台发送消息,由规则引擎处理。 规则引擎可使用设备属性、遥测数据或平台中存储的任何其他数据进行计算。 规则引擎也可在需要时调用外部系统。消息处理完成后,结果将发送回设备。 如下图所示:
客户端RPC请求包含两个必填字段:
- method - 用于区分RPC调用的方法名称。 例如 “getCurrentTime” 或 “getWeatherForecast”。该参数值为字符串。
- params - 用于处理请求的额外参数。值为JSON。若无需参数则使用空JSON “{}”。
RPC请求示例:
1
2
3
4
{
"method": "getCurrentTime",
"params": {}
}
RPC响应可以是任意数字、字符串或JSON。例如:
1
1631881236974
从设备发送客户端RPC
ThingsBoard提供从设备发送RPC命令的API。 该API针对每种支持的网络协议有专门实现。 您可在相应参考页面查看API及示例:
LwM2M和SNMP协议尚不支持客户端RPC。
平台对客户端RPC的处理
客户端RPC命令会转换为规则引擎消息,消息类型为 “TO_SERVER_RPC_REQUEST”。 消息包含基于UUID的唯一标识符,存储在 “requestId” 元数据字段中。 您可以设计规则链, 使用转换、丰富或其他规则节点类型处理传入消息。 将传入消息转换为响应消息后,应使用RPC调用回复节点向设备发送回复。
例如,修改根规则链以处理 “getCurrentTime” 客户端RPC并以毫秒级当前时间回复。 我们将使用 “Script” 转换节点配合以下JavaScript代码:
1
2
3
4
5
6
7
var rpcResponse;
if (msg.method === "getCurrentTime"){
rpcResponse = new Date().getTime();
} else {
rpcResponse = "Unknown RPC request method: " + msg.method;
}
return {msg: rpcResponse, metadata: metadata, msgType: msgType};
服务端RPC
服务端RPC功能允许您从平台向设备发送请求,并可选择将响应返回平台。
服务端RPC调用的典型场景包括各类远程控制: 重启、开关引擎、改变GPIO/执行器状态、修改配置参数等。
服务端RPC分为单向和双向:
-
单向RPC请求不需要设备提供任何回复。
-
双向RPC请求期望在可配置的超时时间内收到设备的响应。
3.3版本之前,ThingsBoard仅支持轻量级RPC。 轻量级RPC调用生命周期短,通常在30秒内(即平台REST API调用的默认超时)。 因其短暂,无需存入数据库。 它们保存在服务端内存中,假设若服务端宕机,仪表板部件会向集群中的其他ThingsBoard服务端发送相同请求。 轻量级RPC资源消耗低,因其处理不涉及除审计日志和规则引擎消息之外的任何I/O操作。
自3.3版本起,ThingsBoard支持持久化 RPC调用。 持久化RPC具有可配置的生命周期并存储在数据库中。 当设备可能长期不可达时,持久化RPC尤为有用。 这种情况通常发生在网络状况差或处于省电模式(PSM)时。
服务端RPC结构
服务端RPC请求体包含多个字段:
- method - 必填,用于区分RPC调用的方法名称。例如 “getCurrentTime” 或 “getWeatherForecast”。参数值为字符串。
- params - 必填,用于处理请求的参数。值为JSON。若无参数则使用空JSON “{}”。
- timeout - 可选,处理超时毫秒数。默认10000(10秒)。最小5000(5秒)。
- expirationTime - 可选,纪元时间毫秒数(UTC)。若存在则覆盖 timeout。
- persistent - 可选,参见[持久化]与[轻量级]RPC。默认为 “false”。
- retries - 可选,定义网络和/或设备侧失败时持久化RPC的重发次数。
- additionalInfo - 可选,定义将添加至[持久化RPC事件]的持久化RPC元数据。
RPC请求示例:
1
2
3
4
5
6
7
8
{
"method": "setGPIO",
"params": {
"pin": 4,
"value": 1
},
"timeout": 30000
}
RPC响应可以是任意JSON。例如:
1
2
3
4
5
{
"pin": 4,
"value": 1,
"changed": true
}
发送服务端RPC
服务端RPC通常通过REST API或仪表板部件发送。实际上,仪表板部件使用的是同一REST API。 平台收到RPC后会验证载荷并执行权限检查。 随后,服务端RPC命令被转换为规则引擎消息。 规则引擎可为命令添加额外参数,并最终将命令下发至设备。
下面详细说明如何发送命令:
使用REST API
要发送RPC请求,需向以下URL发起HTTP POST请求:
1
http(s)://host:port/api/plugins/rpc/{callType}/{deviceId}
其中
- http(s)://host:port 为ThingsBoard服务器基础URL。例如eu.thingsboard.cloud
- callType 为 oneway 或 twoway;
- deviceId 为目标设备ID。
请求体应为上文所述RPC请求对象的有效JSON。
For example:
|
|
请注意,要执行此请求,需将 $JWT_TOKEN 替换为有效的JWT访问令牌。 该令牌应属于拥有 $DEVICE_ID 所标识设备的 TENANT_ADMIN 或 CUSTOMER_USER 角色用户。 请使用以下指南获取令牌。
用户通过REST API发送轻量级RPC时,API调用会包含设备回复或错误码。例如:
1
2
3
4
5
{
"pin": 4,
"value": 1,
"changed": true
}
用户通过REST API发送持久化RPC时,响应会包含唯一标识符 “rpcId”。例如:
1
2
3
{
"rpcId": "b10bb1a0-0afd-11ec-a08f-1b3182194747"
}
您可使用此标识符跟踪命令状态。详见持久化RPC 状态。
使用仪表板
控制部件用于向设备发送RPC命令。 最常用的部件有 “RPC按钮”、”圆形开关”、”开关控件” 和 “旋钮控件”。 这些部件的高级设置允许您定义RPC方法名和参数。 您也可开发自定义部件并使用控制API发送RPC命令。
使用规则引擎
所有从部件或REST API发送的服务端RPC命令最终都会转换为规则引擎消息, 消息类型为 “RPC_CALL_FROM_SERVER_TO_DEVICE”。
消息包含存储在 “requestUUID” 元数据字段中的基于UUID的唯一标识符。 您可以设计规则链, 使用转换、丰富或其他规则节点类型处理传入消息。 最后,应使用RPC调用请求节点将消息发送至设备。
您也可以使用生成器节点创建RPC:
1
2
3
4
5
6
7
8
9
var msg = { method: "rpcCommand", params: {} };
var metadata = {
expirationTime: new Date().getTime() + 60000,
oneway: true,
persistent: false
};
var msgType = "RPC_CALL_FROM_SERVER_TO_DEVICE";
return { msg: msg, metadata: metadata, msgType: msgType };
在设备上处理服务端RPC
ThingsBoard提供便于在设备上接收和处理服务端RPC命令的API。 该API针对每种支持的网络协议有专门实现。 您可在相应参考页面查看API及示例:
持久化RPC
状态
ThingsBoard跟踪持久化RPC的状态。共有7种状态:
- QUEUED - RPC已创建并保存到数据库;尚未尝试向设备发送;当设备上线或已在线时,ThingsBoard会立即尝试发送;默认情况下平台会同时尝试发送所有待处理RPC;在受限设备且队列中消息较多时,可能导致网络或设备过载。
- SENT - ThingsBoard已尝试向设备发送RPC。
- DELIVERED - 设备已确认RPC送达;这是单向RPC处理的最后一步。
- SUCCESSFUL - ThingsBoard已收到双向RPC的回复。
- TIMEOUT - ThingsBoard传输层(MQTT/CoAP/LwM2M等)检测到RPC投递超时;超时由对应配置参数控制:MQTT_TIMEOUT(默认10秒)、COAP_TIMEOUT(默认10秒)、LWM2M_TIMEOUT(默认120秒);默认平台不会重试,状态会变为FAILED;可在RPC体中配置重试次数;默认最大重试次数为5。
- EXPIRED - 在配置的过期时间内RPC未送达或平台未收到设备回复;
- FAILED - 在可配置次数的重试后仍无法送达,或设备固件不支持该命令。
规则链事件
RPC状态的变化会作为独立消息推送到规则引擎。 每种RPC状态都有对应的消息类型。如下图所示:
消息包含RPC请求的完整信息,包括实体id及请求体中的 “additionalInfo”。 “RPC Successful” 消息还会包含设备回复。 若要在外部系统中处理设备回复,这些消息很有用。
成功RPC消息示例如下:
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
38
39
40
{
"id": {
"entityType": "RPC",
"id": "bea26301-1aec-11ec-9441-73a37bbb7cd2"
},
"createdTime": 1632236465459,
"tenantId": {
"entityType": "TENANT",
"id": "ab937a40-3f98-11eb-a8d6-f5a87f07d4be"
},
"deviceId": {
"entityType": "DEVICE",
"id": "3e46db70-e480-11eb-9d0e-1f8899a6f9b3"
},
"expirationTime": 1632236525354,
"request": {
"id": "bea26301-1aec-11ec-9441-73a37bbb7cd2",
"tenantId": {
"entityType": "TENANT",
"id": "ab937a40-3f98-11eb-a8d6-f5a87f07d4be"
},
"deviceId": {
"entityType": "DEVICE",
"id": "3e46db70-e480-11eb-9d0e-1f8899a6f9b3"
},
"oneway": false,
"expirationTime": 1632236525354,
"body": {
"method": "rpcCommand",
"params": "{}"
},
"persisted": true,
"retries": null
},
"response": {
"test": "passed"
},
"status": "SUCCESSFUL",
"additionalInfo": "{\"param1\":\"value1\",\"param2\":\"value2\"}"
}
TTL配置
持久化RPC的生存时间取决于订阅计划。详见订阅中的 ‘RPC TTL’ 参数。