2-5 在ESP8266中接收 MQTT 消息
现在让我们使用 mosquitto_pub 发布消息并在 ESP8266 中接收它。
为此,ESP8266 需要订阅 mosquitto_pub 将发布消息的相同主题。我们将主题称为 outdoor/light,它将发布 0 或 1 值。如果 ESP8266 的值为 1,它将打开连接到 GPIO 12 的 LED,如果它接收到 0,它将关闭该 LED:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
使用适合您网络的值更新这些值:
const char* wifi_network= "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* mqtt_serv_address = "YOUR_MQTT_SERVER_IP";
const int mqtt_port_number = 1883;
#define OUTDOOR LIGHT 12
WiFiClient espClient;
PubsubClient client(espClient);
long lastMsg = 0;
启动与Wi-Fi网络的连接,并设置从MQTT代理接收消息时将调用的函数的名称,如下所示:
void setup() {
pinMode(OUTDOOR_LIGHT, OUTPUT);
//Initialize the BUILTIN LED pin as an output
// 初始化BUILTIN LED引脚作为输出
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_serv_address, mqtt_port_number);
client.setCallback(callback);
}
连接到Wi-Fi网络:
void setup_wifi() {
delay(10);
//我们首先连接到WiFi网络
Serial.println();
Serial.print("Connecting to");
Serial.println(wifi_network);
WiFi.begin(wifi_network, password);
while(WiFi.status() != WL_CONNECTED) {
WiFi.begin(wifi_network, password);
Serial.print(".");
delay(5000);
}
Serial.println("");
Serial.println( "WiFi connected");
Serial.println("IP address:");
Serial.println(WiFi.localIP());
}
当消息到达 ESP8266 MQTT 客户端时,将带着 包含到达消息中的主题名称(模块可能订阅了多个主题) 的 topic 参数 ,消息的实际内容 payload 和 消息的长度 msg_length:
void callback(char* topic, byte* payload, unsigned int msg_length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("]");
for(inti=O;i<msg_length;i++){
Serial.print((char)payload[i]);
}
Serial.println();
// 如果收到第一个字符为 1 ,则打开LED
if ((char)payload[0] == '0') {
digitalWrite(OUTDOOR_LIGHT, LOW); //关闭 LED
} else {
digitalWrite(OUTDOOR_LIGHT, HIGH); //打开 LED
}
}
在 reconnect()函数中,它也将订阅 outdoor/light 主题并从中获取消息 ,如果与代理的连接丢失,它将每五秒尝试连接一次:
void reconnect( ) {
//循环直到我们重新连接
while (!client.connected()) {
Serial.print("Attempting MQTT connection. . .");
//尝试连接
if (client.connect("ESP8266Client")){
Serial.println("connected");
client.subscribe("outdoor/light");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println("try again in 5 seconds");
//等待5秒再重试
delay(5000);
}
}
}
loop()函数将发布 GPIO 12 的值,它实际上是室外灯的状态:
void loop() {
if(!client.connected()){
reconnect();
}
client.loop();
long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
String light_state;
if (digitalRead (OUTDOOR_LIGHT) == HIGH)
light state = "ON";
else
light_state = "OFF";
Serial.print("Publish message: ");
Serial.println(light_state);
client.publish ("outdoor/light/status", light_state.c_str());
}
}
在终端窗口中,您将看到 ON 或 OFF,具体取决于在 outdoor/light 主题上传输的最后一条消息的值。请注意,该模块正在订阅 outdoor/light 主题,并在 outdoor/light 主题上发布GPIO的状态: