Moone 发表于 前天 18:27

[FireBeetle 2 ESP32-C5]ESP32-C5 WiFi网络状态监测器

本帖最后由 Moone 于 2025-10-3 18:36 编辑

WiFi网络状态监测器项目概述
本项目是一个基于FireBeetle 2 ESP32-C5开发套件和OLED显示屏的WiFi网络状态监测器,实时显示网络连接状态、信号质量、时间信息等,具有多页面显示和动画切换效果。
系统整体流程图


流程说明系统启动阶段

[*]初始化硬件:配置OLED显示屏引脚和通信参数,设置串口通信
[*]显示欢迎界面:展示设备名称、版本信息,建立品牌认知
[*]连接WiFi:尝试连接到预设的WiFi网络,包含超时处理机制
连接结果处理

[*]连接成功:配置NTP时间服务,确保时间同步准确
[*]连接失败:显示错误提示,但系统继续运行以便后续重连
主循环处理核心

[*]非阻塞设计:所有任务基于时间间隔执行,避免单个任务阻塞系统
[*]模块化处理:各功能模块独立运行,通过标志位协调
[*]状态驱动更新:只有状态变化时才触发显示更新,优化性能
详细功能流程图说明
项目结构
WiFi_Monitor/
├── WiFi_Monitor.ino # 主程序文件
├── WiFiConnection.h # WiFi连接管理模块
├── DisplayManager.h # 显示控制模块
├── NetworkTest.h # 网络测试模块
├── TimeManager.h # 时间管理模块
├── Configuration.h # 配置参数模块
└── README.md # 项目说明文档
系统初始化流程


功能模块详细说明
1. 配置参数模块 (Configuration.h)
/**
* 系统配置参数定义
* 包含WiFi配置、设备个性化设置、时间配置等常量
*/

// WiFi网络配置
const char* WIFI_SSID = "WiFi名称";      // 替换为您的WiFi名称
const char* WIFI_PWD = "WiFi密码";       // 替换为您的WiFi密码

// 设备个性化设置
const char* DEVICE_NAME = "Moone Monitor";
const char* OWNER_NAME = "Moone";

// NTP时间服务器配置
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 8 * 3600;      // UTC+8 北京时间
const int daylightOffset_sec = 0;

// 硬件引脚配置
#define I2C_SDA 9
#define I2C_SCL 10

// 时间间隔配置(毫秒)
const unsigned long PING_INTERVAL = 8000;         // Ping测试间隔
const unsigned long WIFI_UPDATE_INTERVAL = 2000;    // WiFi状态更新间隔
const unsigned long DISPLAY_UPDATE_INTERVAL = 500;// 显示更新间隔
const unsigned long PAGE_CHANGE_INTERVAL = 8000;    // 页面切换间隔
const unsigned long WELCOME_DURATION = 3000;      // 欢迎界面显示时长
const unsigned long UPTIME_UPDATE_INTERVAL = 1000;// 运行时间更新间隔2. WiFi连接管理模块 (WiFiConnection.h)
/**
* WiFi连接管理模块
* 负责WiFi连接、状态监测和重连管理
*/

class WiFiConnectionManager {
private:
    // 网络状态变量
    int wifiRSSI = 0;                  // WiFi信号强度
    String ipAddress = "No IP";          // IP地址
    bool wifiConnected = false;          // 连接状态标志
   
    // 时间管理
    unsigned long lastWiFiUpdate = 0;    // 上次WiFi状态更新时间
   
public:
    /**
   * 连接到WiFi网络
   * 显示连接过程动画,支持超时处理
   */
    void connectToWiFi() {
      displayConnectingScreen(0);
      WiFi.begin(WIFI_SSID, WIFI_PWD);
      
      unsigned long startTime = millis();
      int dotCount = 0;
      
      // 20秒连接超时
      while (WiFi.status() != WL_CONNECTED && millis() - startTime < 20000) {
            delay(300);
            dotCount = (dotCount + 1) % 4;
            displayConnectingScreen(dotCount);
      }
      
      if (WiFi.status() == WL_CONNECTED) {
            onWiFiConnected();
      } else {
            onWiFiFailed();
      }
    }
   
