【RaspberryPi5开发板方案创意赛】双胞胎健康监测系统-成果贴3-部署贴2一、部署概述1.1 系统架构升级
相比初版部署方案,本次部署进行了以下升级:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ AtomS3R-CAM │ │ Cardputer │ │ 树莓派5 │ │ (摄像头+称重) │ │ (称重采集) │ │ (后端服务) │ │ │ │ │ │ │ │ MQTT Client │ ──────────────────▶│ MQTT Client │ ──────────────────▶│ Flask API │ │ ESP-NOW │ 公网MQTT │ ESP-NOW │ 公网MQTT │ SQLite DB │ │ 摄像头拍照 │ │ 智能网络发现 │ │ Web界面 │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ └──────────────────────────────────────┴──────────────────────────────────────┘ broker.emqx.io:1883 (公网MQTT服务器)
1.2 主要改进改进项说明改进原因
| MQTT服务迁移 | 本地Mosquitto → 公网EMQX服务器 | 家庭网络无公网IP,内网穿透方案复杂且不稳定,公网MQTT服务器可让所有设备直接连接 |
| 新增设备支持 | AtomS3R-CAM(摄像头+称重) | 需要拍照记录功能,用于确认物品使用情况 |
| 智能网络发现 | Cardputer支持自动发现ESP-NOW网络 | 手动配置MAC地址繁琐,设备数量增加后管理困难 |
| 配置同步 | 后端可远程更新设备传感器映射 | 设备配置分散,修改需要逐个更新,容易不一致 |
| 在线状态检测 | 60秒心跳超时自动标记离线 | 原实现只更新不检测,设备断开后仍显示在线,误导用户 |
1.3 设备清单设备类型硬件型号数量功能说明
| 摄像头设备 | M5Stack AtomS3R-CAM | 1-2 | 称重+拍照+MQTT上传 |
| 称重设备 | M5Stack Cardputer V1.1 | 1-N | 称重采集+智能网络发现 |
| 服务器 | 树莓派5 (4GB) | 1 | Flask API + 数据存储 + Web服务 |
| 传感器 | M5Unit-Miniscale | 适量 | 称重检测 |
二、树莓派服务器部署2.1 系统环境准备
# 更新系统sudo apt update && sudo apt upgrade -y# 安装Python依赖sudo apt install python3-pip python3-venv -y# 创建项目目录mkdir -p ~/twins_healthcd ~/twins_health# 创建虚拟环境python3 -m venv venvsource venv/bin/activate# 安装依赖pip install paho-mqtt flask flask-cors pandas openpyxl pillow
2.2 后端代码部署
项目文件结构:
raspberrypi/ ├── backend/ │ ├── mqtt_server.py # 主服务程序 │ ├── mqtt_server_config.py.example # 配置模板 │ ├── image_upload.py # 图片处理 │ ├── image_utils.py # 图像工具 │ ├── decode_image.py # 图像解码 │ └── requirements.txt # 依赖列表 └── frontend/ ├── index.html # 主页面 ├── realtime.html # 实时数据 ├── stats.html # 统计页面 ├── rawdata.html # 原始数据 └── config.html # 配置管理
2.3 MQTT配置
使用公网EMQX服务器,无需本地Mosquitto:
# mqtt_server.py 配置MQTT_BROKER = "broker.emqx.io"MQTT_PORT = 1883MQTT_USER = NoneMQTT_PASSWORD = None# MQTT主题MQTT_TOPIC_WEIGHT = "sensors/twins/weight"MQTT_TOPIC_STATUS = "sensors/twins/status"MQTT_TOPIC_CONFIG = "sensors/twins/config"
2.4 数据库初始化
系统自动创建SQLite数据库,包含以下表:
表名说明
| sensor_data | 传感器数据记录 |
| board_status | 设备在线状态 |
| sensor_mappings | 传感器映射配置 |
| twins_stats | 双胞胎统计汇总 |
| device_registry | 设备注册信息 |
2.5 配置开机自启
创建服务文件 /etc/systemd/system/twins_health.service:
[Unit]Description=Twins Health Monitor Backend ServiceAfter=network.target[Service]Type=simpleUser=piWorkingDirectory=/home/pi/twins_healthExecStart=/home/pi/twins_health/venv/bin/python mqtt_server.pyRestart=alwaysRestartSec=10[Install]WantedBy=multi-user.target
启用服务:
sudo systemctl daemon-reloadsudo systemctl enable twins_healthsudo systemctl start twins_health
2.6 API接口接口方法说明
| /api/data | GET | 获取最新传感器数据 |
| /api/boards | GET | 获取设备在线状态 |
| /api/history | GET | 获取历史数据 |
| /api/mappings | GET/POST | 传感器映射配置 |
| /api/images/upload | POST | 图片上传接口 |
三、AtomS3R-CAM设备部署3.1 硬件特点
AtomS3R-CAM是一款集成摄像头的紧凑型设备:
ESP32-S3芯片
内置OV5640摄像头
I2C接口连接MiniScale称重传感器
支持WiFi和MQTT
3.2 安装MicroPython
AtomS3R-CAM使用M5Stack官方MicroPython固件:
进入下载模式(按住BTN,按RST)
使用M5Burner烧录固件
3.3 配置文件
创建 config.py:
# WiFi配置WIFI_SSID = "YOUR_WIFI_SSID"WIFI_PASSWORD = "YOUR_WIFI_PASSWORD"# MQTT配置MQTT_BROKER = "broker.emqx.io"MQTT_PORT = 1883MQTT_USER = ""MQTT_PASSWORD = ""MQTT_CLIENT_ID = "atoms3r_cam"# MQTT主题MQTT_TOPIC_WEIGHT = "sensors/twins/weight"MQTT_TOPIC_IMAGE = "sensors/twins/image"MQTT_TOPIC_STATUS = "sensors/twins/status"MQTT_TOPIC_CONFIG = "sensors/twins/config"# 设备信息BOARD_ID = "atoms3r_cam"DEVICE_NAME = "AtomS3R-CAM"DEVICE_VERSION = "1.0.0"# 称重配置WEIGHT_CHECK_INTERVAL = 1WEIGHT_CHANGE_THRESHOLD = 2WEIGHT_STABLE_COUNT = 3WEIGHT_STABLE_THRESHOLD = 2# 传感器映射SENSOR_ITEMS = {
"sensor_0": {"item": "toothpaste", "twin": "A"},
"sensor_1": {"item": "water_cup", "twin": "A"}}3.4 核心功能
重量稳定性检测:
def check_weight_stable(self, sensor_id, weight): """ 检测重量是否稳定 三次采样波动小于阈值认为稳定 """ history = self.weight_history.get(sensor_id, []) history.append(weight) if len(history) > WEIGHT_STABLE_COUNT: history = history[-WEIGHT_STABLE_COUNT:] if len(history) >= WEIGHT_STABLE_COUNT: max_diff = max(history) - min(history) if max_diff <= WEIGHT_STABLE_THRESHOLD: return True, history[-1] return False, 0
自动拍照上传:
def _take_and_upload_photo(self): """ 重量稳定后自动拍照并上传 """ # 拍照 img = camera.capture() # RLE5压缩 compressed = image_utils.rle5_compress(img) # HTTP上传 self._http_upload_image(compressed)
3.5 配置同步
设备订阅配置主题,接收后端下发的传感器映射:
def handle_mqtt_config(topic, message):
"""
处理MQTT配置消息
"""
config_data = json.loads(message)
if config_data.get("board_id") == BOARD_ID:
new_items = config_data.get("sensor_items", {})
for sensor_id, item_config in new_items.items():
SENSOR_ITEMS[sensor_id] = {
"twin": item_config.get("twin", ""),
"item": item_config.get("item", "")
}四、Cardputer设备部署4.1 安装CircuitPython
进入Bootloader模式(按住G0,按RST,松开)
复制 .uf2 文件到 CARDPUTERBOOT
4.2 安装依赖库
复制以下库到 CIRCUITPY/lib/ 目录:
lib/ ├── adafruit_minimqtt/ ├── adafruit_st7789.mpy ├── adafruit_requests.mpy ├── espnow.mpy └── miniscale.mpy
4.3 配置文件
创建 settings.toml:
# WiFi配置CIRCUITPY_WIFI_SSID = "YOUR_WIFI_SSID"CIRCUITPY_WIFI_PASSWORD = "YOUR_WIFI_PASSWORD"# 设备信息BOARD_ID = "cardputer"DEVICE_NAME = "Cardputer"DEVICE_VERSION = "1.0.0"DEVICE_MODE = "auto"# MQTT配置MQTT_BROKER = "broker.emqx.io"MQTT_PORT = 1883MQTT_USER = ""MQTT_PASSWORD = ""MQTT_CLIENT_ID = "cardputer"# MQTT主题MQTT_TOPIC_WEIGHT = "sensors/twins/weight"MQTT_TOPIC_STATUS = "sensors/twins/status"MQTT_TOPIC_CONFIG = "sensors/twins/config"# ESP-NOW配置ESPNOW_CHANNEL = 1GATEWAY_MAC = ""NETWORK_ID = "TWINS_HEALTH_2026"# 传感器I2C地址[sensors]C1 = 0x26C2 = 0x2AC3 = 0x2BC4 = 0x2C# 传感器物品映射[sensor_items]C1 = "toothpaste"C2 = "water_cup"C3 = "kettle"C4 = "toothbrush_cup"# 时间间隔配置READ_INTERVAL = 1.0SEND_INTERVAL = 5.0MQTT_SEND_INTERVAL = 5.0STATUS_REPORT_INTERVAL = 30# 重量检测配置WEIGHT_CHECK_INTERVAL = 1WEIGHT_CHANGE_THRESHOLD = 2WEIGHT_STABLE_COUNT = 3WEIGHT_STABLE_THRESHOLD = 2
4.4 智能网络发现
Cardputer支持智能ESP-NOW网络发现:
设备启动 │ ├── 已配置GATEWAY_MAC? ──是──▶ 连接到配置的网关 │ └── 否 ──▶ 搜索网络 (10秒) │ ├── 发现网关 ──▶ 显示选择界面 │ │ │ ├── 单击 KEY0 → 加入网络 │ └── 双击 KEY0 → 创建新网络 │ └── 未发现网关 ──▶ 自动成为网关
4.5 工作模式模式说明
| direct | 直接MQTT上传模式 |
| sender | ESP-NOW发送端模式 |
| gateway | ESP-NOW网关模式 |
| hybrid | 混合模式 |
| auto | 自动检测模式(推荐) |
五、Web界面功能5.1 主页面
访问地址:http://<树莓派IP>:5000
主要功能:
实时传感器数据展示
设备在线状态监控
历史数据图表
双胞胎统计对比
5.2 设备状态监控
系统自动检测设备在线状态:
60秒内有心跳 → 在线(绿色)
超过60秒无心跳 → 离线(红色)
# 后端超时检测逻辑now = datetime.now()offline_threshold = timedelta(seconds=60)for board in boards: last_seen = datetime.strptime(board['last_seen'], "%Y-%m-%d %H:%M:%S") if now - last_seen > offline_threshold: board['status'] = 'offline'
5.3 配置管理
通过 /config.html 页面可以:
查看当前传感器映射
修改传感器物品名称
设置双胞胎标识
配置自动下发到设备
六、数据流程6.1 传感器数据上传
1. 设备采集重量数据
↓
2. 稳定性检测(3次采样,波动<2g)
↓
3. 构建MQTT消息(简化格式)
{
"b": "atoms3r_cam",
"w": 150,
"d": {
"sensor_0": {"w": 50, "t": "A", "i": "toothpaste"},
"sensor_1": {"w": 100, "t": "A", "i": "water_cup"}
}
}
↓
4. 发布到 broker.emqx.io:1883
↓
5. 树莓派订阅并存储到SQLite
↓
6. Web界面实时更新6.2 配置同步流程
1. 设备上线,发送status消息
↓
2. 后端收到消息,查询数据库中的映射配置
↓
3. 后端发布配置到 config 主题
{
"board_id": "atoms3r_cam",
"sensor_items": {
"sensor_0": {"twin": "A", "item": "toothpaste"}
}
}
↓
4. 设备订阅config主题,更新本地配置七、验证测试7.1 检查服务状态
# 检查后端服务sudo systemctl status twins_health# 查看日志sudo journalctl -u twins_health -f
7.2 检查MQTT连接
# 安装MQTT客户端sudo apt install mosquitto-clients# 订阅测试mosquitto_sub -h broker.emqx.io -t "sensors/#" -v
7.3 检查Web服务
浏览器访问:http://<树莓派IP>:5000
应看到:
设备状态显示"在线"
传感器数据实时更新
历史数据图表正常显示
八、常见问题问题解决方案
| WiFi连接失败 | 检查SSID和密码,确认信号强度 |
| MQTT连接失败 | 确认broker.emqx.io可访问 |
| 设备显示离线 | 检查设备是否正常发送心跳 |
| 数据不更新 | 检查MQTT主题是否匹配 |
| 图片上传失败 | 检查HTTP服务器地址配置 |
九、部署总结9.1 部署顺序
✅ 树莓派服务器(先部署,确保API可用)
✅ AtomS3R-CAM设备(摄像头+称重)
✅ Cardputer设备(称重采集)
9.2 关键配置项配置项说明
| MQTT_BROKER | 所有设备必须一致 |
| MQTT_TOPIC_* | 主题名称必须匹配 |
| NETWORK_ID | ESP-NOW网络标识,同一网络必须一致 |
| ESPNOW_CHANNEL | ESP-NOW通道,同一网络必须一致 |
9.3 成功标志
设备串口输出:MQTT连接成功
Web界面设备状态:在线
传感器数据实时更新
历史数据正常记录
十、项目帖子汇总
本项目在EEPW论坛发布的全部帖子:
序号帖子标题链接
| 1 | 开箱贴 | https://forum.eepw.com.cn/thread/399205/1 |
| 2 | 过程贴 | https://forum.eepw.com.cn/thread/399206/1 |
| 3 | 成果贴1 | https://forum.eepw.com.cn/thread/399208/1 |
| 4 | 成果贴2-部署贴1 | https://forum.eepw.com.cn/thread/399209/1 |
部署完成日期:2026年2月
总结图片:









全部部署源码和文档,内容较多,请下载后解压:
twins_health_source_code.zip
我要赚赏金
