WaveshareCloud Wiki Help

设备间通信

如何通过Waveshare Cloud实现设备与设备之间的通信?

通信原理

发布/订阅模式

发布订阅模式(Publish-Subscribe Pattern)是一种消息传递模式,它将发送消息的客户端(发布者)与接收消息的客户端(订阅者)解耦,使得两者不需要建立直接的联系也不需要知道对方的存在。

MQTT 发布/订阅模式的精髓在于由一个被称为代理(Broker)的中间角色负责所有消息的路由和分发工作,发布者将带有主题的消息发送给代理,订阅者则向代理订阅主题来接收感兴趣的消息。

在 MQTT 中,主题和订阅无法被提前注册或创建,所以代理也无法预知某一个主题之后是否会有订阅者,以及会有多少订阅者,所以只能将消息转发给当前的订阅者, 如果当前不存在任何订阅,那么消息将被直接丢弃。

MQTT 发布/订阅模式有 4 个主要组成部分:发布者、订阅者、代理和主题。

  • 发布者(Publisher)

    负责将消息发布到主题上,发布者一次只能向一个主题发送数据,发布者发布消息时也无需关心订阅者是否在线。

  • 订阅者(Subscriber)

    订阅者通过订阅主题接收消息,且可一次订阅多个主题。MQTT还支持通过共享订阅的方式在多个订阅者之间实现订阅的负载均衡。

  • 代理(Server)

    负责接收发布者的消息,并将消息转发至符合条件的订阅者。另外,代理也需要负责处理客户端发起的连接、断开连接、订阅、取消订阅等请求。

  • 主题(Topic)

    主题是 MQTT 进行消息路由的基础,它类似 URL 路径,使用斜杠 / 进行分层,比如 sensor/1/temperature。一个主题可以有多个订阅者,代理会将该主题下的消息转发给所有订阅者;一个主题也可以有多个发布者,代理将按照消息到达的顺序转发。

Mqtt

MQTT 发布/订阅中的消息路由

在 MQTT 发布/订阅模式中,一个客户端既可以是发布者,也可以是订阅者,也可以同时具备这两个身份。 当客户端发布一条消息时,它会被发送到代理,然后代理将消息路由到该主题的所有订阅者。 当客户端订阅一个主题时,它会收到代理转发到该主题的所有消息。

Waveshare Cloud的消息过滤是通过主题的:订阅者向代理订阅自己感兴趣的主题,发布者发布的所有消息中都会包含自己的主题,代理根据消息的主题判断需要将消息转发给哪些订阅者。

A1ae3d44

ESP32代码实现

获取地址参数

95d6bec9

代码参考: ESP32接入Waveshare Cloud SDK (建议复制下述整体代码)

这里定义了消息回调控制参数为

{ "data": { "builtIn": 0 // 0 or 1 } }

整体代码

#include <ArduinoJson.h> #include <Arduino.h> #include <PubSubClient.h> #include <WiFi.h> #include <WiFiClientSecure.h> #define MSG_BUFFER_SIZE (50) // WiFi 接入点的名称和密码 #define STASSID "" #define STAPSK "" const char* mqtt_server = "mqtt.waveshare.cloud"; int PORT = 1883; const char* ID = "19ba7e8b"; // 定义设备 ID char sub[] = "Sub/1/37/19ba7e8b"; // MQTT 订阅主题 char pub[] = "Pub/1/37/19ba7e8b"; // MQTT 发布主题 StaticJsonDocument<400> sendJson; StaticJsonDocument<400> readJson; unsigned long lastUpdateTime = 0; const char* ssid = STASSID; const char* password = STAPSK; char msg[MSG_BUFFER_SIZE]; WiFiClient espClient; PubSubClient client(espClient); const unsigned long updateInterval = 5000; void setup() { Serial.begin(9600); setup_wifi(); client.setServer(mqtt_server, PORT); client.setCallback(callback); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); } // MQTT 订阅回调函数,用于处理接收到的消息 void callback(char* topic, byte* payload, unsigned int length) { String inputString; for (int i = 0; i < length; i++) { inputString += (char)payload[i]; } Serial.println(inputString); int dataBegin = inputString.indexOf("\"data\""); if (dataBegin == -1) { Serial.println(F("Missing 'data' field in JSON.")); return; } int builtInBegin = inputString.indexOf("\"builtIn\"", dataBegin); if (builtInBegin == -1) { Serial.println(F("Missing 'builtIn' field in 'data' object.")); return; } int valueBegin = inputString.indexOf(':', builtInBegin); int valueEnd = inputString.indexOf('}', valueBegin); if (valueBegin == -1 || valueEnd == -1) { Serial.println(F("Invalid 'builtIn' value.")); return; } String builtInValueStr = inputString.substring(valueBegin + 1, valueEnd); int builtInValue = builtInValueStr.toInt(); if (builtInValue == 0) { Serial.println("close!"); sendJsonData(0); } else { Serial.println("open!"); sendJsonData(1); } } void setup_wifi() { Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("IP address: "); Serial.println(WiFi.localIP()); } // 重新连接 MQTT 服务器 void reconnect() { while (!client.connected()) { if (client.connect(ID)) { client.subscribe(sub); } else { Serial.print(client.state()); delay(5000); } } } // 发送 JSON 格式的数据到 MQTT 服务器 void sendJsonData(int value) { sendJson["builtIn"] = value; String pubres; serializeJson(sendJson, pubres); int str_len = pubres.length() + 1; char char_array[str_len]; pubres.toCharArray(char_array, str_len); client.publish(pub, char_array); }

SIM7028 NB-IoT HAT指令实现

获取SIM7028 Client ID

6d583946

指令集

指令集

返回

继续输入?

输入值

说明

AT+CMQTTSTART

+CMQTTSTART: 0

No

——

开启MQTT功能

AT+CMQTTACCQ=0,"82b52f8b",0

OK

No

——

设置Client ID82b52f8b代表平台获得的Client ID,后一位0代表使用mqtt协议(非ssl)

AT+CMQTTCONNECT=0, tcp://mqtt.waveshare.cloud: 1883,20,1

+CMQTTCONNECT: 0,0

No

——

连接MQTT服务器,返回值0,0代表连接成功

AT+CMQTTSUB=0,17,1

>

Icon available

Pub/1/37/19ba7e8b

ESP32 Pub主题

AT+CMQTTTOPIC=0,17

>

Icon available

Sub/1/37/19ba7e8b

ESP32 Sub主题

AT+CMQTTPAYLOAD=0,22

>

Icon available

{"data":{"builtIn":1}}

输入消息体

AT+CMQTTPUB=0,1,60

+CMQTTPUB: 0,0

No

——

发送消息

指令示例

Fbe9095c
Last modified: 12 一月 2024