路由器 IoT 网关复刻指南 (X-WRT/OpenWrt + eMMC)
JDCloud 路由器(X-WRT 系统)上构建了一个高效、稳定的 嵌入式 IoT 数据网关。
利用 128GB 的 eMMC,我们避开了路由器 Flash 空间不足的限制,实现了数据的本地持久化与 Web 可视化。
一、 已完成的操作总结
1. 存储空间优化 (eMMC 适配)
- 路径重定向:将
apk包管理器的数据库(/lib/apk)和缓存迁移到 eMMC。 - 环境准备:在
/mnt/emmc下建立了opt、db、www、cgi-bin等目录,确保系统重启后配置不丢失(通过rc.local自动建立软链接)。
2. 软件环境部署
- 包管理器切换:确认系统使用
apk而非opkg。 - 核心组件安装:安装了非加密版的
mosquitto-nossl(降低资源占用)和sqlite3-cli(轻量级数据库)。 - Web 服务配置:开启了
uhttpd的 CGI 前缀支持(/cgi-bin),并建立了 Web 软链接。
3. 数据链路打通
- 数据库初始化:建立了支持历史曲线(
sensor_history)和实时状态(sensor_latest)的 SQLite 表结构。 - 自动化采集:编写了 Shell 脚本(利用
mosquitto_sub管道流)实时监听 MQTT 消息并自动写入数据库。 - API 开发:实现了基于 CGI 的 JSON 接口,供前端网页调用。
二、 MQTT 实现架构图
当前系统的逻辑架构如下:
1. 采集层 (Data Collection)
- 设备端:温湿度计、故障指示器、STM32(GaN 信号源)等通过 Wi-Fi/以太网发送 MQTT 报文。
- 主题设计:采用分级主题(如
env/temp或device/current)来区分不同设备和数据类型。
2. 处理层 (Processing & Storage)
- MQTT Broker (Mosquitto):负责消息的中转和分发。
- Data Bridge (Shell Script):充当“中间件”,它订阅感兴趣的主题,将接收到的异步字符串解析为结构化数据。
- Storage (SQLite):将数据物理存储在 128GB eMMC 中。SQLite 的 ACID 特性保证了即使在断电情况下,数据记录也不会损坏。
3. 展示层 (Visualization)
- Web Server (uhttpd):处理 HTTP 请求。
- CGI Interface:负责连接 Web 和数据库,执行 SQL 查询并将结果转化为 JSON 格式。
- Dashboard (HTML5 + ECharts):用户浏览器运行 JavaScript,异步抓取 JSON 数据并绘制出平滑的电流、温度历史曲线。
三、 架构的优势
- 高可靠性:128GB eMMC 几乎可以存储几亿条记录,完全不用担心空间满。
- 低耦合:你可以随时增加新的传感器,只需修改
mqtt_to_db.sh里的主题匹配逻辑即可,不需要重新编译程序。 - 零外部依赖:所有数据都在路由器本地处理,不需要上云,保护了工业/个人数据的私密性,且在断网状态下依然正常工作。
第一步:eMMC 环境初始化
在刷好 X-WRT 固件后,首先将存储压力转移到 eMMC 分区。
Bash
# 1. 创建 eMMC 基础目录
mkdir -p /mnt/emmc/apk/lib_apk /mnt/emmc/apk/cache /mnt/emmc/db /mnt/emmc/www/cgi-bin
# 2. 迁移 apk 数据库防止系统 Flash 撑爆
cp -a /lib/apk /mnt/emmc/apk/lib_apk_backup
rm -rf /lib/apk && ln -s /mnt/emmc/apk/lib_apk /lib/apk
rm -rf /var/cache/apk && ln -s /mnt/emmc/apk/cache /var/cache/apk
# 3. 验证 apk 是否可用
apk update
第二步:核心软件安装
卸载默认的 SSL 版本(节省资源,解决冲突),安装非加密版。
Bash
# 1. 切换 Mosquitto 版本
apk del mosquitto-ssl mosquitto-client-ssl
apk add mosquitto-nossl mosquitto-client-nossl
# 2. 安装数据库工具
apk add libsqlite3-0 sqlite3-cli
第三步:数据库与 API 配置
建立数据表并打通 Web 接口。
Bash
# 1. 初始化数据库表结构
sqlite3 /mnt/emmc/db/iot.db <<EOF
CREATE TABLE IF NOT EXISTS sensor_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
topic TEXT,
value REAL,
time DATETIME DEFAULT (datetime('now', 'localtime'))
);
CREATE TABLE IF NOT EXISTS device_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
device_id TEXT,
event_type TEXT,
description TEXT,
time DATETIME DEFAULT (datetime('now', 'localtime'))
);
EOF
# 2. 开启 Web 服务器 CGI 支持
uci set uhttpd.main.cgi_prefix='/cgi-bin'
uci commit uhttpd
/etc/init.d/uhttpd restart
第四步:写入自动化脚本
这两个脚本是系统的核心“桥梁”。
1. 数据采集脚本 (/mnt/emmc/mqtt_to_db.sh)
Bash
cat << 'EOF' > /mnt/emmc/mqtt_to_db.sh
#!/bin/sh
DB="/mnt/emmc/db/iot.db"
mosquitto_sub -t "env/#" -t "device/#" -v | while read -r line
do
TOPIC=$(echo $line | cut -d' ' -f1)
VAL=$(echo $line | cut -d' ' -f2-)
# 写入历史曲线表
if echo "$TOPIC" | grep -Eq "temp|humi|current"; then
sqlite3 $DB "INSERT INTO sensor_history (topic, value) VALUES ('$TOPIC', $VAL);"
# 写入事件日志表
elif echo "$TOPIC" | grep -Eq "status|event"; then
D_ID=$(echo $TOPIC | cut -d'/' -f2)
sqlite3 $DB "INSERT INTO device_events (device_id, event_type, description) VALUES ('$D_ID', 'EVENT', '$VAL');"
fi
done
EOF
chmod +x /mnt/emmc/mqtt_to_db.sh
2. 数据接口 API (/mnt/emmc/www/cgi-bin/data)
Bash
cat << 'EOF' > /mnt/emmc/www/cgi-bin/data
#!/bin/sh
echo "Content-Type: application/json"
echo ""
sqlite3 /mnt/emmc/db/iot.db "SELECT json_group_array(json_object('time', time, 'topic', topic, 'val', value)) FROM (SELECT * FROM sensor_history ORDER BY id DESC LIMIT 100);"
EOF
chmod +x /mnt/emmc/www/cgi-bin/data
第五步:设置开机自启
编辑 /etc/rc.local,在 exit 0 之前加入:
Bash
# 建立 Web 目录映射
ln -s /mnt/emmc/www /www/iot
mkdir -p /www/cgi-bin
ln -s /mnt/emmc/www/cgi-bin/data /www/cgi-bin/data
# 启动数据采集后台
/mnt/emmc/mqtt_to_db.sh &
架构逻辑图示
系统运行流程:
- MQTT 终端:发送数据至路由器 IP。
- Mosquitto:接收数据流。
- Shell 脚本:从 Mosquitto 抓取数据,解析后通过
sqlite3命令插入 eMMC 文件。 - 前端网页:用户访问
/iot/index.html,JS 调用/cgi-bin/data。 - CGI 接口:读取数据库返回 JSON,由 ECharts 完成绘图。