Galeros OpenIris ESP32 固件使用教程

Galeros OpenIris ESP32 固件开发和使用教程

本文详细介绍了基于 ESP32 的 OpenIris 摄像头固件二次开发项目,说明了网页配网系统和实时 Web 日志监控的实现方法。

更新日志

  • 2026-07-12: 日志系统重构:废弃旧的”三通道”日志体系(ESP_LOG / Serial / SendLogToWeb),引入统一的 GLogManager + GLOG 宏,一次调用同时输出到串口和 Web;新增日志级别过滤功能;修复了 Serial.available() 相关误解。

零、开发环境搭建(VSCode + PlatformIO)

本节详细介绍如何在 VSCode 中配置 PlatformIO 开发环境,并完成固件编译与烧录。

0.1 安装 Visual Studio Code

  1. 访问 VS Code 官网 下载并安装 VS Code
  2. 启动 VS Code,点击左侧扩展图标(或按 Ctrl+Shift+X

VS Code 扩展图标位置

图 0-1:VS Code 左侧扩展图标位置

0.2 安装 PlatformIO 插件

  1. 在扩展搜索框中输入 PlatformIO
  2. 找到 PlatformIO IDE 插件,点击安装

PlatformIO 插件搜索

图 0-2:搜索并安装 PlatformIO 插件

  1. 安装完成后,点击 Reload Now 重启 VS Code

PlatformIO 安装完成

图 0-3:PlatformIO 安装完成,点击 Reload Now

0.3 打开项目并编译

  1. 打开 VS Code,点击 FileOpen Folder
  2. 选择项目根目录 Openiris_esp32_aithinker

打开项目文件夹

图 0-4:打开项目文件夹

  1. 等待 PlatformIO 自动下载依赖(首次可能需要 1-3 分钟)

依赖下载中

图 0-5:PlatformIO 正在下载依赖

  1. 依赖下载完成后,在底部找到 PlatformIO 图标,点击展开菜单

PlatformIO 菜单

图 0-6:点击底部 PlatformIO 菜单

  1. 点击 Build(或按 Ctrl+Alt+B)开始编译

点击 Build 编译

图 0-7:点击 Build 开始编译

  1. 编译成功后会看到类似输出:
1
2
3
4
5
6
7
Advanced Memory usage is available via "Build"
================================================
INFO: Successfully burned binary to flash
Environment Status Duration
-------------------- --------- --------
esp32AIThinker SUCCESS 00:01:32
================================================

编译成功

图 0-8:编译成功输出

0.4 烧录固件到开发板

  1. 用 USB 线连接 ESP32 开发板到电脑
  2. 在 PlatformIO 菜单中点击 Upload(或按 Ctrl+Alt+U

点击 Upload 烧录

图 0-9:点击 Upload 烧录固件

  1. 烧录过程中开发板上的指示灯会闪烁

  2. 烧录成功后设备会自动重启

烧录成功

图 0-10:烧录成功提示


一、项目背景与目标

在 ESP32 开发中,WiFi 配置一直是开发者头痛的问题。传统方式需要:

  1. 硬编码 WiFi 凭证 → 每次换环境要重新烧录
  2. 串口终端手动输入 → 依赖电脑工具
  3. BLE 配网 → 需要额外 App

Galeros OpenIris 正是为解决这些痛点而生的二次开发固件。项目目标非常明确:

让 ESP32 设备开箱即用,通过浏览器即可完成 WiFi 配置,并实时监控设备运行日志。


二、核心功能架构

2.1 智能网页配网系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
┌─────────────────────────────────────────────────────────┐
│ 首次上电流程 │
├─────────────────────────────────────────────────────────┤
│ │
│ 设备上电 ──→ 检查 NVS 中是否有保存的 WiFi │
│ │ │
│ ┌─────────┴─────────┐ │
│ ▼ ▼ │
│ 已保存 WiFi 无保存 WiFi │
│ │ │ │
│ ▼ ▼ │
│ 尝试连接 ──→ 失败 ──→ 开启 AP 热点 │
│ │ │
│ ▼ │
│ SSID: Galeros_ESP32 │
│ 密码: Galeros_ESP32 │
│ │ │
│ ▼ │
│ 浏览器自动弹出配网页面 │
│ (Captive Portal) │
│ │ │
│ ▼ │
│ 用户输入 WiFi 信息并提交 │
│ │ │
│ ▼ │
│ 保存到 NVS 分区,重启设备 │
│ │
└─────────────────────────────────────────────────────────┘

首次配网界面

图 2-1:首次配网时连接 AP 热点后浏览器自动弹出的配网页面

配网成功后,设备会重启并连接 WiFi。此后可通过以下地址访问配置管理页面:

配置网络界面

图 2-2:STA 模式下访问 http://设备IP:8080 看到的配置管理页面,可查看当前连接的 WiFi 并重新配置

关键实现代码 (main.cpp):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// AP 模式配置
void etvr_eye_tracker_web_init() {
// 先尝试连接已保存的 WiFi
WiFi.disconnect(true);
WiFi.mode(WIFI_STA);
wifiHandler.begin();
delay(1000);

if (WiFi.isConnected()) {
// 已连接:启动 mDNS、视频流、API、配置页面
mdnsHandler.startMDNS();
streamServer.startStreamServer();
apiServer.setup();
configServer = new AsyncWebServer(CONFIG_PORT);
setupConfigServer(false);
configServer->begin();
} else {
// 未连接:进入 AP 模式
WiFi.mode(WIFI_AP);
WiFi.softAP(AP_SSID, AP_PASSWORD);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
dnsServer.start(DNS_PORT, "*", apIP);

configServer = new AsyncWebServer(80);
setupConfigServer(true); // 启用 Captive Portal
configServer->begin();
isInAPMode = true;
}
}

2.2 实时 Web 日志监控(重构版)

日志系统进行了彻底重构。旧版存在三条互不相通的日志通道——Serial.printf(只到串口)、log_i/log_d(ESP_LOG 通道,Web 回调有 bug)、SendLogToWeb()(只到 Web)——导致开发者需要手动调用两个不同的函数才能实现”串口 + Web”双输出。

新版引入了统一日志管理器 GLogManager,架构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌────────────────────────────────────────────────────────────┐
│ GLog 统一日志架构 │
├────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 代码中任何位置 │ │
│ │ GLOG_D("TAG", "msg %d", val) │ │
│ │ GLOG_I("TAG", "msg") │ │
│ │ GLOG_W("TAG", "msg") │ │
│ │ GLOG_E("TAG", "msg") │ │
│ └──────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌──────────────┴──────────────┐ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 串口输出 │ │ Web SSE 推送 │ │
│ │ 带 ANSI 颜色 │ │ (端口 1234) │ │
│ │ [信息][WIFI] │ │ │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ 两条输出均由 GLogManager::send() 统一管理 │
│ 自动级别过滤:低于 LOG_LEVEL 的日志静默丢弃 │
│ │
└────────────────────────────────────────────────────────────┘

核心实现 (log_manager.cpp):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void GLogManager::send(GLogLevel level, const char* tag, const String& msg) {
// 级别过滤——低于 _minLevel 的日志直接丢弃
if (level < _minLevel) return;

// → 串口(带 ANSI 颜色)
Serial.printf("%s[%s][%s] %s%s\n",
ansiColor(level), levelPrefix(level), tag,
msg.c_str(), ansiReset());

// → Web SSE(如果就绪)
if (webReady && _webCallback) {
String webMsg = "[" + String(levelPrefix(level)) + "][" + String(tag) + "] " + msg;
_webCallback(webMsg);
}
}

便捷宏 (log_manager.hpp):

1
2
3
4
#define GLOG_D(tag, fmt, ...)  GLogManager::instance().log(GLogLevel::DEBUG, tag, fmt, ##__VA_ARGS__)
#define GLOG_I(tag, fmt, ...) GLogManager::instance().log(GLogLevel::INFO, tag, fmt, ##__VA_ARGS__)
#define GLOG_W(tag, fmt, ...) GLogManager::instance().log(GLogLevel::WARN, tag, fmt, ##__VA_ARGS__)
#define GLOG_E(tag, fmt, ...) GLogManager::instance().log(GLogLevel::ERROR, tag, fmt, ##__VA_ARGS__)

使用示例

1
2
3

// 新版(一行搞定,自动双输出):
GLOG_I("SETUP", "WiFi connected");

三、技术实现详解

3.1 配网页面实现

使用 AsyncWebServer 构建轻量级 Web 服务器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// AP 模式配网页面
configServer->on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/html, charset=utf-8", ap_config_html);
});