    /**
   * WiFi连接成功处理
   * 更新状态变量并显示成功界面
   */
    void onWiFiConnected() {
      wifiConnected = true;
      ipAddress = WiFi.localIP().toString();
      wifiRSSI = WiFi.RSSI();
      
      displaySuccessScreen();
      Serial.println("WiFi Connected - IP: " + ipAddress);
    }
   
    /**
   * WiFi连接失败处理
   * 显示错误界面并设置连接状态为false
   */
    void onWiFiFailed() {
      wifiConnected = false;
      displayErrorScreen();
      Serial.println("WiFi Connection Failed");
    }
   
    /**
   * 更新WiFi连接状态
   * 定期检查连接状态,处理断开重连情况
   */
    void updateWiFiStatus() {
      bool previousStatus = wifiConnected;
      wifiConnected = (WiFi.status() == WL_CONNECTED);
      
      if (wifiConnected) {
            // 更新信号强度(变化超过2dBm才更新)
            int newRSSI = WiFi.RSSI();
            if (abs(newRSSI - wifiRSSI) > 2) {
                wifiRSSI = newRSSI;
                displayNeedsUpdate = true;
            }
            ipAddress = WiFi.localIP().toString();
            
            // WiFi重连处理
            if (!previousStatus) {
                Serial.println("WiFi Reconnected");
                displayNeedsUpdate = true;
            }
      } else if (previousStatus) {
            // WiFi断开处理
            Serial.println("WiFi Disconnected");
            displayNeedsUpdate = true;
      }
    }
   
    // Getter方法
    bool isConnected() { return wifiConnected; }
    int getRSSI() { return wifiRSSI; }
    String getIP() { return ipAddress; }
};WiFi状态转换说明


连接生命周期

[*]完整状态机:覆盖从初始到连接的完整流程
[*]异常处理:处理各种连接失败场景
[*]自动恢复:连接断开后自动尝试重连
状态持久性

[*]状态记忆:系统记住当前连接状态
[*]条件执行:基于连接状态决定功能可用性
[*]用户反馈:每个状态变化都有相应的用户提示
这个详细的流程图说明文档完整地解释了WiFi网络状态监测器的程序架构、设计理念和实现细节,为后续的维护、扩展和故障排查提供了完整的技术参考。
WiFi连接管理流程说明
流程图概述


连接过程设计说明用户反馈优化

[*]动态指示:通过动态点动画显示连接进行中状态
[*]进度感知:每300ms更新一次界面,让用户感知系统运行
[*]明确结果:成功或失败都有明确的视觉反馈
超时管理策略

[*]合理超时:20秒超时时间平衡了连接成功率和用户体验
[*]** graceful失败**:连接失败后系统继续运行,支持后续手动恢复
信息记录

[*]关键数据保存:连接成功后立即保存IP地址和信号强度
[*]状态同步:确保显示数据与实际连接状态一致
3. 显示控制模块 (DisplayManager.h)
/**
* 显示控制模块
* 管理OLED显示屏的所有绘制操作和页面管理
*/

class DisplayManager {
private:
    U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2;
   
    // 显示状态
    int displayPage = 0;               // 当前显示页面
    bool displayNeedsUpdate = true;      // 显示更新标志
    bool showWelcome = true;             // 欢迎界面显示标志
   
    // 动画状态
    bool isAnimating = false;
    int previousPage = 0;
    unsigned long animationStartTime = 0;
   
public:
    DisplayManager() : u8g2(U8G2_R0, 10, 9, U8X8_PIN_NONE) {}
   
    /**
   * 初始化OLED显示屏
   * 设置字体、颜色等基础参数
   */
    void begin() {
      u8g2.begin();
      u8g2.setFont(u8g2_font_6x10_tf);
      u8g2.setFontRefHeightExtendedText();
      u8g2.setDrawColor(1);
      u8g2.setFontPosTop();
      u8g2.setFontDirection(0);
      Serial.println("OLED Display Initialized");
    }
   
