ESP32实现(MQTT Client)连接物联网平台(EMQX)

news2024/11/15 13:31:18

目录

概述

1 配置EMQX服务器

1.1 搭建EMQX服务器

1.2 配置服务器参数

2 ESP32实现MQTT Client

2.1 创建MQTT Client项目

2.2 实现MQTT Client

2.3 ESP32连接EMQX

3 ESP32Client实现广播和订阅消息

3.1 广播消息

3.1.1 编写广播消息函数

3.1.2 下载和验证

3.1.3 订阅ESP32 Client消息

3.2 订阅消息

3.2.1 MQTT.fx定义广播消息

3.2.2 ESP32 Client订阅消息

3.2.3 下载和验证

4 ESP32控制外围硬件

4.1 功能描述

4.2 代码实现

4.3 下载和验证

5 源代码文件


使用ESP32和EMQX搭建物联网平台,实现消息发布和订阅功能

概述

本文主要介绍使用ESP32实现MQTT Client, 连接至使用EMQX自建服务器上,使用MQTT.fx模拟客户端发布和订阅来自ESP32实现MQTT Client的消息,同时ESP32实现MQTT Client也订阅来自MQTT.fx的消息。还使用MQTT.fx发布消息的方式来触发ESP32控制外围设备。

1 配置EMQX服务器

1.1 搭建EMQX服务器

登录如下网址,下载EMQX数据包,搭建一台自己的EMQX服务器。

https://www.emqx.io/zh/downloads?os=Ubuntu

笔者使用ubuntu系统搭建了一台EMQX服务器,其具体步骤如下:

1.2 配置服务器参数

安装完成服务器,登录系统

在客户端认证 pannel 添加用户端信息,笔者添加了两个mqtt_user,分别为:

mqtt_user-1 : 用于MQTT.fx 客户端订阅和发布消息

mqtt_user-2: 用于ESP32 客户端订阅和发布消息

配置参数时,记录下用户名和密码信息,两个参数对应:

AccessToken: 用户名

ProjectKey: 密码

2 ESP32实现MQTT Client

2.1 创建MQTT Client项目

打开Arduino IED, 在Tools--->Mange librarys下,搜索AsyncMqtt_Generic这个SDK,然后安装这个SDK.

安装完毕之后,在对应的SDK提供的Example中选择一个模版,然后添加自己的代码。

2.2 实现MQTT Client

笔者选择 FullyFeature_ESP32.ino 作为模版项目。使用Arduino IED打开项目文件,如下参数需要根据实际情况一一配置。

参数功能介绍如下:

参数描述
WIFI_SSIDwifi 账号名称
WIFI_PASSWORDwifi密码
MQTT_HOSTMQTT服务器地址
USERNAME设备用户名
PASSWORD设备用户认证密码

2.3 ESP32连接EMQX

配置好参数后,下载代码至ESP32。下载代码时注意,正确的选择设备及其对应的端口号。下载完毕代码后,ESP32会连接EMQX服务器

在ESP32的log输出端口也能看见相应的信息:

3 ESP32Client实现广播和订阅消息

3.1 广播消息

3.1.1 编写广播消息函数

实现功能:ESP32 MQTT Client 广播温度湿度数据

{
    "temperature": 22.5,
    "light": 2000,
    "humidity": 62.3
}

代码实现:

void pubSensors()
{
  mqttClient.publish("temperature", 0, true, "22.5");
​
  mqttClient.publish("humidity", 1, true, "62.5");
​
  mqttClient.publish("light", 2, true, "2000");
}

在loop函数中,调用该广播函数:

3.1.2 下载和验证

下载代码至ESP32:

下载完成后,登录到EMQX服务器上,可以看见,ESP32 MQTT Client已经发布信息至服务器:

3.1.3 订阅ESP32 Client消息

使用MQTT.fx订阅ESP32 Client消息,具体方法如下:

在EMQX上可以看见mqtt_user1:

使用MQTT.fx分别订阅如下Topic

{ 
   "temperature", 
   "light", 
   "humidity" 
}

