路由器 IoT 网关复刻指南 (X-WRT/OpenWrt + eMMC)

JDCloud 路由器(X-WRT 系统)上构建了一个高效、稳定的 嵌入式 IoT 数据网关

利用 128GB 的 eMMC,我们避开了路由器 Flash 空间不足的限制,实现了数据的本地持久化与 Web 可视化。


一、 已完成的操作总结

1. 存储空间优化 (eMMC 适配)

  • 路径重定向:将 apk 包管理器的数据库(/lib/apk)和缓存迁移到 eMMC。
  • 环境准备:在 /mnt/emmc 下建立了 optdbwwwcgi-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/tempdevice/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 &

架构逻辑图示

系统运行流程:

  1. MQTT 终端:发送数据至路由器 IP。
  2. Mosquitto:接收数据流。
  3. Shell 脚本:从 Mosquitto 抓取数据,解析后通过 sqlite3 命令插入 eMMC 文件。
  4. 前端网页:用户访问 /iot/index.html,JS 调用 /cgi-bin/data
  5. CGI 接口:读取数据库返回 JSON,由 ECharts 完成绘图。

发表回复