MQTT是一种针对小型物联网设备的轻量级传输协议。虽然Arduino开发板本身没有网络功能,但它可以使用以太网扩展板Shield,实现连接到互联网的功能。使用以太网和MQTT库,我们可以快速建立Arduino开发板与MQTT服务器之间的对话,实现发送和接收数据!
安装所需的库 默认情况下,Arduino IDE自带了所需的以太网库,但需要安装MQTT库。转到Sketch> Include Library> Manager Libraries,并在搜索字段中搜索MQTT。我们将使用名为“PubSubClient”的库,它是一个用于MQTT的轻量级库。该库有点靠近列表的底部,因此请仔细查看列表!
创建一个新文件,随意起个名字(例如“MyFirstMQTT”),然后在程序开始部分包含这些库文件。以太网扩展板需要SPI,Ethernet.h是传递给PubSubClient.h库的以太网库。该库文件处理MQTT协议和消息传递。 - #include <SPI.h>
- #include <Ethernet.h>
- #include <PubSubClient.h>
复制代码
初始化 使用MQTT的第一步是定义许多变量,包括IP地址、MAC、服务器和一些对象。我们程序的第一行是函数的函数原型,它将处理传入的消息,稍后将对此进行更深入的研究。接下来的几行代码创建了我们的MAC地址 - 它必须是唯一的 - 以及我们以太网的IP地址。应该注意的是,如果我们的路由器可以为我们分配一个IP地址,将忽略该IP地址。如果不能,它将退回并使用此IP地址。
下一行定义了我们将连接到的MQTT代理。 MQTT世界中的代理只是一个服务器,但与服务器不同,代理可以随时向客户端发送消息,它们不是为存储数据而设计的,只是中继。最后两行定义了一个用于控制以太网扩展板的以太网对象和一个接收以太网对象的MQTT客户端。由于MQTT客户端采用以太网对象,因此代码非常简单,这样我们根本不需要处理以太网扩展板! - // Function prototypes
- void subscribeReceive(char* topic, byte* payload, unsigned int length);
-
- // Set your MAC address and IP address here
- byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
- IPAddress ip(192, 168, 1, 160);
-
- // Make sure to leave out the http and slashes!
- const char* server = "test.mosquitto.org";
-
- // Ethernet and MQTT related objects
- EthernetClient ethClient;
- PubSubClient mqttClient(ethClient);
复制代码
setup()函数 在setup()函数中,我们需要先启用串口,这样我们就可以看到Arduino的状态并开始以太网连接。 .begin()函数有两个参数:MAC地址和IP地址。在这一点上,我们还包括一个小延迟,以允许以太网扩展板做它的事情!
下一步是设置我们将要进行通信的MQTT代理。 .connect()函数接受多个参数,包括用户名和密码,但由于我们使用的是公共测试MQTT代理,因此我们只需要定义用户ID。目前,我们的用户ID将是“myClientID”。此函数将返回一个布尔值,具体取决于与代理的连接是否成功。如果连接成功,则返回true。否则,它返回false。如果连接为true,那么我们创建一个事件处理程序,它将在收到消息时调用函数“subscribeReceive”。 - void setup()
- {
- // Useful for debugging purposes
- Serial.begin(9600);
-
- // Start the ethernet connection
- Ethernet.begin(mac, ip);
-
- // Ethernet takes some time to boot!
- delay(3000);
-
- // Set the MQTT server to the server stated above ^
- mqttClient.setServer(server, 1883);
-
- // Attempt to connect to the server with the ID "myClientID"
- if (mqttClient.connect("myClientID"))
- {
- Serial.println("Connection has been established, well done");
-
- // Establish the subscribe event
- mqttClient.setCallback(subscribeReceive);
- }
- else
- {
- Serial.println("Looks like the server connection failed...");
- }
- }
复制代码
main loop()函数 在loop()函数中,第一个函数是.loop()。实质上,它处理保持活动信号,以及处理传入消息。循环中的下一行让我们的Arduino订阅一个主题“MakerIOTopic”。在MQTT中,可以将主题视为存储在代理上的字符串变量,该变量可以包含一些数据,用户可以发布到主题、订阅主题或同时执行这两个操作!例如,如果用户向主题“门状态”发布值“门打开”,则订阅主题“门状态”的任何设备将接收消息“门打开”。如果世界上的任何设备发布了消息“MakerIOTopic”然后我们的程序将调用函数“subscribeReceive”。
下一部分代码尝试将消息发布到主题“MakerIOTopic”。在这种情况下,我们将消息“Hello World”发送到“MakerIOTopic”主题,以便订阅该主题的任何设备都将收到此消息。最后一行是一个简单的延迟,防止我们用一百万条消息滥用服务器! - void loop()
- {
- // This is needed at the top of the loop!
- mqttClient.loop();
-
- // Ensure that we are subscribed to the topic "MakerIOTopic"
- mqttClient.subscribe("MakerIOTopic");
-
- // Attempt to publish a value to the topic "MakerIOTopic"
- if(mqttClient.publish("MakerIOTopic", "Hello World"))
- {
- Serial.println("Publish message success");
- }
- else
- {
- Serial.println("Could not send message :(");
- }
-
- // Dont overload the server!
- delay(4000);
- }
复制代码
订阅处理 我们程序中的最后一个函数是subscribeReceive,只要消息从MQTT代理到达,就会调用它。 传递给它的三个变量:主题名称(以char数组的形式)、消息本身(以字节数组的形式),以及这些字节的长度。 打印主题和有效负载,输出窗口显示下面的结果。 - void subscribeReceive(char* topic, byte* payload, unsigned int length)
- {
- // Print the topic
- Serial.print("Topic: ");
- Serial.println(topic);
-
- // Print the message
- Serial.print("Message: ");
- for(int i = 0; i < length; i ++)
- {
- Serial.print(char(payload[i]));
- }
-
- // Print a newline
- Serial.println("");
- }
复制代码
|