可以看见MQTT.fx收到ESP32发布的消息,在EMQX服务器上同时可以看见如下信息:mqtt_user1已经订阅了这三个Topic。

3.2 订阅消息

3.2.1 MQTT.fx定义广播消息

在 MQTT.fx定义广播消息的类型,其分别为:

bool 类型消息: true/false

{
"switch": true
}

字符串型消息(attributes):"ON"/"OFF"

{
"attributes": "ON"
}

3.2.2 ESP32 Client订阅消息

ESP32 Client实现订阅消息功能,其具体代码如下:

void subscribeSensors()
{
  mqttClient.subscribe("attributes", 1);
  mqttClient.subscribe("switch", 1);
}

函数被onMqttConnect()函数调用

3.2.3 下载和验证

编译代码下载到ESP32,登录EMQX查看消息情况。在服务器上看见mqtt_user2已经订阅了这两条Topic

4 ESP32控制外围硬件

4.1 功能描述

使用ESP32订阅的Topic: switch功能控制LED, 当ESP32收到:

订阅消息-1: 打开led

{
    "switch": true
}

订阅消息-2: 关闭led

{
    "switch": false
}

4.2 代码实现

代码214: 解析playload为json格式

代码221:判断是否包含key

代码224:比较value值,value = true ,执行开灯

4.3 下载和验证

编译代码,下载至ESP32中,然后在MQTT.fx中广播消息

1)验证开灯功能

2)验证关灯功能

5 源代码文件

#include <ArduinoJson.h>
#include "defines.h"

#include <WiFi.h>

extern "C"
{
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
}
#include <AsyncMqtt_Generic.h>

#define MQTT_HOST         IPAddress(192, 168, 1, 11)
#define MQTT_PORT         1883

#define WIFI_SSID         ""
#define WIFI_PASSWORD     ""

#define USERNAME          "mqtt_user2"
#define PASSWORD          "123456"


// 设置 LED GPIO 引脚
const int LED_PIN = 2;

const char *PubTopic  = "async-mqtt/ESP32_Pub";               // Topic to publish

AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;

unsigned long timer1 = millis();
const int report_interval = 1000 * 30;



void pubSensors();
void subscribeSensors();