// 保存 WiFi 配置
configServer->on("/save", HTTP_POST, [](AsyncWebServerRequest *request) {
String ssid = request->getParam("ssid", true)->value();
String pass = request->getParam("password", true)->value();

// 保存到 NVS 分区
deviceConfig.setWifiConfig("main", ssid.c_str(), pass.c_str(), 0, 52,
false, true);

request->send(200, "text/plain, charset=utf-8", "配置已保存!设备即将重启...");
delay(2500);
ESP.restart();
});

3.2 Captive Portal 自动弹出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CaptiveRequestHandler : public AsyncWebHandler {
public:
bool canHandle(AsyncWebServerRequest *request) { return true; }

void handleRequest(AsyncWebServerRequest *request) {
// 重定向到配网页面
request->redirect("http://" + apIP.toString());
}
};

// AP 模式下启用
if (isAP) {
configServer->addHandler(new CaptiveRequestHandler())
.setFilter(ON_AP_FILTER);
}

3.3 日志级别过滤系统

GLogManager 内置四级日志过滤,用户通过 main.cpp 顶部的 LOG_LEVEL 变量控制全局输出:

LOG_LEVEL 值 输出内容
GLogLevel::DEBUG 全部日志(调试 + 信息 + 警告 + 错误)
GLogLevel::INFO 信息 + 警告 + 错误(调试日志被跳过)
GLogLevel::WARN 警告 + 错误
GLogLevel::ERROR 仅错误
1
2
3
4
5
// main.cpp 用户配置区
const GLogLevel LOG_LEVEL = GLogLevel::DEBUG; // ← 开发时用 DEBUG,部署时改为 INFO

