|
|
@@ -0,0 +1,166 @@
|
|
|
+#include "MQTTHandler.h"
|
|
|
+#include "WiFiConfig.h"
|
|
|
+
|
|
|
+
|
|
|
+extern Preferences preferences; // 引用外部定义的 preferences 对象
|
|
|
+
|
|
|
+WiFiClient espClient;
|
|
|
+PubSubClient client(espClient);
|
|
|
+
|
|
|
+const char* mqttUser = "yangfei";
|
|
|
+const char* mqttPassword = "yangfei";
|
|
|
+
|
|
|
+static int lastGpio18State = LOW; // 保存上一次 GPIO18 的电平状态,默认为 LOW
|
|
|
+
|
|
|
+int mqttConnectionAttempts = 0; // 用于记录 MQTT 连接失败的次数
|
|
|
+String targetDeviceID = ""; // 存储从订阅消息中接收的完整数据
|
|
|
+
|
|
|
+// unsigned long lowGpioStartTime = 0; // 记录 GPIO18 低电平的开始时间
|
|
|
+bool gpio18HighSent = false; // 标记是否已经发送过 ON 消息
|
|
|
+
|
|
|
+void mqttSetup() {
|
|
|
+ client.setServer(serverAddress.c_str(), serverPort);
|
|
|
+ client.setCallback(mqttCallback);
|
|
|
+
|
|
|
+ // 初始化 Preferences
|
|
|
+ preferences.begin("mqtt", false);
|
|
|
+ targetDeviceID = preferences.getString("targetDeviceID", ""); // 从存储中加载 targetDeviceID
|
|
|
+ if (targetDeviceID.length() > 0) {
|
|
|
+ Serial.println("[信息] 从存储中加载 targetDeviceID: " + targetDeviceID);
|
|
|
+ } else {
|
|
|
+ Serial.println("[信息] 未找到存储的 targetDeviceID");
|
|
|
+ }
|
|
|
+ preferences.end();
|
|
|
+}
|
|
|
+
|
|
|
+void mqttCallback(char* topic, byte* payload, unsigned int length) {
|
|
|
+ String message = "";
|
|
|
+ for (unsigned int i = 0; i < length; i++) {
|
|
|
+ message += (char)payload[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ String expectedTopic = "device/24G-" + deviceID + "/control"; // 订阅的主题
|
|
|
+ if (String(topic) == expectedTopic) {
|
|
|
+ Serial.println("[信息] 收到控制消息: " + message);
|
|
|
+ // 添加闪烁任务:发送第三个 MQTT 消息时闪烁 5 次
|
|
|
+ addBlinkTask(6);
|
|
|
+
|
|
|
+ // 将接收到的完整消息存储到 targetDeviceID
|
|
|
+ targetDeviceID = message;
|
|
|
+ Serial.println("[信息] 存储 targetDeviceID: " + targetDeviceID);
|
|
|
+
|
|
|
+ // 将 targetDeviceID 永久存储
|
|
|
+ preferences.begin("mqtt", false);
|
|
|
+ preferences.putString("targetDeviceID", targetDeviceID);
|
|
|
+ preferences.end();
|
|
|
+ Serial.println("[信息] 已永久存储 targetDeviceID: " + targetDeviceID);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool connectMQTT() {
|
|
|
+ Serial.println("[信息] 尝试连接到 MQTT 服务器...");
|
|
|
+ if (client.connect(("24G-" + deviceID).c_str(), mqttUser, mqttPassword)) {
|
|
|
+ Serial.println("[信息] MQTT 连接成功");
|
|
|
+ mqttConnectionAttempts = 0; // 连接成功时重置计数器
|
|
|
+ String topic = "device/24G-" + deviceID + "/control"; // 订阅的主题
|
|
|
+ client.subscribe(topic.c_str());
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ Serial.print("[错误] MQTT 连接失败, 错误码: ");
|
|
|
+ Serial.println("服务器地址: " + serverAddress);
|
|
|
+ Serial.println("服务器端口: " + String(serverPort));
|
|
|
+ Serial.println(client.state());
|
|
|
+
|
|
|
+ mqttConnectionAttempts++; // 连接失败时增加计数器
|
|
|
+ if (mqttConnectionAttempts >= 3) {
|
|
|
+ Serial.println("[错误] MQTT 连接失败三次,进入 Wi-Fi 配置模式...");
|
|
|
+ setupWiFiConfig(); // 进入 Wi-Fi 配置模式
|
|
|
+ mqttConnectionAttempts = 0; // 重置计数器
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void mqttLoop() {
|
|
|
+ client.loop();
|
|
|
+}
|
|
|
+
|
|
|
+// 实现发送 MQTT 消息的函数
|
|
|
+void sendMQTTMessage(const char* message) {
|
|
|
+ if (client.connected()) {
|
|
|
+ String topic = "device/24G-" + deviceID + "/gpio18"; // 定义 MQTT 主题
|
|
|
+ client.publish(topic.c_str(), message);
|
|
|
+
|
|
|
+ // 添加闪烁任务:发送第一个 MQTT 消息时闪烁 3 次
|
|
|
+ addBlinkTask(4);
|
|
|
+ Serial.println("[信息] 发送 MQTT 消息: " + String(message));
|
|
|
+ } else {
|
|
|
+ Serial.println("[错误] MQTT 未连接,无法发送消息");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 新增函数:发送继电器控制消息
|
|
|
+void sendRelayControlMessage(const char* state) {
|
|
|
+ if (client.connected() && targetDeviceID.length() > 0) {
|
|
|
+ // 组合发布主题:device/<targetDeviceID>/relay/control
|
|
|
+ String topic = "device/" + targetDeviceID + "/relay/control";
|
|
|
+ String message = String(state);
|
|
|
+ client.publish(topic.c_str(), message.c_str());
|
|
|
+
|
|
|
+ // 添加闪烁任务:发送第二个 MQTT 消息时闪烁 4 次
|
|
|
+ addBlinkTask(5);
|
|
|
+ Serial.println("[信息] 发送继电器控制消息到设备 " + targetDeviceID + ": " + message);
|
|
|
+ } else {
|
|
|
+ Serial.println("[错误] MQTT 未连接或 targetDeviceID 未设置,无法发送继电器控制消息");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 处理 GPIO18 状态并发送 high/low 消息
|
|
|
+void handleGpio18State() {
|
|
|
+ static int lastGpio18State = HIGH; // 保存上一次 GPIO18 的电平状态
|
|
|
+ int gpio18State = digitalRead(GPIO3_PIN); // 读取 GPIO18 的电平状态
|
|
|
+
|
|
|
+ // 如果电平状态发生变化
|
|
|
+ if (gpio18State != lastGpio18State) {
|
|
|
+ if (gpio18State == HIGH) {
|
|
|
+ sendMQTTMessage("high"); // 发送 high
|
|
|
+ } else {
|
|
|
+ sendMQTTMessage("low"); // 发送 low
|
|
|
+ }
|
|
|
+ lastGpio18State = gpio18State; // 更新上一次的电平状态
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// 处理继电器控制逻辑,发送 ON/OFF 消息
|
|
|
+void handleRelayControl() {
|
|
|
+ static int lastGpio18State = HIGH; // 保存上一次 GPIO18 的电平状态
|
|
|
+ static unsigned long lowGpioStartTime = 0; // 记录低电平的开始时间
|
|
|
+
|
|
|
+ int gpio18State = digitalRead(GPIO3_PIN); // 读取 GPIO18 的电平状态
|
|
|
+
|
|
|
+ // 如果电平状态发生变化
|
|
|
+ if (gpio18State != lastGpio18State) {
|
|
|
+ if (gpio18State == HIGH) {
|
|
|
+ // GPIO18 从低电平变为高电平,立即发送 ON
|
|
|
+ sendRelayControlMessage("ON");
|
|
|
+ Serial.println("发送:ON");
|
|
|
+ lowGpioStartTime = 0; // 重置低电平计时
|
|
|
+ } else if (gpio18State == LOW) {
|
|
|
+ // GPIO18 从高电平变为低电平,开始计时
|
|
|
+ lowGpioStartTime = millis(); // 记录低电平开始时间
|
|
|
+ }
|
|
|
+ lastGpio18State = gpio18State; // 更新上一次的电平状态
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果当前是低电平且计时已经开始
|
|
|
+ if (gpio18State == LOW && lowGpioStartTime != 0) {
|
|
|
+ if (millis() - lowGpioStartTime >= 15 * 60 * 1000) { // 15 分钟
|
|
|
+ // 低电平保持 15 分钟,发送 OFF
|
|
|
+ sendRelayControlMessage("OFF");
|
|
|
+ Serial.println("发送:OFF");
|
|
|
+ lowGpioStartTime = 0; // 重置计时
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|