    /**
   * 显示欢迎界面
   * 设备启动时显示设备名称和版本信息
   */
    void showWelcomeScreen() {
      u8g2.firstPage();
      do {
            u8g2.setFont(u8g2_font_7x14_tf);
            u8g2.drawStr(15, 10, DEVICE_NAME);
            
            u8g2.setFont(u8g2_font_6x10_tf);
            u8g2.drawStr(25, 30, "Initializing...");
            u8g2.drawStr(20, 45, "WiFi Monitor v2.0");
      } while (u8g2.nextPage());
    }
   
    /**
   * 显示WiFi连接过程界面
   * 带动态点动画显示连接状态
   */
    void displayConnectingScreen(int dotCount) {
      u8g2.firstPage();
      do {
            u8g2.drawStr(20, 15, "Connecting WiFi");
            
            // 动态点动画
            char dots = "...";
            dots = '\0';
            u8g2.drawStr(55, 35, dots);
            u8g2.drawStr(25, 50, "Please wait");
      } while (u8g2.nextPage());
    }
   
    /**
   * 显示连接成功界面
   * 显示IP地址和信号强度
   */
    void displaySuccessScreen() {
      u8g2.firstPage();
      do {
            u8g2.drawStr(40, 15, "Connected!");
            
            String shortIP = getShortIP(ipAddress);
            u8g2.drawStr(10, 35, shortIP.c_str());
            
            char signalStr;
            snprintf(signalStr, sizeof(signalStr), "%d dBm", wifiRSSI);
            u8g2.drawStr(45, 50, signalStr);
      } while (u8g2.nextPage());
    }
   
    /**
   * 显示状态页面
   * 包含WiFi状态、信号强度、Ping延迟、IP地址和时间
   */
    void displayStatusPage() {
      u8g2.firstPage();
      do {
            char wifiStatus;
            snprintf(wifiStatus, sizeof(wifiStatus), "WiFi:%s",
                     wifiConnected ? "ON" : "OFF");
            
            char signalStr;
            snprintf(signalStr, sizeof(signalStr), "Sig:%ddBm", wifiRSSI);
            
            char pingStr;
            snprintf(pingStr, sizeof(pingStr), "Ping:%s",
                     pingTime > 0 ? String(pingTime) + "ms" : "--ms");
            
            String shortIP = getShortIP(ipAddress);
            String currentTime = getCurrentTime();
            
            // 紧凑的5行布局
            u8g2.setCursor(0, 2);
            u8g2.print(wifiStatus);
            u8g2.setCursor(64, 2);
            u8g2.print(signalStr);
            
            u8g2.setCursor(0, 14);
            u8g2.print(pingStr);
            
            u8g2.setCursor(0, 26);
            u8g2.print(shortIP.c_str());
            
            u8g2.setCursor(0, 38);
            u8g2.print("Time:");
            u8g2.setCursor(30, 38);
            u8g2.print(currentTime.c_str());
            
            u8g2.setCursor(0, 50);
            u8g2.print("Page 1/3");
      } while (u8g2.nextPage());
    }
   
    /**
   * 处理页面切换动画
   * 实现平滑的页面切换效果
   */
    void handleAnimation() {
      unsigned long elapsed = millis() - animationStartTime;
      float progress = (float)elapsed / 400;
      
      if (progress > 1.0) {
            isAnimating = false;
            return;
      }
      
      int offset = (progress < 0.5) ?
                   (int)(64 * (0.5 - progress) * 2) :
                   (int)(64 * (progress - 0.5) * 2);
      
      u8g2.firstPage();
      do {
            if (progress < 0.5) {
                displayPageContent(previousPage, 0, offset);
            } else {
                displayPageContent(displayPage, 0, offset - 64);
            }
      } while (u8g2.nextPage());
    }
   