// setup() 中生效
GLogManager::instance().setLevel(LOG_LEVEL);

实战场景

  • 开发调试阶段 → DEBUG(输出所有细节,包括每10秒的内存报告)
  • 正式部署 → INFO(只保留关键信息,loop 中的调试输出自动静默)

3.4 Web SSE 桥接

1
2
3
4
5
6
7
8
9
10
11
12
// main.cpp — 将 GLogManager 的输出挂接到 AsyncEventSource
void setupGLogWebCallback() {
auto logCallback = [](const String &msg) {
if (events != nullptr && msg.length() > 0) {
events->send(msg.c_str(), nullptr, millis());
}
};
GLogManager::instance().setWebCallback(logCallback);
}

// Web 服务器就绪时标记
GLogManager::instance().webReady = true;

已修复:旧版 esp_log_set_vprintf 回调不工作的问题已通过架构重构彻底解决。新方案不依赖 ESP_LOG 拦截,而是由 GLOG 宏直接分发到串口和 Web 两端,不再有递归风险或通道遗漏。


四、使用教程

4.1 首次配网步骤

步骤 操作
1 设备上电,若无保存 WiFi 会自动开启热点
2 手机/电脑连接 Galeros_ESP32(密码相同)
3 浏览器自动弹出配网页面,或访问 192.168.4.1
4 输入家用 WiFi 名称和密码
5 点击「保存并重启」
6 设备自动重启并连接 WiFi

4.2 访问服务

1
2
3
4
5
6
7
8
9
┌────────────────────────┬──────────────────────────────┐
│ 功能 │ 访问地址 │
├────────────────────────┼──────────────────────────────┤
│ Web 日志监控 │ http://设备IP:1234 │
│ 配置管理页面 │ http://设备IP:8080 │
│ 视频流地址 │ http://设备IP/ │
│ REST API │ http://设备IP:81/control/... │
│ mDNS 访问 │ http://Galeros-ESP32.local │
└────────────────────────┴──────────────────────────────┘

Web 日志监控界面

图 4-1:访问 http://设备IP:1234 看到的实时 Web 日志监控页面,可实时查看设备运行日志


