MQTTHandler.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include "MQTTHandler.h"
  2. #include "WiFiConfig.h"
  3. extern Preferences preferences; // 引用外部定义的 preferences 对象
  4. WiFiClient espClient;
  5. PubSubClient client(espClient);
  6. const char* mqttUser = "yangfei";
  7. const char* mqttPassword = "yangfei";
  8. static int lastGpio18State = LOW; // 保存上一次 GPIO18 的电平状态,默认为 LOW
  9. int mqttConnectionAttempts = 0; // 用于记录 MQTT 连接失败的次数
  10. String targetDeviceID = ""; // 存储从订阅消息中接收的完整数据
  11. bool gpio18HighSent = false; // 标记是否已经发送过 ON 消息
  12. void mqttSetup() {
  13. client.setServer(serverAddress.c_str(), serverPort);
  14. client.setCallback(mqttCallback);
  15. // 初始化 Preferences
  16. preferences.begin("mqtt", false);
  17. targetDeviceID = preferences.getString("targetDeviceID", ""); // 从存储中加载 targetDeviceID
  18. if (targetDeviceID.length() > 0) {
  19. Serial.println("[信息] 从存储中加载 targetDeviceID: " + targetDeviceID);
  20. } else {
  21. Serial.println("[信息] 未找到存储的 targetDeviceID");
  22. }
  23. preferences.end();
  24. }
  25. void mqttCallback(char* topic, byte* payload, unsigned int length) {
  26. String message = "";
  27. for (unsigned int i = 0; i < length; i++) {
  28. message += (char)payload[i];
  29. }
  30. String expectedTopic = "device/24G-" + deviceID + "/control"; // 订阅的主题
  31. if (String(topic) == expectedTopic) {
  32. Serial.println("[信息] 收到控制消息: " + message);
  33. // 添加闪烁任务:发送第三个 MQTT 消息时闪烁 5 次
  34. addBlinkTask(6);
  35. // 将接收到的完整消息存储到 targetDeviceID
  36. targetDeviceID = message;
  37. Serial.println("[信息] 存储 targetDeviceID: " + targetDeviceID);
  38. // 将 targetDeviceID 永久存储
  39. preferences.begin("mqtt", false);
  40. preferences.putString("targetDeviceID", targetDeviceID);
  41. preferences.end();
  42. Serial.println("[信息] 已永久存储 targetDeviceID: " + targetDeviceID);
  43. }
  44. }
  45. bool connectMQTT() {
  46. Serial.println("[信息] 尝试连接到 MQTT 服务器...");
  47. if (client.connect(("24G-" + deviceID).c_str(), mqttUser, mqttPassword)) {
  48. Serial.println("[信息] MQTT 连接成功");
  49. mqttConnectionAttempts = 0; // 连接成功时重置计数器
  50. String topic = "device/24G-" + deviceID + "/control"; // 订阅的主题
  51. client.subscribe(topic.c_str());
  52. return true;
  53. } else {
  54. Serial.print("[错误] MQTT 连接失败, 错误码: ");
  55. Serial.println("服务器地址: " + serverAddress);
  56. Serial.println("服务器端口: " + String(serverPort));
  57. Serial.println(client.state());
  58. mqttConnectionAttempts++; // 连接失败时增加计数器
  59. if (mqttConnectionAttempts >= 3) {
  60. Serial.println("[错误] MQTT 连接失败三次,进入 Wi-Fi 配置模式...");
  61. setupWiFiConfig(); // 进入 Wi-Fi 配置模式
  62. mqttConnectionAttempts = 0; // 重置计数器
  63. }
  64. return false;
  65. }
  66. }
  67. void mqttLoop() {
  68. client.loop();
  69. }
  70. // 实现发送 MQTT 消息的函数
  71. void sendMQTTMessage(const char* message) {
  72. if (client.connected()) {
  73. String topic = "device/24G-" + deviceID + "/gpio18"; // 定义 MQTT 主题
  74. client.publish(topic.c_str(), message);
  75. // 添加闪烁任务:发送第一个 MQTT 消息时闪烁 3 次
  76. addBlinkTask(4);
  77. Serial.println("[信息] 发送 MQTT 消息: " + String(message));
  78. } else {
  79. Serial.println("[错误] MQTT 未连接,无法发送消息");
  80. }
  81. }
  82. // 新增函数:发送继电器控制消息
  83. void sendRelayControlMessage(const char* state) {
  84. if (client.connected() && targetDeviceID.length() > 0) {
  85. // 组合发布主题:device/<targetDeviceID>/relay/control
  86. String topic = "device/" + targetDeviceID + "/relay/control";
  87. String message = String(state);
  88. client.publish(topic.c_str(), message.c_str());
  89. // 添加闪烁任务:发送第二个 MQTT 消息时闪烁 4 次
  90. addBlinkTask(5);
  91. Serial.println("[信息] 发送继电器控制消息到设备 " + targetDeviceID + ": " + message);
  92. } else {
  93. Serial.println("[错误] MQTT 未连接或 targetDeviceID 未设置,无法发送继电器控制消息");
  94. }
  95. }
  96. // 处理 GPIO18 状态并发送 high/low 消息
  97. void handleGpio18State() {
  98. static int lastGpio18State = HIGH; // 保存上一次 GPIO18 的电平状态
  99. int gpio18Voltage = analogRead(GPIO3_PIN); // 读取 GPIO18 的电压值
  100. int gpio18State = (gpio18Voltage > 2 * 1023 / 3.3) ? HIGH : LOW; // 判断高低电平
  101. // 如果电平状态发生变化
  102. if (gpio18State != lastGpio18State) {
  103. if (gpio18State == HIGH) {
  104. sendMQTTMessage("high"); // 发送 high
  105. } else {
  106. sendMQTTMessage("low"); // 发送 low
  107. }
  108. lastGpio18State = gpio18State; // 更新上一次的电平状态
  109. }
  110. }
  111. // 处理继电器控制逻辑,发送 ON/OFF 消息
  112. void handleRelayControl() {
  113. static int lastGpio18State = HIGH; // 保存上一次 GPIO18 的电平状态
  114. static unsigned long lowGpioStartTime = 0; // 记录低电平的开始时间
  115. int gpio18Voltage = analogRead(GPIO3_PIN); // 读取 GPIO18 的电压值
  116. int gpio18State = (gpio18Voltage > 2 * 1023 / 3.3) ? HIGH : LOW; // 判断高低电平
  117. // 如果电平状态发生变化
  118. if (gpio18State != lastGpio18State) {
  119. if (gpio18State == HIGH) {
  120. // GPIO18 从低电平变为高电平,立即发送 ON
  121. sendRelayControlMessage("ON");
  122. Serial.println("发送:ON");
  123. lowGpioStartTime = 0; // 重置低电平计时
  124. } else if (gpio18State == LOW) {
  125. // GPIO18 从高电平变为低电平,开始计时
  126. lowGpioStartTime = millis(); // 记录低电平开始时间
  127. }
  128. lastGpio18State = gpio18State; // 更新上一次的电平状态
  129. }
  130. // 如果当前是低电平且计时已经开始
  131. if (gpio18State == LOW && lowGpioStartTime != 0) {
  132. if (millis() - lowGpioStartTime >= 15 * 60 * 1000) { // 15 分钟
  133. // 低电平保持 15 分钟,发送 OFF
  134. sendRelayControlMessage("OFF");
  135. Serial.println("发送:OFF");
  136. lowGpioStartTime = 0; // 重置计时
  137. }
  138. }
  139. }