    // 其他显示相关方法...
};显示页面管理流程说明
流程图概述

显示系统架构说明优先级管理

[*]欢迎界面优先:系统启动时优先显示欢迎界面
[*]动画优先:页面切换动画期间暂停常规内容更新
[*]状态驱动:根据系统状态选择显示内容
页面切换动画

[*]平滑过渡:400ms动画时长提供舒适的视觉体验
[*]双向滑动:前半段移出旧页面,后半段移入新页面
[*]精确控制:基于时间进度的精确动画控制
三页面内容设计

[*]状态页面:核心网络参数实时监控
[*]质量页面:网络质量分析和评级
[*]个人页面:个性化信息和设备状态
布局优化

[*]5行紧凑布局:充分利用128x64像素显示区域
[*]信息分层:重要信息突出显示,次要信息适当位置
[*]一致性设计:各页面保持统一的布局风格
4. 网络测试模块 (NetworkTest.h)
/**
* 网络测试模块
* 负责网络连通性测试和延迟测量
*/

class NetworkTestManager {
private:
    int pingTime = 0;                  // Ping延迟时间
    unsigned long lastPingTime = 0;      // 上次Ping测试时间
   
public:
    /**
   * 异步执行Ping测试
   * 测试多个服务器的连通性,取最快响应时间
   */
    void performPingTestAsync() {
      HTTPClient http;
      
      // 测试服务器列表
      const char* servers[] = {
            "http://www.bing.com",
            "http://www.qq.com",
            "http://www.baidu.com"
      };
      
      bool success = false;
      
      // 尝试多个服务器,直到成功或全部失败
      for (int i = 0; i < 3 && !success; i++) {
            http.begin(servers);
            http.setTimeout(2000);// 2秒超时
            
            unsigned long startTime = millis();
            int httpCode = http.GET();
            unsigned long responseTime = millis() - startTime;
            
            if (httpCode > 0) {
                updatePingTime(responseTime);
                success = true;
            }
            
            http.end();
            if (!success && i < 2) delay(100); // 服务器间短暂延迟
      }
      
      if (!success) {
            pingTime = -1;// 测试失败
            displayNeedsUpdate = true;
      }
    }
   
    /**
   * 更新Ping时间
   * 只有变化超过10ms才触发显示更新
   */
    void updatePingTime(unsigned long responseTime) {
      int newPingTime = responseTime;
      if (abs(newPingTime - pingTime) > 10) {
            pingTime = newPingTime;
            displayNeedsUpdate = true;
      }
    }
   
    /**
   * 获取网络质量评级
   * 基于信号强度和延迟的综合评价
   */
    String getOverallRating() {
      if (!wifiConnected) return "Offline";
      
      int score = 0;
      
      // 信号强度评分
      if (wifiRSSI >= -55) score += 2;
      else if (wifiRSSI >= -65) score += 1;
      
      // 延迟评分
      if (pingTime > 0 && pingTime < 100) score += 2;
      else if (pingTime > 0 && pingTime < 200) score += 1;
      
      // 综合评级
      if (score >= 4) return "Excel";
      else if (score >= 3) return "Good";
      else if (score >= 2) return "Fair";
      else return "Poor";
    }
   
    // Getter方法
    int getPingTime() { return pingTime; }
};网络测试流程说明
流程图概述

网络测试策略说明多服务器容错机制

[*]服务器多样性:选择不同服务商的服务器提高测试可靠性
[*]顺序测试:依次测试直到成功,避免不必要的并行请求
[*]智能切换:当前服务器失败后自动切换到下一个
性能优化设计

[*]合理超时:2秒超时平衡了响应速度和成功率
[*]变化检测:只有显著变化(>10ms)才触发显示更新
[*]服务器间延时:100ms间隔避免请求过于密集
用户体验考虑

