Browse Source

上传文件至 ''

yangfei 1 year ago
parent
commit
e31d27ad8b
5 changed files with 462 additions and 0 deletions
  1. 111 0
      LEDHandler.cpp
  2. 33 0
      LEDHandler.h
  3. 166 0
      MQTTHandler.cpp
  4. 35 0
      MQTTHandler.h
  5. 117 0
      esp32_c6.ino

+ 111 - 0
LEDHandler.cpp

@@ -0,0 +1,111 @@
+#include "LEDHandler.h"
+
+// 变量定义
+std::queue<BlinkTask> blinkQueue;  // 闪烁任务队列
+bool isBlinking = false;  // 是否正在执行闪烁任务
+bool isConstantOn = false;  // 是否常亮
+unsigned long blinkStartTime = 0;  // 当前闪烁任务的开始时间
+int remainingBlinks = 0;  // 剩余闪烁次数
+int currentBlinkCount = 0;  // 当前任务的闪烁次数
+int pwmBrightness = 0;  // 当前 PWM 亮度值
+
+// 初始化 LED
+void setupLED() {
+  pinMode(LED_PIN, OUTPUT);  // 设置 LED 引脚为输出模式
+  digitalWrite(LED_PIN, LOW);  // 初始状态为关闭
+}
+
+// 添加闪烁任务
+void addBlinkTask(int blinkCount) {
+  BlinkTask task;
+  task.blinkCount = blinkCount;
+  blinkQueue.push(task);  // 将任务加入队列
+  //Serial.println("[信息] 添加闪烁任务,闪烁次数: " + String(blinkCount));
+}
+
+// 设置 LED 常亮或关闭
+void setConstantOn(bool constantOn) {
+  isConstantOn = constantOn;
+  if (isConstantOn) {
+    analogWrite(LED_PIN, pwmBrightness);  // 使用 PWM 控制亮度
+    Serial.println("[信息] LED 常亮,亮度: " + String(pwmBrightness));
+  } else {
+    analogWrite(LED_PIN, 0);  // 关闭 LED
+    Serial.println("[信息] LED 关闭");
+  }
+}
+
+// 设置 PWM 亮度
+void setBrightness(int brightness) {
+  if (brightness < 0) brightness = 0;
+  if (brightness > 255) brightness = 255;
+  pwmBrightness = brightness;
+
+  if (isConstantOn) {
+    // 如果 LED 常亮,更新亮度
+    analogWrite(LED_PIN, pwmBrightness);
+  }
+  Serial.println("[信息] 设置 PWM 亮度: " + String(pwmBrightness));
+}
+
+// 设置固定亮度(百分比)
+void setFixedBrightness(int percentage) {
+  if (percentage < 0) percentage = 0;
+  if (percentage > 100) percentage = 100;
+
+  // 将百分比转换为 PWM 值(0-255)
+  pwmBrightness = map(percentage, 0, 100, 0, 255);
+  setBrightness(pwmBrightness);  // 设置亮度
+  Serial.println("[信息] 设置固定亮度: " + String(percentage) + "%");
+}
+
+// 处理闪烁任务
+void processBlinkTasks() {
+  if (!isBlinking && !blinkQueue.empty() && !isConstantOn) {
+    // 如果没有正在执行的任务且队列不为空,且 LED 不常亮,开始执行下一个任务
+    BlinkTask currentTask = blinkQueue.front();
+    blinkQueue.pop();
+    remainingBlinks = currentTask.blinkCount * 2;  // 每次闪烁包括亮和灭
+    currentBlinkCount = currentTask.blinkCount;  // 记录当前任务的闪烁次数
+    blinkStartTime = millis();  // 记录任务开始时间
+    isBlinking = true;
+    //Serial.println("[信息] 开始执行闪烁任务,闪烁次数: " + String(currentTask.blinkCount));
+  }
+}
+
+// 控制 LED 闪烁
+void blinkLED() {
+  if (isConstantOn) {
+    // 如果 LED 需要常亮,直接返回
+    return;
+  }
+
+  unsigned long currentTime = millis();
+
+  if (isBlinking) {
+    // 计算每个闪烁周期的时间
+    unsigned long blinkDuration = 1000 / currentBlinkCount;  // 每个闪烁周期的总时间(亮 + 灭)
+    unsigned long halfBlinkDuration = blinkDuration / 2;  // 亮或灭的时间
+
+    // 计算当前闪烁周期
+    unsigned long elapsedTime = currentTime - blinkStartTime;
+    int currentCycle = elapsedTime / blinkDuration;
+
+    if (currentCycle < currentBlinkCount) {
+      // 控制 LED 状态
+      if (elapsedTime % blinkDuration < halfBlinkDuration) {
+        analogWrite(LED_PIN, pwmBrightness);  // 使用 PWM 控制亮度
+      } else {
+        analogWrite(LED_PIN, 0);  // 关闭 LED
+      }
+    } else {
+      // 当前任务完成
+      analogWrite(LED_PIN, 0);  // 确保 LED 关闭
+      isBlinking = false;
+      //Serial.println("[信息] 闪烁任务完成");
+    }
+  }
+
+  // 处理下一个任务
+  processBlinkTasks();
+}

