ESP32(基于Arduino)通过EMQX的MQTT服务器上传信息与实现命令控制

前言: 

EMQX开源版提供了免费的本地的局域网下的mqtt服务器,可以通过订阅主题与发布主题下的信息实现物联网的诸多操作。什么操作?如通过订阅将设备采集的传感器信息转储到本地数据库。通过发布来实现对设备的开关进行控制。

上传信息和命令控制都基于我本地搭建的一个客户端来作为中间枢纽。本地客户端开启一个web的服务并提供了接口访问。

上传信息:

由于我已经在本地写了一个客户端订阅ESP32的发布信息的主题 device/date,esp32每对device/date发布一次信息,客户端收到后就转储到mysql数据库。

命令控制:

esp32订阅esp32/dev/# ,不完全匹配 ,这里的#可以是1,2,3代表esp32的控制器dev1,dev2,dev3(对于esp32外接的led灯,电机,蜂鸣器等等)。这里的控制是最直接的控制,为了达到间接控制比如安卓端,web端控制可通过接口传参数让本地客户端发布esp32/dev/#所对应主题下的信息以此来控制ESP32。

问题:

1:esp32的json数据发送让客户端接收。

参考

Arduino-ESP32中的Json构造与解析_星水瓜瓜的博客-CSDN博客_arduino esp32 json

添加库

#include <ArduinoJson.h>

发送的是以字符串为形式的json数据

StaticJsonDocument<200> sensor_json;
sensor_json["sensor_val"] = hallRead();
sensor_json["sensor_val"] = cnt;
sensor_json["to"] = "starmelon";
String msg;
serializeJson(sensor_json, msg);

2:esp32连接不上emqx的mqtt服务器。

因为是在局域网下,emqx下的mqtt服务器就有其局域网地址,此局域网地址也就是emqx所在主机的ip地址,如果用的是路由器搭建的本地局域网且以IP自动分配的方式,每次都需要改服务器地址,连接手机热点也是一样。

默认域名:"broker-cn.emqx.io"  字符串格式

 问题来了,当我用这个默认域名做服务器地址,esp32确实能给设置的主题发消息,但我主机上的poho(一个监听软件)和客户端竟然确收不到消息了。

 

而只有当我回到最初的状态,使用局域网地址192.168.43.234,esp32能正常工作,poho和客户端也能正常工作。

正常的消息上报

 

实现:

 
#include <WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
#include <ArduinoJson.h>

StaticJsonDocument<200> sensor_json;
 String realmsg="";
int LED=2;
// 设置wifi接入信息(请根据您的WiFi信息进行修改)
const char* ssid = "realme";
const char* password = "12345678";
const char* mqttServer = "192.168.43.246";//本机ip地址
//发布的消息字段
typedef struct {
  int msg1;
  int msg2;
  int msg3;
}msg;
int count=0;//发布消息间隔
// 如以上MQTT服务器无法正常连接,请前往以下页面寻找解决方案
// http://www.taichi-maker.com/public-mqtt-broker/
//------------------全局变量定义-----------------
msg mymsg={123,45,6};//定义消息结构体
 
Ticker ticker;
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
//------------------全局变量定义-----------------
void tickerCount(){//Ticker回调函数
  count++;
  //数据测试
sensor_json["msg1"] = 12;
sensor_json["msg2"] =21;
sensor_json["msg3"] = 98;
serializeJson(sensor_json, realmsg);
}

void pubmsg( const String &topicString, const  String &messageString){
  char publishTopic[topicString.length() + 1];  
  strcpy(publishTopic, topicString.c_str());
  char publishMsg[messageString.length() + 1];   
  strcpy(publishMsg, messageString.c_str());
  
  // 实现ESP8266向主题发布信息
  if(mqttClient.publish(publishTopic, publishMsg)){
    Serial.println("Publish Topic:");Serial.println(publishTopic);
    Serial.println("Publish message:");Serial.println(publishMsg);    
  } else {
    Serial.println("Message Publish Failed."); 
  }
}
void setup() {
  pinMode(LED, OUTPUT);     // 设置板上LED引脚为输出模式
  digitalWrite(LED, LOW);  // 启动后关闭板上LED
  Serial.begin(9600);               // 启动串口通讯

  // Ticker定时对象
  ticker.attach(2, tickerCount); //每过2s调用其回调函数
  
  //设置ESP8266工作模式为无线终端模式
  WiFi.mode(WIFI_STA);
  
  // 连接WiFi
  connectWifi();
  
  // 设置MQTT服务器和端口号
  mqttClient.setServer(mqttServer, 1883);
  mqttClient.setCallback(receiveCallback);
 
  // 连接MQTT服务器
  connectMQTTserver();
}

void loop() {
  if (mqttClient.connected()) { // 如果开发板成功连接服务器
   if (count >= 2){
      pubmsg("device/date",realmsg);
      realmsg="";
      count = 0;
    }
    
    mqttClient.loop();          // 处理信息以及心跳   
  } else {                      // 如果开发板未能成功连接服务器
    connectMQTTserver();        // 则尝试连接服务器
  }
}

// 连接MQTT服务器并订阅信息
void connectMQTTserver(){
  // 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)
  String clientId = "esp8266-" + WiFi.macAddress();
 
  // 连接MQTT服务器
  if (mqttClient.connect(clientId.c_str())) { 
    Serial.println("MQTT Server Connected.");
    Serial.println("Server Address:");
    Serial.println(mqttServer);
    Serial.println("ClientId: ");
    Serial.println(clientId);
    subscribeTopic(); // 订阅指定主题
  } else {
    Serial.print("MQTT Server Connect Failed. Client State:");
    Serial.println(mqttClient.state());
    delay(5000);
  }   
}
// 收到信息后的回调函数
void receiveCallback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message Received [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println("");
  Serial.print("Message Length(Bytes) ");
  Serial.println(length);
  int temp=0;
  while(*topic){
    temp++;
    topic++;
  }
  Serial.println("主题长度:");
  Serial.println(temp);
  if(temp>11){
    if((char)topic[11]=='1'){
          if ((char)payload[0] == 'O' && (char)payload[1] == 'F') {     // 如果收到的信息以“1”为开始
            digitalWrite(LED, LOW);  // 则点亮LED。
          } else {                           
            digitalWrite(LED, HIGH); // 否则熄灭LED。
          }
    }
  }
}
 
// 订阅指定主题
void subscribeTopic(){
 
 
  
  // 通过串口监视器输出是否成功订阅主题1以及订阅的主题1名称
  if(mqttClient.subscribe("device/dev/#")){
    Serial.println("Subscrib Topic:");
    Serial.println("device/action");
  } else {
    Serial.print("Subscribe Fail...");
  }  
 
  // 通过串口监视器输出是否成功订阅主题2以及订阅的主题2名称
     
}
 
// ESP8266连接wifi
void connectWifi(){
 
  WiFi.begin(ssid, password);
 
  //等待WiFi连接,成功连接后输出成功信息
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Connected!");  
  Serial.println(""); 
}

效果:

 在poho上发布控制信息即可实现控制板载LED灯。

 

参考:

零基础入门学用物联网 – MQTT基础篇 – 目录 – 太极创客 (taichi-maker.com)

物联沃分享整理
物联沃-IOTWORD物联网 » ESP32(基于Arduino)通过EMQX的MQTT服务器上传信息与实现命令控制

发表评论