[*]快速失败:单个服务器快速超时,整体测试时间可控
[*]明确状态:成功和失败都有明确的状态标识
[*]渐进式反馈:通过显示更新向用户反馈测试结果
5. 时间管理模块 (TimeManager.h)
/**
* 时间管理模块
* 管理NTP时间同步、设备运行时间和时间相关功能
*/

class TimeManager {
private:
    unsigned long deviceUptime = 0;          // 设备运行时间(秒)
    unsigned long lastUptimeUpdate = 0;      // 上次运行时间更新时间
    String customMessage = "Have a nice day!"; // 个性化消息
   
public:
    /**
   * 配置NTP时间服务
   * 设置时区和夏令时配置
   */
    void configureNTP() {
      configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
      Serial.println("NTP Time Service Configured");
    }
   
    /**
   * 获取当前时间字符串
   * 格式: HH:MM:SS
   */
    String getCurrentTime() {
      struct tm timeinfo;
      if (!getLocalTime(&timeinfo)) {
            return "--:--:--";
      }
      
      char timeString;
      strftime(timeString, sizeof(timeString), "%H:%M:%S", &timeinfo);
      return String(timeString);
    }
   
    /**
   * 获取当前日期字符串
   * 格式: MM/DD
   */
    String getCurrentDate() {
      struct tm timeinfo;
      if (!getLocalTime(&timeinfo)) {
            return "---/--/--";
      }
      
      char dateString;
      strftime(dateString, sizeof(dateString), "%m/%d", &timeinfo);
      return String(dateString);
    }
   
    /**
   * 获取设备运行时间字符串
   * 格式: Xh Ym 或 Ym(小于1小时)
   */
    String getUptimeString() {
      unsigned long hours = deviceUptime / 3600;
      unsigned long minutes = (deviceUptime % 3600) / 60;
      
      if (hours > 0) {
            return String(hours) + "h " + String(minutes) + "m";
      } else {
            return String(minutes) + "m";
      }
    }
   
    /**
   * 更新设备运行时间
   * 每秒更新一次,每小时更新个性化消息
   */
    void updateUptime() {
      deviceUptime = millis() / 1000;
      
      // 每小时更新个性化消息
      if (deviceUptime % 3600 == 0) {
            setTimeBasedMessage();
      }
    }
   
    /**
   * 根据当前时间设置个性化问候消息
   * 根据不同时间段显示不同的问候语
   */
    void setTimeBasedMessage() {
      struct tm timeinfo;
      if (!getLocalTime(&timeinfo)) {
            customMessage = "Welcome!";
            return;
      }
      
      int hour = timeinfo.tm_hour;
      
      if (hour >= 5 && hour < 12) {
            customMessage = "Good morning!";
      } else if (hour >= 12 && hour < 18) {
            customMessage = "Good afternoon!";
      } else if (hour >= 18 && hour < 22) {
            customMessage = "Good evening!";
      } else {
            customMessage = "Time to rest...";
      }
    }
   
    // Getter方法
    String getCustomMessage() { return customMessage; }
};时间管理流程说明
流程图概述

时间系统设计说明NTP时间同步

[*]自动配置:WiFi连接成功后自动配置时间服务
[*]时区支持:支持UTC+8北京时间配置
[*]容错处理:时间获取失败时提供默认值显示
运行时间统计

[*]精确计时:基于millis()的精确运行时间计算
[*]友好显示:自动在小时和分钟格式间切换
[*]低开销:每秒更新一次,性能开销极小
智能问候系统

[*]时间段划分:按早晨、下午、晚上、深夜四个时段
[*]个性化消息:每个时段提供相应的问候语
[*]自动更新:每小时检查更新,确保问候语及时性
错误处理机制

[*]优雅降级:NTP服务不可用时显示默认时间
[*]状态保持:运行时间统计不受网络状态影响
[*]用户透明:时间显示异常时用户仍可获取基本功能
6. 主程序模块 (WiFi_Monitor.ino)
/**
* 主程序模块
* 协调各个功能模块,实现非阻塞式多任务处理
*/

