在Raspberry Pi上安装和测试MQTT进行IoT通信
MQTT是一种用于通过 Internet 发送和接收消息的协议。我们之前在物联网电表和Raspberry Pi Alexa中使用此协议在互联网上发布数据。在本教程中,我们将更多地了解 MQTT 及其相关术语。在这里,我们将使用Raspberry Pi 作为本地 MQTT 代理,并通过 MQTT 应用程序仪表板控制连接到 NodeMCU ESP12E 的 LED。DHT11 传感器也连接到 NodeMCU,因此我们再次使用 Raspberry Pi 作为本地 MQTT 代理,在 MQTT 仪表板上读取温度和湿度。
因此,让我们从了解 MQTT 及其相关术语开始。
什么是 MQTT?
MQTT 代表IBM 设计的 Message Queue Telemetry Transport。该协议简单轻量,用于通过互联网发送和接收消息,专为低带宽使用的设备而设计。如今,该协议经常在物联网设备中用于发送和接收传感器数据。此外,在基于物联网的家庭自动化系统中,无需使用大量互联网数据即可轻松使用此协议。
在 MQTT 中经常使用的术语很少:
订阅和发布
信息
话题
经纪人
1.订阅和发布:订阅是从其他设备获取数据,发布是向其他设备发送数据。
当 device1 将数据发送到 device2 时,它称为发布者,另一个称为订阅者,反之亦然。
2. 消息:消息是我们发送和接收的信息。它可以是数据或任何类型的命令。例如,如果我们将温度数据发布到云端,则此温度数据称为消息。
3. 主题:这是您注册对传入消息感兴趣的方式或您如何指定要发布消息的位置。主题用正斜杠分隔的字符串表示。使用 MQTT 在主题上发布数据,然后 MQTT 设备订阅主题以获取数据。
4. MQTT Broker:这个东西负责接收所有发布者的消息,过滤消息,然后将消息发布给感兴趣的订阅者。
当这个代理托管在云上时,它被称为 MQTT 云。有许多基于云的 MQTT 服务,例如 Adafruit IO、MQTT.IO、IBM bluemix、Microsoft Azure 等。MQTT 也可以与流行的 Amazon AWS 云一起使用,我们在Amazon AWS 入门教程中对此进行了说明。
我们可以使用 Raspberry Pi 创建自己的 MQTT 代理。这将是本地 MQTT 代理,即您只能在本地网络上发送和接收数据,而不是从任何地方。所以在这里我们将在 Raspberry Pi 中安装 Mosquitto MQTT 代理,使其成为本地 MQTT 代理,并将温度数据从 NodeMCU 发送到 MQTT 仪表板应用程序。此外,我们将使用代理控制连接到 NodeMCU 的 LED。
在树莓派上安装 Mosquitto MQTT 代理
在您的 Raspberry pi 中打开终端并键入以下命令以安装代理
sudo apt update sudo apt install -y mosquitto mosquitto-clients
等待安装完成。现在,要在启动树莓派时启动代理,请键入以下命令
sudo systemctl 启用 mosquitto.service
就是这样,我们都准备好启动我们的 MQTT 代理了。要检查它是否安装正确,请输入以下命令
蚊子-v
此命令将为您提供 MQTT 代理的版本。它应该是 1.4.x 或更高版本。
测试 Raspberry Pi Mosquitto Broker
1. 使用以下命令在后台运行 Mosquitto 代理
蚊子-d
2. 现在,我们将使用以下命令在 exampleTopic 中订阅一个主题
mosquitto_sub -d -t exampleTopic
3. 现在,我们将发布一些消息到 exampleTopic
mosquitto_pub -d -t exampleTopic -m "Hello world!"
您将收到 Hello World!用户终端中的消息。
现在,在我们使用 NodeMCU 和MQTT 仪表板应用程序的案例中,是时候控制和从另一台设备获取数据了。
首先,我们将通过使用 App 发送命令来控制 LED,因此在这种情况下,NodeMCU 表现为订阅者,而 App 表现为发布者。
然后 ESP12E 还连接了 DHT11 传感器,并将此温度读数发送到 Mobile MQTT 应用程序,因此在这种情况下,移动设备将成为订阅者,NodeMCU 将成为发布者。为了在各自的主题上转发这些消息,使用了 Mosquitto MQTT 代理。
电路原理图
如图所示连接电路。这里 DHT11 用于温度读数,但也可以使用LM35 温度传感器。
让我们开始编写 NodeMCU 的代码来订阅和发布数据。
代码和解释
在这里,我们将使用 Adafruit MQTT 库模板,并将更改代码中所需的内容。只需更改一些内容,即可使用相同的代码将数据发布和订阅到 Adafruit IO 云。
为此,从Sketch -》 Include Library -》 Manage Libraries 下载 Adafruit MQTT 库。搜索 Adafruit MQTT 并安装它。安装库后。转到 示例-》 Adafruit mqtt 库-》 mqtt_esp8266
然后根据我们的 Raspberry Pi IP 地址和 Wi-Fi 凭据编辑此代码。
包括 ESP8266WIFI 和 Adafruit MQTT 的所有库。
#include#include "Adafruit_MQTT.h" #include "Adafruit_MQTT_Client.h" #include "DHT.h"
然后为您想要连接 ESP-12e 的 Wi-Fi 定义 SSID 和密码。确保您的 RPi 和 NodeMCU 连接到同一个网络。
#define WLAN_SSID "xxxxxxxx" #define WLAN_PASS "xxxxxxxxxxx"
本节定义 Adafruit 服务器,在本例中是您的 Raspberry Pi 的 IP 地址和服务器端口。
#define AIO_SERVER "你的 Pi 的 IP 地址" #define AIO_SERVERPORT 1883
下面的字段将保持空白,因为我们没有使用 Adafruit 云。
#define AIO_USERNAME "" #define AIO_KEY ""
然后创建一个 ESP8266 WiFiClient 类来连接到 MQTT 服务器。
WiFiClient客户端;
通过传入 WiFi 客户端和 MQTT 服务器以及登录详细信息来设置 MQTT 客户端类。
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
设置一个名为“温度”的提要来发布温度。
Adafruit_MQTT_Publish 温度 = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/temperature");
设置一个名为“led1”的提要来订阅更改。
Adafruit_MQTT_Subscribe led1 = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/led");
在setup函数中,我们声明了要在其上获得输出的 NodeMCU 的 PIN。然后,将 NodeMCU 连接到 Wi-fi 接入点。
无效设置() { Serial.begin(115200); 延迟(10); pinMode(LED,输出); Serial.println(F("Adafruit MQTT demo")); // 连接到 WiFi 接入点。 序列号.println(); 序列号.println(); Serial.print("正在连接"); Serial.println(WLAN_SSID); WiFi.开始(WLAN_SSID,WLAN_PASS); 而 (WiFi.status() != WL_CONNECTED) { .... …… … 为 led 提要设置 MQTT 订阅。 mqtt.subscribe(&led1); }
在循环函数中,我们将使用 MQTT_connect() 确保与 MQTT 服务器的连接处于活动状态;功能。
无效循环() { MQTT_connect();
现在,订阅 'led' 提要并从 MQTT 代理获取字符串,并使用atoi() 将此字符串转换为数字;函数并使用digitalWrite()将此数字写入 LED 引脚;功能。
Adafruit_MQTT_Subscribe *订阅; while ((subscription = mqtt.readSubscription(20000))) { if (subscription == &led1) { Serial.print(F("Got: ")); Serial.println((char *)led1.lastread); int led1_State = atoi((char *)led1.lastread); 数字写入(LED,led1_State); }
现在,获取变量中的温度并使用Temperature.publish(t)函数发布该值。
浮动 t = dht.readTemperature(); … .. if (!Temperature.publish(t)) { Serial.println(F("Failed")); } else { Serial.println(F("OK!")); }
#include
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
#include "DHT.h"
#define LED D5
#define DHTPIN D4
#define WLAN_SSID "awesome"
#define WLAN_PASS "awesome12"
#define AIO_SERVER "192.168.43.177" //RPi的IP地址
#define AIO_SERVERPORT 1883
#define AIO_USERNAME ""
#define AIO_KEY ""
WiFiClient客户端;
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
Adafruit_MQTT_Publish 温度 = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/temperature");
Adafruit_MQTT_Subscribe led1 = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/led");
#define DHTTYPE DHT11 // DHT 11
DHT dht(DHTPIN, DHTTYPE);
uint32_t 延迟时间;
/****************************** 草图代码 ************************ ******************/
无效 MQTT_connect();
无效设置() {
Serial.begin(115200);
延迟(10);
pinMode(LED,输出);
Serial.println(F("Adafruit MQTT demo"));
// 连接到 WiFi 接入点。
序列号.println(); 序列号.println();
Serial.print("正在连接");
Serial.println(WLAN_SSID);
WiFi.开始(WLAN_SSID,WLAN_PASS);
而(WiFi.status()!= WL_CONNECTED){
延迟(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi 连接");
Serial.println("IP地址:"); Serial.println(WiFi.localIP());
//设置 DHT 传感器
dht.begin();
// 为 onoff feed 设置 MQTT 订阅。
mqtt.subscribe(&led1);
}
uint32_t x = 0;
void loop() {
// 确保与 MQTT 服务器的连接处于活动状态(这将建立第一个
// 连接并在断开连接时自动重新连接)。请参阅下面的 MQTT_connect
// 函数定义。
MQTT_connect();
// 这是我们的“等待收到的订阅数据包”繁忙的子循环
// 试着把你的时间花在这里
Adafruit_MQTT_Subscribe *订阅;
while ((subscription = mqtt.readSubscription(20000))) {
if (subscription == &led1) {
Serial.print(F("Got: "));
Serial.println((char *)led1.lastread);
int led1_State = atoi((char *)led1.lastread);
数字写入(LED,led1_State);
Serial.println("onnn");
}
}
// 以摄氏度读取温度(默认)
float t = dht.readTemperature();
// 检查是否有任何读取失败并提前退出(重试)。
if (isnan(t)) {
Serial.println("读取 DHT 传感器失败!");
返回;
}
if (! Temperature.publish(t)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("OK!"));
}
}
// 根据需要连接和重新连接到 MQTT 服务器的函数。
// 应该在循环函数中调用,如果连接会小心。
无效 MQTT_connect() {
int8_t ret;
// 如果已经连接则停止。
if (mqtt.connected()) {
返回;
}
Serial.print("正在连接 MQTT...");
uint8_t 重试次数 = 3;
while ((ret = mqtt.connect()) != 0) { // connect 将返回 0 连接
Serial.println(mqtt.connectErrorString(ret));
Serial.println("5 秒后重试 MQTT 连接...");
mqtt.disconnect();
延迟(5000);// 等待 5 秒
重试--;
if (retries == 0) {
// 基本上死了,等待 WDT 重置我
while (1);
}
}
Serial.println("MQTT 已连接!");
}