OpenWrt Monitor
这是一个基于 ESP32 + LCD 屏幕的 OpenWrt 状态监控小屏项目。ESP32 会通过 Wi-Fi 定时访问 OpenWrt 路由器上的 CGI 接口,获取 CPU 负载、内存占用、温度、运行时间、实时上下行速率、内网 IP、公网 IP 和路由器时间,并显示在 LCD 上。
当前代码默认适配:
- 开发板:Waveshare ESP32-C6-LCD-1.47
- 屏幕驱动:ST7789
- 分辨率:172 x 320
- 开发环境:Arduino IDE
- 显示库:GFX Library for Arduino
- UI 库:LVGL 8.x
功能
- 显示设备名称:
C2000 Max - 显示 OpenWrt 系统状态:
- CPU 使用率
- RAM 使用率
- CPU 温度
- OpenWrt uptime
- 显示网络状态:
- UP 上传速率
- DOWN 下载速率
- LAN IP
- Public IP
- 底部显示 OpenWrt 后台
date获取的当前时间 - OpenWrt 后端脚本无固定
sleep阻塞,响应更快 - 网络速度单位自动切换
Kb/s和Mb/s - 英文和数字使用 LVGL 内置 Montserrat 字体
项目文件
OpenWrt_Monitor.ino Arduino 主程序
config.h Wi-Fi 和 OpenWrt 接口配置
gfx.cpp / gfx.h 屏幕驱动配置
ui.cpp / ui.h LVGL 界面
openwrt.cpp / .h HTTP 请求与 JSON 解析
lcd.cpp / lcd.h 备用底层 LCD 驱动,目前主程序未使用
openwrt_status.sh OpenWrt 后台 CGI 脚本
新手先看:完整流程总览
如果你是第一次使用 Arduino 或 OpenWrt CGI,可以按下面顺序做,不要跳步:
- 准备硬件:ESP32-C6-LCD-1.47、USB-C 数据线、OpenWrt 路由器。
- 在电脑上安装 Arduino IDE。
- 在 Arduino IDE 里安装 ESP32 开发板支持。
- 在 Arduino IDE 里安装依赖库:
GFX Library for Arduino、lvgl、ArduinoJson。 - 修改 config.h 里的 Wi-Fi 名称、Wi-Fi 密码、OpenWrt 接口地址。
- 把 openwrt_status.sh 上传到 OpenWrt 的
/www/cgi-bin/status.sh。 - 给
/www/cgi-bin/status.sh添加执行权限。 - 检查 OpenWrt 的
uhttpd是否允许.shCGI。 - 用浏览器打开
http://192.168.7.1/cgi-bin/status.sh,确认能看到 JSON。 - 回到 Arduino IDE,选择开发板和串口,上传 ESP32 程序。
- 上传后按一下 ESP32 的
RESET,等待屏幕显示数据。
命令在哪里执行
文档里会出现电脑命令和 OpenWrt 命令。新手最容易混淆,先记住这个表:
命令前面写 scp 在电脑终端执行
命令前面写 ssh 在电脑终端执行,用来登录 OpenWrt
命令路径是 /www/... 登录 OpenWrt 后,在 OpenWrt 终端执行
uci / chmod / ls / mkdir 登录 OpenWrt 后执行
Arduino IDE 菜单操作 在电脑上的 Arduino IDE 里完成
如果你用的是 macOS,打开“终端”执行命令。如果你用的是 Windows,可以用 PowerShell、Windows Terminal,或者安装 PuTTY / WinSCP。
开始前准备
硬件准备
- Waveshare ESP32-C6-LCD-1.47
- 一根支持数据传输的 USB-C 线
- 一台已经刷好 OpenWrt 的路由器
- 一台电脑,安装 Arduino IDE
注意:有些 USB-C 线只能充电,不能传数据。如果 Arduino IDE 看不到串口,优先换一根线。
网络准备
- ESP32 要连接到能访问 OpenWrt 的 Wi-Fi。
- 电脑最好也连接到同一个 OpenWrt 网络,方便测试接口。
- 本文默认 OpenWrt LAN IP 是
192.168.7.1。如果你的路由器不是这个地址,所有命令里的192.168.7.1都要改成你的实际地址。
一、Arduino IDE 准备
1. 安装 ESP32 开发板支持
打开 Arduino IDE,进入:
文件 -> 首选项 -> 其他开发板管理器地址
加入 Espressif ESP32 地址:
https://espressif.github.io/arduino-esp32/package_esp32_index.json
然后进入:
工具 -> 开发板 -> 开发板管理器
搜索并安装:
esp32 by Espressif Systems
建议使用较新的 3.x 版本。如果某些旧库不兼容,也可以尝试 2.0.x 版本。
安装完成后,可以在 Arduino IDE 菜单里看到类似:
工具 -> 开发板 -> esp32
如果看不到 ESP32 相关开发板,说明 ESP32 开发板支持还没有安装成功。
2. 安装依赖库
进入 Arduino IDE:
工具 -> 管理库
安装以下库:
GFX Library for Arduino
lvgl
ArduinoJson
建议:
- LVGL 使用 8.x 版本
- ArduinoJson 使用 6.x 或兼容版本
如果 Arduino IDE 提示找不到某个头文件,例如:
lvgl.h: No such file or directory
ArduinoJson.h: No such file or directory
Arduino_GFX_Library.h: No such file or directory
说明对应库没有安装成功,需要回到“管理库”重新安装。
二、配置 ESP32 端
打开 config.h,修改 Wi-Fi 和 OpenWrt 接口地址:
#define WIFI_SSID "你的WiFi名称"
#define WIFI_PASS "你的WiFi密码"
#define OPENWRT_URL "http://192.168.7.1/cgi-bin/status.sh"
注意:
- ESP32 必须能访问 OpenWrt 的这个 IP。
- 如果你的路由器 LAN IP 不是
192.168.7.1,请改成实际地址。 - 默认后端脚本路径是
/www/cgi-bin/status.sh。如果你使用其他文件名,这里也要同步修改。
举例:
如果你的 Wi-Fi 名称是 Home-WiFi,密码是 12345678,OpenWrt 地址是 192.168.1.1,则应改成:
#define WIFI_SSID "Home-WiFi"
#define WIFI_PASS "12345678"
#define OPENWRT_URL "http://192.168.1.1/cgi-bin/status.sh"
常见错误:
- Wi-Fi 名称大小写写错。
- Wi-Fi 密码写错。
- ESP32 连接的是访客 Wi-Fi,无法访问 OpenWrt 管理地址。
- OpenWrt 地址写成了电脑地址或公网地址。
三、部署 OpenWrt 后台脚本
项目里的 openwrt_status.sh 是运行在 OpenWrt 上的 CGI 脚本。
1. SSH 登录 OpenWrt
先确认电脑可以登录路由器:
ssh root@192.168.7.1
如果你的 OpenWrt LAN IP 不是 192.168.7.1,请替换成实际 IP。
第一次登录时,系统可能会询问:
Are you sure you want to continue connecting?
输入:
yes
然后回车。
如果提示密码,请输入 OpenWrt 的 root 密码。输入密码时终端通常不会显示任何字符,这是正常现象。
登录成功后,通常会看到类似:
root@OpenWrt:~#
看到这个提示符,说明你现在已经在 OpenWrt 里面了。
2. 确认 CGI 目录存在
登录 OpenWrt 后执行:
mkdir -p /www/cgi-bin
3. 上传脚本到路由器
可以用 scp 上传:
scp openwrt_status.sh root@192.168.7.1:/www/cgi-bin/status.sh
如果你的路由器 IP 不是 192.168.7.1,请替换成实际 IP。
注意:scp 这条命令是在电脑终端执行,不是在 OpenWrt 里执行。
上传成功后,可以登录 OpenWrt 检查文件是否存在:
ls -l /www/cgi-bin/status.sh
如果提示:
No such file or directory
说明文件没有传到正确位置,请重新执行 scp 命令。
4. 添加执行权限
SSH 登录 OpenWrt 后执行:
chmod +x /www/cgi-bin/status.sh
确认权限:
ls -l /www/cgi-bin/status.sh
正常应能看到类似:
-rwxr-xr-x 1 root root ... /www/cgi-bin/status.sh
5. OpenWrt uhttpd 开启 CGI
OpenWrt 默认使用 uhttpd 提供 Web 服务。为了让 .sh 文件能作为 CGI 脚本运行,需要确认解释器配置。
执行:
uci show uhttpd.main.interpreter
如果已经看到类似:
uhttpd.main.interpreter='.sh=/bin/sh'
说明 .sh CGI 已经配置好。
如果没有输出,或者没有 .sh=/bin/sh,执行:
uci add_list uhttpd.main.interpreter='.sh=/bin/sh'
uci commit uhttpd
/etc/init.d/uhttpd restart
如果你不确定配置是否生效,可以再次查看:
uci show uhttpd.main.interpreter
6. 命令行测试脚本
在 OpenWrt 上直接执行:
/www/cgi-bin/status.sh
正常情况下,开头应输出:
Content-Type: application/json
下面跟着一段 JSON 数据。
如果提示权限不足,重新执行:
chmod +x /www/cgi-bin/status.sh
如果直接执行脚本时看到 JSON,但浏览器打不开,通常是 uhttpd CGI 配置问题,请重点检查上一节的 .sh=/bin/sh。
7. 浏览器测试接口
在浏览器打开:
http://192.168.7.1/cgi-bin/status.sh
正常情况下会看到类似:
{
"load": 0.08,
"cpu_load": 0.08,
"cpu_percent": 12,
"mem": 42,
"mem_percent": 42,
"temp": 48,
"cpu_temp": 48,
"uptime": 123456,
"time": "14:30:08",
"rx": 123456789,
"tx": 987654321,
"rx_speed": 2048,
"tx_speed": 1024,
"lan_ip": "192.168.7.1",
"wan_ip": "10.0.0.2",
"public_ip": "1.2.3.4"
}
说明:
rx_speed和tx_speed单位是 Byte/s。- ESP32 会转换成 bit/s 后显示为
Kb/s或Mb/s。 - 第一次请求时速度可能为 0,因为脚本需要先建立一次采样缓存。
public_ip默认通过api.ipify.org获取,并缓存 5 分钟,避免频繁访问外网。
如果浏览器显示下载文件,而不是直接显示 JSON,也没有关系,说明 CGI 有返回内容。可以用文本编辑器打开下载的文件确认是否是 JSON。
如果浏览器显示:
404 Not Found
通常表示路径错了,检查:
ls -l /www/cgi-bin/status.sh
如果浏览器显示:
403 Forbidden
通常表示权限不对,执行:
chmod +x /www/cgi-bin/status.sh
如果浏览器显示脚本文本本身,而不是 JSON,通常表示 .sh 没有被当作 CGI 执行,重新检查:
uci show uhttpd.main.interpreter
四、测试接口
完成 OpenWrt 脚本部署和 uhttpd CGI 配置后,建议先测试接口,再上传 ESP32 程序。
1. 浏览器测试
访问:
http://192.168.7.1/cgi-bin/status.sh
能看到 JSON 就说明 OpenWrt 后端正常。
2. ESP32 配置对应 URL
确认 config.h 中的地址一致:
#define OPENWRT_URL "http://192.168.7.1/cgi-bin/status.sh"
如果浏览器里能打开,但 ESP32 显示数据为空,通常是:
- ESP32 连接的 Wi-Fi 和 OpenWrt 不在同一网络
OPENWRT_URL的 IP 或文件名写错- OpenWrt 防火墙或网络隔离阻止访问
五、上传 ESP32 程序
Waveshare ESP32-C6-LCD-1.47 推荐设置
Arduino IDE 中选择:
工具 -> 开发板 -> ESP32 Arduino -> ESP32C6 Dev Module
常见设置:
USB CDC On Boot: Enabled
Upload Speed: 460800 或 921600
Flash Size: 4MB
Partition Scheme: Default
不同 Arduino ESP32 Core 版本的菜单项可能略有不同,能正常编译上传即可。
上传步骤
- 用 USB-C 线连接 ESP32 和电脑。
- 打开 Arduino IDE。
- 打开本项目的
OpenWrt_Monitor.ino。 - 选择开发板:
工具 -> 开发板 -> ESP32 Arduino -> ESP32C6 Dev Module
- 选择串口:
工具 -> 端口
如果看不到串口:
- 换一根支持数据传输的 USB-C 线。
- 换电脑 USB 口。
- 按一下开发板
RESET。 - macOS 或 Windows 可能需要安装 USB 串口驱动,具体看开发板使用的 USB 芯片。
- 点击 Arduino IDE 左上角的“验证”按钮,先确认能编译。
- 编译通过后,点击“上传”按钮。
- 上传完成后,按一下开发板
RESET。 - 等待 ESP32 连接 Wi-Fi 并访问 OpenWrt 接口。
如果上传失败,可以尝试手动进入下载模式:
- 按住
BOOT - 点一下
RESET - 松开
BOOT - 再点击 Arduino IDE 上传
- 上传完成后按一下
RESET
上传成功后的正常现象
正常情况下,屏幕会显示:
C2000 MAX
SYSTEM
CPU / RAM / TEMP / UPTIME
NETWORK
UP / DOWN / LAN / PUB
如果 Wi-Fi 或 OpenWrt 接口暂时不可用,部分数据可能显示为 --。
建议先打开串口监视器
Arduino IDE 中可以打开:
工具 -> 串口监视器
波特率选择:
115200
当前程序主要显示在屏幕上,串口输出不多,但串口监视器可以帮助判断开发板是否已经正常启动。
六、默认屏幕参数
当前 gfx.cpp 默认使用 Waveshare ESP32-C6-LCD-1.47 参数:
constexpr int LCD_MOSI = 6;
constexpr int LCD_SCLK = 7;
constexpr int LCD_CS = 14;
constexpr int LCD_DC = 15;
constexpr int LCD_RST = 21;
constexpr int LCD_BL = 22;
constexpr int LCD_WIDTH = 172;
constexpr int LCD_HEIGHT = 320;
constexpr int LCD_X_OFFSET = 34;
constexpr int LCD_Y_OFFSET = 0;
对应官方参数:
MOSI GPIO6
SCLK GPIO7
CS GPIO14
DC GPIO15
RST GPIO21
BL GPIO22
LCD ST7789
Size 172 x 320
Offset X = 34
七、适配不同 ESP32 型号或不同屏幕
适配其他 ESP32 板子时,主要改 4 类东西:
- 开发板型号
- LCD 引脚
- LCD 驱动型号
- 分辨率、偏移和旋转方向
1. 修改开发板型号
在 Arduino IDE 选择与你硬件匹配的板型,例如:
ESP32 Dev Module
ESP32-S3 Dev Module
ESP32-C3 Dev Module
ESP32-C6 Dev Module
ESP32C6 Dev Module
如果屏幕驱动和引脚都正确,但一直黑屏,优先确认板型是否选错。
2. 修改 LCD 引脚
打开 gfx.cpp,修改:
constexpr int LCD_MOSI = 6;
constexpr int LCD_SCLK = 7;
constexpr int LCD_CS = 14;
constexpr int LCD_DC = 15;
constexpr int LCD_RST = 21;
constexpr int LCD_BL = 22;
不同开发板的屏幕接线不同,必须按实际原理图或商家 Wiki 修改。
如果你的屏幕没有背光控制脚,可以把:
constexpr int LCD_BL = 22;
改成实际背光脚,或者在 gfx_init() 中去掉:
pinMode(LCD_BL, OUTPUT);
digitalWrite(LCD_BL, HIGH);
3. 修改屏幕分辨率和偏移
仍然在 gfx.cpp 修改:
constexpr int LCD_WIDTH = 172;
constexpr int LCD_HEIGHT = 320;
constexpr int LCD_X_OFFSET = 34;
constexpr int LCD_Y_OFFSET = 0;
常见 ST7789 屏幕参数示例:
240 x 240: offset 0, 0 或 0, 80
240 x 320: offset 0, 0
172 x 320: offset 34, 0
170 x 320: offset 35, 0
偏移不对时,常见现象:
- 画面偏移
- 画面只显示一部分
- 边缘有彩条
- 屏幕亮但内容不在可见区域
4. 修改 LCD 驱动类型
当前使用:
Arduino_GFX *gfx = new Arduino_ST7789(...);
如果你的屏幕不是 ST7789,需要换成对应驱动。例如:
Arduino_GFX *gfx = new Arduino_ILI9341(...);
Arduino_GFX *gfx = new Arduino_GC9A01(...);
Arduino_GFX *gfx = new Arduino_ST7735(...);
具体支持哪些驱动,请查看 GFX Library for Arduino 文档或示例。
5. 修改 SPI 总线
当前使用:
Arduino_DataBus *bus = new Arduino_ESP32SPI(
LCD_DC, LCD_CS, LCD_SCLK, LCD_MOSI, GFX_NOT_DEFINED
);
大多数 ESP32 SPI 屏幕都可以这样使用。
如果你的屏幕需要 MISO,可以把最后一个参数改成实际 MISO 引脚:
Arduino_DataBus *bus = new Arduino_ESP32SPI(
LCD_DC, LCD_CS, LCD_SCLK, LCD_MOSI, LCD_MISO
);
6. 修改 UI 分辨率
当前 UI 按 172 x 320 竖屏设计:
disp_drv.hor_res = 172;
disp_drv.ver_res = 320;
如果屏幕分辨率不同,需要在 ui.cpp 里同步修改:
static lv_color_t buf[172 * 40];
disp_drv.hor_res = 172;
disp_drv.ver_res = 320;
例如 240 x 320 竖屏:
static lv_color_t buf[240 * 40];
disp_drv.hor_res = 240;
disp_drv.ver_res = 320;
如果改成横屏,还需要重新调整 ui.cpp 里的控件坐标和宽高。
八、OpenWrt 接口字段说明
ESP32 当前支持以下字段:
{
"load": 0.08,
"cpu_percent": 12,
"mem": 42,
"temp": 48,
"uptime": 123456,
"time": "14:30:08",
"rx": 123456789,
"tx": 987654321,
"rx_speed": 2048,
"tx_speed": 1024,
"lan_ip": "192.168.7.1",
"public_ip": "1.2.3.4"
}
也兼容这些旧字段:
{
"cpu_load": 0.08,
"mem_percent": 42,
"cpu_temp": 48
}
字段说明:
load CPU load average,浮点数,兼容旧字段
cpu_percent CPU 使用率百分比,0-100
mem 内存占用百分比,0-100
temp CPU 温度,摄氏度
uptime OpenWrt 运行时间,单位秒
time OpenWrt 当前时间,建议 HH:MM:SS
rx 网卡累计接收字节数
tx 网卡累计发送字节数
rx_speed 接收速度,Byte/s
tx_speed 发送速度,Byte/s
lan_ip 内网 IP
public_ip 公网 IP
九、修改监控网卡
OpenWrt 脚本默认监控:
IFACE="${IFACE:-br-lan}"
如果你要监控 WAN 口、PPPoE 或其他接口,可以改成实际网卡名,例如:
IFACE="${IFACE:-pppoe-wan}"
查看网卡:
ip link
也可以临时用环境变量运行:
IFACE=pppoe-wan /www/cgi-bin/status.sh
十、常见问题
1. 屏幕完全不亮
优先检查:
LCD_BL背光引脚是否正确LCD_CS、LCD_DC、LCD_RST是否正确- 开发板型号是否选对
- USB 供电是否稳定
当前默认背光是:
pinMode(LCD_BL, OUTPUT);
digitalWrite(LCD_BL, HIGH);
如果你的屏幕背光是低电平点亮,需要改成:
digitalWrite(LCD_BL, LOW);
2. 屏幕亮,但没有内容
可能原因:
- ST7789 偏移参数不对
- 分辨率不对
- SPI 引脚不对
- 屏幕驱动型号不对
重点检查 gfx.cpp 中的:
LCD_WIDTH
LCD_HEIGHT
LCD_X_OFFSET
LCD_Y_OFFSET
Arduino_ST7789
3. 一直显示空数据或网速为 0
先在浏览器打开:
http://你的路由器IP/cgi-bin/status.sh
确认 JSON 是否正常返回。
如果网页打不开:
- CGI 脚本没有执行权限
- 路径不对
- OpenWrt 没启用 uhttpd CGI
- ESP32 和 OpenWrt 不在同一网络
建议按这个顺序排查:
- 电脑浏览器能否打开
status.sh。 - 手机或电脑连接同一个 Wi-Fi 后,能否打开
status.sh。 - config.h 中的
OPENWRT_URL是否和浏览器地址完全一致。 - OpenWrt 的 LAN IP 是否变化。
- ESP32 连接的 Wi-Fi 是否是同一个内网。
如果浏览器能打开,但 ESP32 还是没有数据,优先检查 Wi-Fi 名称和密码。
4. 公网 IP 显示为空
脚本会访问:
http://api.ipify.org
如果路由器不能访问外网,公网 IP 会回退为 WAN IP。某些内网、多级 NAT、旁路由环境下,公网 IP 和 WAN IP 可能不同。
5. 时间显示不对
底部时间优先显示 OpenWrt 的:
date '+%H:%M:%S'
如果时间不对,请先修正 OpenWrt 时间同步:
date
或者检查 OpenWrt 的 NTP 设置。
如果 OpenWrt 自己的 date 时间就是错的,ESP32 屏幕底部时间也会错。请先让 OpenWrt 能正常同步时间。
6. 上传失败
ESP32-C6 有时需要手动进入下载模式:
- 按住
BOOT - 点一下
RESET - 松开
BOOT - 点击 Arduino IDE 上传
- 上传完成后再按一下
RESET
7. 编译失败
如果 Arduino IDE 报错,请先看第一行真正的错误。
常见情况:
No such file or directory
通常是缺少库,回到“管理库”安装对应库。
undefined reference
通常是代码引用了没有参与编译的对象。当前版本已经移除了中文 CJK 字库依赖,如果仍出现这类错误,请清理 Arduino 缓存或重启 Arduino IDE 后再编译。
Sketch uses too much program storage space
通常是启用了过大的字体或图片资源。当前项目已经改为全英文显示,正常不会再因为中文字体导致体积过大。
十一、交付客户前建议
交付给客户前,建议确认:
- Wi-Fi 名称和密码已经改成客户环境
OPENWRT_URL是客户路由器地址- OpenWrt 脚本已经部署并能浏览器访问
- 屏幕能正常点亮
- CPU/RAM/TEMP/UP 有数据
- UP/DOWN 网速会变化
- LAN/PUB IP 正常
- 底部时间与 OpenWrt 时间一致
十二、安全提醒
当前 config.h 中会明文保存 Wi-Fi 密码。公开代码或交付第三方前,建议删除真实密码,改成占位内容:
#define WIFI_SSID "YOUR_WIFI"
#define WIFI_PASS "YOUR_PASSWORD"
OpenWrt 的 status.sh 接口默认没有鉴权,建议只在内网使用,不要暴露到公网。