// 全局对象实例
WiFiConnectionManager wifiManager;
DisplayManager displayManager;
NetworkTestManager networkTest;
TimeManager timeManager;

// 全局状态变量
bool displayNeedsUpdate = true;
bool showWelcome = true;
unsigned long welcomeStartTime = 0;

void setup() {
    Serial.begin(115200);
    Serial.println("Personal WiFi Monitor Starting...");
   
    // 初始化显示屏
    displayManager.begin();
    displayManager.showWelcomeScreen();
    welcomeStartTime = millis();
   
    // 连接WiFi
    wifiManager.connectToWiFi();
   
    // 配置NTP时间服务
    if (wifiManager.isConnected()) {
      timeManager.configureNTP();
    }
   
    // 初始化时间相关变量
    initializeTimingVariables();
    timeManager.setTimeBasedMessage();
}

void loop() {
    unsigned long currentTime = millis();
   
    // 处理欢迎界面显示
    handleWelcomeScreen(currentTime);
   
    // 更新设备运行时间
    if (currentTime - lastUptimeUpdate > UPTIME_UPDATE_INTERVAL) {
      timeManager.updateUptime();
      lastUptimeUpdate = currentTime;
    }
   
    // 更新WiFi状态
    if (currentTime - lastWiFiUpdate > WIFI_UPDATE_INTERVAL) {
      wifiManager.updateWiFiStatus();
      lastWiFiUpdate = currentTime;
      displayNeedsUpdate = true;
    }
   
    // 执行网络测试
    if (currentTime - lastPingTime > PING_INTERVAL && wifiManager.isConnected()) {
      networkTest.performPingTestAsync();
      lastPingTime = currentTime;
    }
   
    // 页面自动切换
    if (currentTime - lastPageChange > PAGE_CHANGE_INTERVAL && !showWelcome) {
      switchPage();
      lastPageChange = currentTime;
    }
   
    // 显示更新
    if ((currentTime - lastDisplayUpdate > DISPLAY_UPDATE_INTERVAL || displayNeedsUpdate) && !showWelcome) {
      updateDisplay();
      lastDisplayUpdate = currentTime;
      displayNeedsUpdate = false;
    }
   
    // 处理动画效果
    if (isAnimating) {
      displayManager.handleAnimation();
    }
   
    delay(50); // 主循环延迟,降低CPU占用
}

/**
* 处理欢迎界面显示逻辑
*/
void handleWelcomeScreen(unsigned long currentTime) {
    if (showWelcome && currentTime - welcomeStartTime > WELCOME_DURATION) {
      showWelcome = false;
      displayNeedsUpdate = true;
    }
}

/**
* 切换显示页面
* 触发页面切换动画
*/
void switchPage() {
    previousPage = displayPage;
    displayPage = (displayPage + 1) % 3;// 循环切换0,1,2三个页面
   
    isAnimating = true;
    animationStartTime = millis();
    displayNeedsUpdate = true;
}

/**
* 更新显示内容
* 根据当前状态选择显示内容
*/
void updateDisplay() {
    if (showWelcome) {
      displayManager.showWelcomeScreen();
      return;
    }
   
    if (isAnimating) {
      displayManager.handleAnimation();
    } else {
      switch (displayPage) {
            case 0:
                displayManager.displayStatusPage();
                break;
            case 1:
                displayManager.displayQualityPage();
                break;
            case 2:
                displayManager.displayPersonalPage();
                break;
      }
    }
}硬件要求

[*]FireBeetle 2 ESP32-C5开发套件
[*]0.96寸OLED显示屏(SSD1306,128x64)
[*]WiFi网络接入
使用说明

[*]修改Configuration.h中的WiFi配置
[*]根据需要调整设备个性化设置
[*]上传程序到FireBeetle 2 ESP32-C5开发套件
[*]设备将自动连接WiFi并开始监测
实物照片







页: [1]
查看完整版本: [FireBeetle 2 ESP32-C5]ESP32-C5 WiFi网络状态监测器