五、项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Galeros-ESP/
├── src/
│ ├── main.cpp # ★ 主程序入口(启动流程、Web服务、用户配置)
│ └── html_content.h # HTML 页面(配网页、管理页、日志页)
├── lib/src/
│ ├── openiris.hpp # 主头文件
│ ├── data/
│ │ ├── utilities/
│ │ │ ├── log_manager.hpp/.cpp # ★ 统一日志管理器 (新增)
│ │ │ ├── Observer.hpp # 观察者模式
│ │ │ ├── helpers.hpp/.cpp # 通用工具
│ │ │ └── network_utilities.hpp/.cpp
│ │ ├── CommandManager/ # 命令管理(JSON 解析)
│ │ ├── config/ # 配置管理(NVS 持久化)
│ │ └── StateManager/ # 全局状态机
│ ├── io/
│ │ ├── Serial/ # 串口管理
│ │ ├── LEDManager/ # LED 状态指示
│ │ └── camera/ # 摄像头
│ └── network/
│ ├── wifihandler/ # WiFi 处理
│ ├── api/ # REST API (端口 81)
│ ├── stream/ # MJPEG 视频流 (端口 80)
│ └── mDNS/ # mDNS 服务
├── ini/ # 配置文件
│ ├── boards.ini # 开发板定义
│ ├── pinouts.ini # 摄像头引脚映射
│ └── user_config.ini # 用户配置
├── platformio.ini # PlatformIO 主配置
└── CLAUDE.md # 项目文档(AI 友好)

六、用户可配置参数

main.cpp 顶部的「用户自定义配置修改区域」可修改以下参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 全局最低日志级别——低于此级别的 GLOG 调用不会输出
// DEBUG = 输出所有日志(调试/信息/警告/错误),适合开发调试
// INFO = 只输出信息/警告/错误,适合正式部署
// WARN = 只输出警告/错误
// ERROR = 只输出错误
const GLogLevel LOG_LEVEL = GLogLevel::DEBUG; // ← 这里修改

// WiFi 配置
const char *AP_SSID = "Galeros_ESP32"; // AP 热点名称
const char *AP_PASSWORD = "Galeros_ESP32"; // AP 热点密码

// 端口配置
const uint16_t CONFIG_PORT = 8080; // 配置管理页面端口
const uint16_t LOG_PORT = 1234; // Web 日志页面端口

// mDNS 主机名
const char *MDNS_HOSTNAME = "Galeros-ESP32";

// WiFi 信道
const uint8_t WIFI_CHANNEL = 1;

// Adhoc 模式开关(不建议修改)
const bool ENABLE_ADHOC = false;

七、已解决问题 & 待办事项

✅ 已解决

问题 解决方案
日志回调系统 bug(esp_log_set_vprintf 不工作) 废弃 ESP_LOG 拦截,统一为 GLogManager + GLOG 宏
旧版三通道日志分裂(Serial.printf / log_i / SendLogToWeb 互不相通) 全部统一为 GLOG 宏,一次调用 → 串口 + Web 双输出
日志级别过滤 LOG_LEVEL 变量全局控制,四级可调
中文化日志前缀 级别前缀改为中文:[调试][信息][警告][错误]

⬜ 待实现

  • 日志级别颜色区分 正在实现本功能..
  • 修复对除 AI Thinker 以外 ESP32 开发板的兼容问题
  • 支持网页端扫描附近 WiFi 列表
  • 优化内存占用
  • 添加暗黑模式支持

八、总结

Galeros OpenIris 为 ESP32 开发者提供了一个开箱即用的配网 + 日志解决方案:

配网系统

  • 无需硬编码 WiFi,浏览器一键配网
  • Captive Portal 自动弹出配网页
  • 配置保存在 NVS,重启后依然有效
  • 美化后的配网和管理界面

日志系统(重构)

  • 统一的 GLogManager,一次 GLOG_I() 同时输出到串口和 Web
  • 四级日志过滤(DEBUG/INFO/WARN/ERROR),一行配置全局生效
  • 串口输出带 ANSI 颜色,中文级别前缀
  • Web SSE 实时推送,浏览器打开日志页即可监控
  • 不再需要手动调用 SendLogToWeb()——GLOG 自动覆盖

⚠️ 需要注意

  • 首次使用必须通过 AP 配网方式配置 WiFi
  • 调试时建议 LOG_LEVEL = DEBUG,部署后改为 INFO 以减少串口输出
  • 日志级别颜色区分功能正在实现中..

项目地址https://github.com/mayan613/Openiris_esp32_aithinker

欢迎 Star 和 Issue!


许可证:

本项目基于 MIT 许可证开源。