指令说明
概述
Node-MQ的指令(包括应答)采用JSON格式定义。例如,配置GPIO5为输入模式的指令:
{
"action": "config",
"input": [5]
}读取GPIO5引脚电平数字量的指令:
{
"action": "digital_read",
"io_num": [5]
}以及引脚电平数字量的应答信息:
{
"type": "digital",
"data": [
{
"io_num": 5,
"value": 0
}
]
}指令JSON对象的形式如:
{
"action": "action_name",
"param_1": "value_1",
"param_2": "value_2",
...
}指令对象包含指令名称action属性,以及指令所需的参数。在具体指令章节中将对各自的参数作详细说明。
应答JSON对象的形式如:
{
"type": "type_name",
"data": "data",
...
}应答对象包含应答数据类型type属性,以及具体的应答数据。应答数据同样在具体的指令章节中说明。
指令通道
用于传输指令的通道称为指令通道。Node-MQ支持从MQTT、WebSocket或UART通道接收指令,并将对应指令的执行结果(应答)反馈至同一通道。所有的指令通道可以同时启用。
MQTT
当在设置页面启用了 MQTT Client 并配置了相应的MQTT参数后,Node-MQ启动后将自动连接MQTT Broker,并订阅配置的 Subscribe Topic 主题(默认为node/action)。由该主题接收的MQTT消息Payload将作为指令解析并执行。指令的执行结果(应答)以MQTT消息Payload发布到配置的 Publish Topic 主题(默认为node/post)。
作为指令发送方的MQTT客户端,应将指令发布到Node-MQ配置的 Subscribe Topic 主题,并订阅Node-MQ配置的 Publish Topic 主题,以便接收指令的执行结果以及Node-MQ发布的通知消息。
MQTT通道单次接收或发送的消息Payload最大允许 8 KB。
Node-MQ连接MQTT Broker后,将自动发布一条 type-online 消息,用以通知客户端该Node-MQ设备上线。消息Payload如下:
{
"type": "online",
"node_id": "node-5a25d4",
"version": "1.0.0"
}
type- 数据类型online(在线消息)。node_id- Node-MQ自动生成的硬件唯一标识。version- Node-MQ固件版本号。
当在设置页面的MQTT参数中启用 Last Will 后,若Node-MQ设备异常断连,则客户端会收到由MQTT Broker以 Publish Topic 主题发布的遗嘱消息,消息Payload如下:
{
"type": "offline",
"node_id": "node-5a25d4"
}
type- 数据类型offline(断连消息)。node_id- Node-MQ自动生成的硬件唯一标识。
可以在同一个MQTT网络中部署多个Node-MQ设备,此时应注意在MQTT参数中区分 Client ID(默认值为系统自动生成的硬件唯一标识)。多个Node-MQ设备可以通过配置不同的 Subscribe Topic 和 Publish Topic 进行分组控制,或独立控制。
WebSocket
WebSocket通道默认启用,连接地址为:
ws://<host>/ws
<host>为Node-MQ设备的IP地址。Node-MQ以SoftAP模式启动时,连接地址固定为ws://192.168.4.1/ws。
WebSocket通道单次接收或发送的数据包最大允许 8 KB。
当设置页面启用了 Access Control(访问控制)时,客户端在WebSocket连接建立后应首先发送 Access Code,若首帧数据非密码或密码验证失败,服务端将关闭连接。
WebSocket通道在同一时间只允许一个连接(独占),若已有客户端连接了WebSocket通道,则后续的连接请求将被忽略。
注意
Node-MQ的设置页面会自动连接WebSocket通道。因此,使用自定义的WebSocket客户端时,请关闭设置页面。
网页WebSocket客户端样例:
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Client</title>
</head>
<style>
.main {
display: flex;
flex-flow: column;
width: fit-content;
gap: 8px;
}
.main textarea,
.main button {
padding: 5px;
}
</style>
<body>
<div class="main">
Action
<textarea id="action" rows="10" cols="40"></textarea>
<button id="send">Send</button>
Feedback
<textarea id="feedback" rows="10" cols="40"></textarea>
<span id="status"></span>
</div>
<script>
// Replace with the actual IP address of Node-MQ.
const IP_ADDRESS = '192.168.1.106';
let ws;
const action = document.getElementById('action');
const feedback = document.getElementById('feedback');
const send = document.getElementById('send');
const status = document.getElementById('status');
const connect = () => {
status.textContent = 'Connecting';
ws = new WebSocket(`ws://${IP_ADDRESS}/ws`);
ws.onopen = () => {
status.textContent = 'Connected';
// If access control is enabled, send the Access Code.
// ws.send('nodenode');
};
ws.onclose = (e) => {
status.textContent = `Disconnected (code=${e.code})`;
setTimeout(connect, 2000);
};
ws.onmessage = (e) => {
feedback.value += e.data + '\n';
};
};
send.onclick = () => {
if (ws?.readyState === WebSocket.OPEN) {
ws.send(action.value);
}
else {
status.textContent = 'Not Connected';
}
};
connect();
</script>
</body>
</html>保存样例为.html文件,并根据Node-MQ设备的实际IP地址修改对应变量后,使用浏览器打开即可测试样例。
UART
ESP32-S3 模块提供3个UART控制器(UART0~UART2),均可用作指令通道,并可同时启用。UART通道需要由config指令启用,参考 UART配置。
UART通道单次接收或发送的数据包最大允许 4 KB。使用UART通道发送的指令必须一次性连续发送(字符中断间隔小于20毫秒),一次完整指令不可分段发送。
通用规则
单条指令或应答均以JSON对象形式定义。
多条指令可以组合为JSON对象数组,一次性提交。Node-MQ将按照数组中的顺序逐一执行。例如:
json[ { "action": "config", "input": [5] }, { "action": "digital_read", "io_num": [5] } ]指令JSON对象固定包含
action属性,标识指令名称。例如{"action": "config"}表示资源配置指令。应答JSON对象固定包含
type属性,标识应答数据类型。 例如{"type": "digital"}表示引脚电平数字量。指令和应答JSON对象中的属性名称和预定义值(字符型)使用小写英文加下划线分隔形式(snake_case)。
根据应答行为的不同,指令可以分为两种类型:
- 需要明确应答的指令。此类指令的意图即获取应答数据,例如读取引脚电平数字量指令。
- 非必须应答的指令,如设置引脚电平数字量指令。对于此类指令,Node-MQ采用静默原则,即除非捕获到错误,否则不应答。在具体指令说明中提到“该指令无应答”的,均属于此类指令。
当Node-MQ在解析或执行指令过程中捕获到错误时,将反馈
type-error错误信息,例如:json{ "type": "error", "tag": "config", "msg": "ERR_INVALID_IO" }type- 数据类型error(错误消息)。tag- 标识错误源或指令名称。msg- 错误的可读名称或描述。
Node-MQ的指令通道均为异步传输通道,即指令的发送方在发出指令后不会同步等待应答,而是以指令已发出的状态立即返回。指令执行结果则以异步消息的形式通知指令发送方。为使发送方在收到应答消息后能识别其所对应的指令,所有指令均支持可选的
id属性,类型为无符号整数(uint32)。当指令JSON对象中包含该属性时,其应答JSON对象也将包含相同值的id属性。指令的发送方可以为指令设置id标识,并在收到应答后根据相同的id关联对应的指令。带有id属性的指令如:json{ "id": 33, "action": "digital_read", "io_num": [5] }Node-MQ在解析指令JSON时,支持单元素数组简写。即对于数组类型的属性,当仅有一个元素时,可以直接将该元素作为属性值。例如,整型数组:
json{ "action": "digital_read", "io_num": [5] }可简写为:
json{ "action": "digital_read", "io_num": 5 }或对象数组:
json{ "action": "config", "uart": [ { "uart_num": 0 } ] }可简写为:
json{ "action": "config", "uart": { "uart_num": 0 } }
文档约定
本文档统一使用以下格式描述JSON指令对象的属性定义:
属性名称
[值类型] (可选标识)属性说明。值类型:
string- UTF-8字符串,如{"action": "config"}。int- 整数值,如{"value": 10}。float- 浮点值,如{"value": 4.5}。bool- 布尔值,如{"value": true}。object- JSON对象,如{"data": {"name": "Kyle"}}。array- 数组,如{"input": [1, 2, 3]}。
可选标识:
(!)- 表示该属性必须存在。(?)- 表示该属性可选,可以不存在。
样例:
action
[string] (!)指令名称。字符串类型的必选属性 action。
input
[array] (?)设置为输入模式的GPIO序号数组。数组类型的可选属性 input。
在文档中使用以下简写形式指代具体的指令或应答:
- 指令如
{"action": "config"}简写为action-config。 - 应答如
{"type": "digital"}简写为type-digital。
- 指令如