+ 33 - 0
LEDHandler.h

@@ -0,0 +1,33 @@
+#ifndef LED_HANDLER_H
+#define LED_HANDLER_H
+
+#include <Arduino.h>
+#include <queue>  // 引入队列库
+
+// LED 引脚定义
+#define LED_PIN 5  // GPIO 5
+
+// 闪烁任务结构体
+struct BlinkTask {
+  int blinkCount;  // 闪烁次数
+};
+
+// 变量声明
+extern std::queue<BlinkTask> blinkQueue;  // 闪烁任务队列
+extern bool isBlinking;  // 是否正在执行闪烁任务
+extern bool isConstantOn;  // 是否常亮
+extern unsigned long blinkStartTime;  // 当前闪烁任务的开始时间
+extern int remainingBlinks;  // 剩余闪烁次数
+extern int currentBlinkCount;  // 当前任务的闪烁次数
+extern int pwmBrightness;  // 当前 PWM 亮度值
+
+// 函数声明
+void setupLED();  // 初始化 LED
+void addBlinkTask(int blinkCount);  // 添加闪烁任务
+void setConstantOn(bool constantOn);  // 设置 LED 常亮或关闭
+void setBrightness(int brightness);  // 设置 PWM 亮度
+void setFixedBrightness(int percentage);  // 设置固定亮度(百分比)
+void processBlinkTasks();  // 处理闪烁任务
+void blinkLED();  // 控制 LED 闪烁
+
+#endif

+ 166 - 0
MQTTHandler.cpp

@@ -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;  // 重置计时
+    }
+  }
+}

+ 35 - 0
MQTTHandler.h

@@ -0,0 +1,35 @@
+#ifndef MQTT_HANDLER_H
+#define MQTT_HANDLER_H
+
+#include <WiFi.h>
+#include <PubSubClient.h>
+#include <Preferences.h>  // 用于永久存储 targetDeviceID
+
+// 声明 targetDeviceID 为外部变量
+extern String targetDeviceID;
+
+extern String serverAddress;
+extern uint16_t serverPort;
+extern String deviceID;
+
+extern WiFiClient espClient;
+extern PubSubClient client;
+
+extern const char* mqttUser;
+extern const char* mqttPassword;
+
+// 声明 GPIO3_PIN
+#define GPIO3_PIN 3  // 定义 GPIO3 引脚
+
+void mqttSetup();
+bool connectMQTT();
+void mqttLoop();
+void mqttCallback(char* topic, byte* payload, unsigned int length);
+void sendMQTTMessage(const char* message);
+void sendRelayControlMessage(const char* state);
+String extractTargetDeviceIDFromMessage(const String& message);
+void handleGpio18State();  // 添加 handleGpio18State 的声明
+void handleRelayControl(); //开关继电器
+// 声明 addBlinkTask 为带参数的函数
+void addBlinkTask(int blinkCount);  // 添加闪烁任务,接受一个 int 参数
+#endif

+ 117 - 0
esp32_c6.ino