void connectToWifi()
{
  Serial.println("Connecting to Wi-Fi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}

void connectToMqtt()
{
  Serial.println("Connecting to MQTT...");
  mqttClient.connect();
}

void WiFiEvent(WiFiEvent_t event)
{
  switch (event)
  {
#if USING_CORE_ESP32_CORE_V200_PLUS

    case ARDUINO_EVENT_WIFI_READY:
      Serial.println("WiFi ready");
      break;

    case ARDUINO_EVENT_WIFI_STA_START:
      Serial.println("WiFi STA starting");
      break;

    case ARDUINO_EVENT_WIFI_STA_CONNECTED:
      Serial.println("WiFi STA connected");
      break;

    case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
    case ARDUINO_EVENT_WIFI_STA_GOT_IP:
      Serial.println("WiFi connected");
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
      connectToMqtt();
      break;

    case ARDUINO_EVENT_WIFI_STA_LOST_IP:
      Serial.println("WiFi lost IP");
      break;

    case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
      Serial.println("WiFi lost connection");
      xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
      xTimerStart(wifiReconnectTimer, 0);
      break;
#else

    case SYSTEM_EVENT_STA_GOT_IP:
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
      connectToMqtt();
      break;

    case SYSTEM_EVENT_STA_DISCONNECTED:
      Serial.println("WiFi lost connection");
      xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
      xTimerStart(wifiReconnectTimer, 0);
      break;
#endif

    default:
      break;
  }
}

void printSeparationLine()
{
  Serial.println("************************************************");
}

void onMqttConnect(bool sessionPresent)
{
  Serial.print("Connected to MQTT broker: ");
  Serial.print(MQTT_HOST);
  Serial.print(", port: ");
  Serial.println(MQTT_PORT);
  Serial.print("PubTopic: ");
  Serial.println(PubTopic);

  printSeparationLine();
  Serial.print("Session present: ");
  Serial.println(sessionPresent);

  uint16_t packetIdSub = mqttClient.subscribe(PubTopic, 2);
  Serial.print("Subscribing at QoS 2, packetId: ");
  Serial.println(packetIdSub);

  mqttClient.publish(PubTopic, 0, true, "ESP32 Test");
  Serial.println("Publishing at QoS 0");

  uint16_t packetIdPub1 = mqttClient.publish(PubTopic, 1, true, "test 2");
  Serial.print("Publishing at QoS 1, packetId: ");
  Serial.println(packetIdPub1);

  uint16_t packetIdPub2 = mqttClient.publish(PubTopic, 2, true, "test 3");
  Serial.print("Publishing at QoS 2, packetId: ");
  Serial.println(packetIdPub2);

  printSeparationLine();

  subscribeSensors();
}

void onMqttDisconnect(AsyncMqttClientDisconnectReason reason)
{
  (void) reason;

  Serial.println("Disconnected from MQTT.");

  if (WiFi.isConnected())
  {
    xTimerStart(mqttReconnectTimer, 0);
  }
}

void onMqttSubscribe(const uint16_t& packetId, const uint8_t& qos)
{
  Serial.println("Subscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
  Serial.print("  qos: ");
  Serial.println(qos);
}

void onMqttUnsubscribe(const uint16_t& packetId)
{
  Serial.println("Unsubscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}

void onMqttMessage(char* topic, char* payload, const AsyncMqttClientMessageProperties& properties,
                   const size_t& len, const size_t& index, const size_t& total)
{
  (void) payload;

  Serial.println("Publish received.");
  Serial.print("  topic: ");
  Serial.println(topic);
  Serial.print("  qos: ");
  Serial.println(properties.qos);
  Serial.print("  dup: ");
  Serial.println(properties.dup);
  Serial.print("  retain: ");
  Serial.println(properties.retain);
  Serial.print("  len: ");
  Serial.println(len);
  Serial.print("  index: ");
  Serial.println(index);
  Serial.print("  total: ");
  Serial.println(total);

  Serial.println("attributes get response: "); 
  Serial.println(payload);

  DynamicJsonDocument doc(512);
  DeserializationError error = deserializeJson(doc, payload);
  if (error)
  {
      Serial.printf("deserialize error: %s\n", error.f_str());
      return;
  }

  JsonObject obj = doc.as<JsonObject>();
  if (obj.containsKey("switch"))
  {
      if (obj["switch"] == true)
      {
          Serial.println("switch ON");
          // todo 输出 GPIO 控制继电器
          digitalWrite(LED_PIN, HIGH);
      }
      else
      {
          Serial.println("switch OFF");
          // todo 输出 GPIO 控制继电器
          digitalWrite(LED_PIN, LOW);
      }
  }

}

void onMqttPublish(const uint16_t& packetId)
{
  Serial.println("Publish acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}

void setup()
{
  Serial.begin(115200);

  while (!Serial && millis() < 5000);

  Serial.print("\nStarting FullyFeature_ESP32 on ");
  Serial.println(ARDUINO_BOARD);
  Serial.println(ASYNC_MQTT_GENERIC_VERSION);

  mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0,
                                    reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
  wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0,
                                    reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));

  WiFi.onEvent(WiFiEvent);

  mqttClient.onConnect(onMqttConnect);
  mqttClient.onDisconnect(onMqttDisconnect);
  mqttClient.onSubscribe(onMqttSubscribe);
  mqttClient.onUnsubscribe(onMqttUnsubscribe);
  mqttClient.onMessage(onMqttMessage);
  mqttClient.onPublish(onMqttPublish);

  mqttClient.setServer(MQTT_HOST, MQTT_PORT);
  mqttClient.setCredentials(USERNAME,PASSWORD);
  mqttClient.setClientId( USERNAME );

  connectToWifi();

    // 拉低 LED
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

}

void subscribeSensors()
{
  mqttClient.subscribe("attributes", 1);
  mqttClient.subscribe("switch", 1);
}

void pubSensors()
{
  mqttClient.publish("temperature", 0, true, "22.5");

  mqttClient.publish("humidity", 1, true, "62.5");

  mqttClient.publish("light", 2, true, "2000");
}

void loop()
{
    // 按间隔时间上报传感器数据
    if (millis() - timer1 > report_interval)
    {
        timer1 = millis();
        pubSensors();
    }  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1527515.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows11安装Msql8.0版本详细安装步骤!

文章目录 前言一、下载Mysql二、安装Mysql三、登录验证三、环境变量配置总结 前言 每次搭建新环境的时候&#xff0c;都需要网上搜寻安装的步骤教程&#xff01;为了以后方便查阅&#xff01;那么本次就记录一下Windows11安装Msql8.0的详细步骤&#xff01;也希望能帮助到有需…

蓝桥杯物联网竞赛_STM32L071_12_按键中断与串口中断

按键中断&#xff1a; 将按键配置成GPIO_EXTI中断即外部中断 模式有三种上升沿&#xff0c;下降沿&#xff0c;上升沿和下降沿都会中断 external -> 外部的 interrupt -> 打断 trigger -> 触发 detection -> 探测 NVIC中将中断线ENABLE 找接口函数 在接口函数中写…

Apache Doris 2.1 核心特性 Variant 数据类型技术深度解析

在最新发布的 Apache Doris 2.1 新版本中&#xff0c;我们引入了全新的数据类型 Variant&#xff0c;对半结构化数据分析能力进行了全面增强。无需提前在表结构中定义具体的列&#xff0c;彻底改变了 Doris 过去基于 String、JSONB 等行存类型的存储和查询方式。为了让大家快速…

redis-黑马点评-商户查询缓存

缓存&#xff1a;cache public Result queryById(Long id) {//根据id在redis中查询数据String s redisTemplate.opsForValue().get(CACHE_SHOP_KEY id);//判断是否存在if (!StrUtil.isBlank(s)) {//将字符串转为bean//存在&#xff0c;直接返回Shop shop JSONUtil.toBean(s, …

Linux课程四课---Linux第一个小程序(进度条)

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

Windows影子账户

Windows影子账户 先检查administrator账户有没有被禁用&#xff0c;如果administrator账户被禁用 所属组内的账户都会被禁用&#xff0c;导致影子账户无法登录 创建隐藏用户 加入管理员组 隐藏用户创建方法&#xff1a; net user 用户名$ 密码 /add 输入 regedit打开注册表…

微信小程序简单实现手势左右滑动和点击滑动步骤条功能

使用微信小程序实现左右滑动功能&#xff0c;自定义顶部图案&#xff0c;点击文字滑动和手势触屏滑动&#xff0c;功能简单&#xff0c;具体实现代码如下所示&#xff1a; 1、wxss代码&#xff1a; /* 步骤条 */ .tab-box {display: flex;flex-direction: row;position: fix…

springboot整合springsecurity,从数据库中认证

概述&#xff1a;springsecurity这个东西太容易忘了&#xff0c;这里写点东西&#xff0c;避免忘掉 目录 第一步&#xff1a;引入依赖 第二步&#xff1a;创建user表 第三步&#xff1a;创建一个用户实体类&#xff08;User&#xff09;和一个用于访问用户数据的Repository…

Midjourney 和 Dall-E 的优劣势比较

Midjourney 和 Dall-E 的优劣势比较 Midjourney 和 Dall-E 都是强大的 AI 绘画工具&#xff0c;可以根据文本描述生成图像。 它们都使用深度学习模型来理解文本并将其转换为图像。 但是&#xff0c;它们在功能、可用性和成本方面存在一些差异。 Midjourney 优势: 可以生成更…

yocto编译测试

源码下载 git clone -b gatesgarth git://git.yoctoproject.org/poky lkmaolkmao-virtual-machine:~/yocto$ git clone -b gatesgarth git://git.yoctoproject.org/poky Cloning into poky... remote: Enumerating objects: 640690, done. remote: Counting objects: 100% (13…

【漏洞复现】CVE-2004-2761:使用弱哈希算法签名的 SSL 证书(SSL Certificate Signed Using Weak Hashing Algorithm)

概要&#xff1a;本次复现是针对编号为CVE-2004-2761的漏洞&#xff0c;由于条件有限&#xff0c;本次复现通过创建自签名证书进行操作。 问题描述&#xff1a;证书链中的 SSL 证书使用弱哈希算法进行签名。 1 环境搭建 本次复现环境在Linux平台下使用Nginx进行环境的搭建&…

ModbusTCP转Profinet网关高低字节交换切换

背景&#xff1a;在现场设备与设备通迅之间通常涉及到从一种字节序&#xff08;大端或小端&#xff09;转换到另一种字节序。大端字节序是指高位字节存储在高地址处&#xff0c;而小端字节序是指低位字节存储在低地址处。在不动原有程序而又不想或不能添加程序下可选用ModbusTC…

Java安装及环境配置详细教程

1.1 下载 Java 安装包 官网下载链接[点击跳转] 建议下载202版本&#xff0c;因为202版本之后的 Oracle JDK 是商用收费的&#xff08;个人使用不收费&#xff09; 1.2 勾选红框中内容&#xff0c;然后点击下方下载 1.3 如果没有登录 Oracle 则会跳转到该页面&#xff0c;因为…

爬虫 Day2

resp.close()#关掉resp 一requests入门 &#xff08;一&#xff09; 用到的网页&#xff1a;豆瓣电影分类排行榜 - 喜剧片 import requestsurl "https://movie.douban.com/j/chart/top_list" #参数太长&#xff0c;重新封装参数 param {"type": "…

Python环境下基于机器学习(决策树,随机森林,KNN和SVM)的轴承故障诊断

故障特征提取就是从振动信号中提取时、频域统计特征&#xff0c;并利用能量值、谱峭度、幅值等指标&#xff0c;提取出故障特征集。对故障特征值进行全面准确地提取&#xff0c;是提高诊断精度的关键&#xff0c;也是整个滚动轴承故障诊断过程中较困难的部分。 一些常见的时域…

Redis 过期删除策略和内存淘汰策略有什么区别?

资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) Redis 的「内存淘汰策略」和「过期删除策略」&#xff0c;很多小伙伴容易混淆&#xff0c;这两个机制虽然都是做删除的操作&#xff0c;但是触发的条件和使用的策略都是不同的。 今天就跟大家理一理&…

如何将OpenCV Java 与Eclipse结合使用

返回目录&#xff1a;OpenCV系列文章目录 上一篇&#xff1a;OpenCV-Java 开发简介 下一篇&#xff1a; 正文&#xff1a; 警告&#xff1a;本教程可以包含过时的信息。 从 2.4.4 版本开始&#xff0c;OpenCV 支持 Java。在本教程中&#xff0c;我将解释如何设置开发环境&a…

信息系统项目管理师019:存储和数据库(2信息技术发展—2.1信息技术及其发展—2.1.3存储和数据库)

文章目录 2.1.3 存储和数据库1.存储技术2.数据结构模型3.常用数据库类型4.数据仓库 记忆要点总结 2.1.3 存储和数据库 1.存储技术 存储分类根据服务器类型分为&#xff1a;封闭系统的存储和开放系统的存储。封闭系统主要指大型机等服务器。开放系统指基于包括麒麟、欧拉、UNIX…

使用 ONLYOFFICE API 构建 Java 转换器,在 Word 和 PDF 之间进行转换

文章作者&#xff1a;ajun 随着文档处理需求的增加&#xff0c;格式转换成为了一个重要的需求点。由于PDF格式具有跨平台、不易被篡改的特性&#xff0c;将Word格式(.docx)转换为PDF格式(.pdf)的需求尤为强烈。ONLYOFFICE作为一个强大的办公套件&#xff0c;提供了这样的转换功…

Verilog——信号类型

Verilog HDL 的信号类型有很多种&#xff0c;主要包括两种数据类型&#xff1a;线网类型 (net type) 和寄存器类型 &#xff08; reg type &#xff09;。在进行工程设计的过程中也只会使用到这两个类型的信号。 4.1 信号位宽 定义信号类型的同时&#xff0c;必须定义好信号…