@@ -0,0 +1,117 @@
+#include "WiFiConfig.h"
+#include "MQTTHandler.h"
+#include "LEDHandler.h"  // 引入 LEDHandler
+#include "WatchdogHandler.h"  // 引入 WatchdogHandler
+
+#define BUTTON_PIN 4      // 重置引脚4  //高低电平3  //代开发信号5
+#define WIFI_CONNECT_TIMEOUT 30000
+#define BUTTON_HOLD_TIME 1000
+#define DEBOUNCE_DELAY 50
+// LED 连接的 GPIO
+#define LED_PIN 5  // GPIO 5
+
+// 数据量统计
+unsigned long lastCheckTime = 0;  // 上次检查时间
+
+long unsigned int lastDebounceTimeNew = 0;
+int lastButtonStateNew = HIGH;
+bool resetModeActivated = false;
+
+int lastGPIO18State = LOW;  // 保存上一次 GPIO18 的电平状态
+
+void setup() {
+  Serial.begin(115200);
+  delay(1000); // 等待串口初始化完成
+  pinMode(BUTTON_PIN, INPUT_PULLUP);
+  pinMode(GPIO3_PIN, INPUT);  // 设置 GPIO18 为输入模式
+  pinMode(LED_PIN, OUTPUT);   // 设置 LED 引脚为输出模式
+
+  // 初始化 LED
+  setupLED();  // 确保调用 setupLED() 来初始化 LED
+  // 设置 LED 亮度为 20%
+  setFixedBrightness(5);  // 20% 亮度
+
+  // 初始化看门狗
+  setupWatchdog();
+
+  // 加载服务器参数
+  loadServerParams();
+
+  // 循环连接 WiFi 和进入配置模式
+  while (true) {
+    // 尝试连接 WiFi,超时时间为 30 秒
+    if (connectWiFiWithTimeout(30000)) {
+      break;  // 连接成功,退出循环
+    } else {
+      Serial.println("[信息] Wi-Fi 连接失败,进入配置模式...");
+      setupWiFiConfig();  // 进入配置模式,超时时间为 60 秒
+    }
+  }
+
+  // 初始化 MQTT 客户端
+  mqttSetup();
+
+  // 尝试连接到 MQTT 服务器
+  if (!connectMQTT()) {
+    Serial.println("[错误] MQTT 连接失败");
+  }
+  Serial.println("[信息] 已永久存储 targetDeviceID: " + targetDeviceID);
+}
+
+void loop() {
+  static unsigned long lastCheckTime = 0;  // 记录上次检查时间
+  unsigned long currentTime = millis();
+
+  // 按钮去抖逻辑
+  int buttonState = digitalRead(BUTTON_PIN);
+  if (buttonState != lastButtonStateNew) {
+    lastDebounceTimeNew = currentTime;
+  }
+  if ((currentTime - lastDebounceTimeNew) > DEBOUNCE_DELAY) {
+    if (buttonState == LOW && !resetModeActivated) {
+      uint32_t pressStartTime = millis();
+      while (digitalRead(BUTTON_PIN) == LOW) {
+        if (millis() - pressStartTime >= BUTTON_HOLD_TIME) {
+          Serial.println("[信息] 按钮长按,进入配置模式...");
+          setupWiFiConfig();
+          resetModeActivated = true;
+          break;
+        }
+      }
+    }
+  }
+  lastButtonStateNew = buttonState;
+  if (resetModeActivated) {
+    resetModeActivated = false;
+    return;
+  }
+
+  // 每 5 秒执行一次的任务(非阻塞)
+  if (currentTime - lastCheckTime >= 5000) {
+    lastCheckTime = currentTime;  // 更新上次检查时间
+
+    // 处理 GPIO18 状态
+    handleGpio18State();  // 调用 handleGpio18State 函数
+    handleRelayControl(); // 开关继电器
+
+    // MQTT 客户端循环
+    if (!client.connected()) {
+      if (!connectMQTT()) {
+        Serial.println("[错误] MQTT 连接失败");
+        setupWiFiConfig();  // 进入配置模式,超时时间为 60 秒
+      }
+    } else {
+      mqttLoop();  // 继续 MQTT 循环
+    }
+
+    // 喂狗操作
+    feedWatchdog();
+    addBlinkTask(1);
+
+    //Serial.println("[信息] 主循环运行中……");
+    //Serial.println("[信息] 已永久存储 targetDeviceID: " + targetDeviceID);
+  }
+
+  // LED 闪烁逻辑
+  blinkLED();  // 确保 blinkLED() 被调用
+}