水产养殖物联网智能测控系统

  • ~3.65K 字

这个项目来自一次接单需求,目标是完成《物联网通信与控制技术》课程设计中的客户端软件部分。题目方向是物联网通信与控制系统,具体场景选为水产养殖智能测控。

背景

这个项目来自一次接单需求,目标是完成《物联网通信与控制技术》课程设计中的客户端软件部分。题目方向是物联网通信与控制系统,具体场景选为水产养殖智能测控。

客户的核心诉求并不是接入真实云平台,而是完成一个能本地运行、能和 ModSim 模拟传感器通信、能展示测控过程、能打包成 EXE 的课程设计系统。因此技术选型上没有走复杂的前后端工程化路线,而是选择了更稳妥的本地 Web 服务:

  • Python 标准库实现 HTTP 服务和 Modbus TCP 通信。
  • SQLite 做本地持久化。
  • 原生 HTML/CSS/JavaScript 实现客户端页面。
  • pywebview 将本地 Web 页面封装为桌面程序。
  • PyInstaller 打包为 EXE。

这个组合的好处是部署简单、依赖少、容易解释,也比较符合课程设计对“通信协议、传感器模拟、客户端软件开发”的考核重点。

快速预览

image.png
image.png
image.png
image.png
image.png
image.png
image.png

系统目标

系统围绕水产养殖池塘中的五个关键指标展开:

指标 单位 说明
溶解氧含量 mg/L 反映水体供氧情况
水位值 m 反映养殖池水位
pH 值 pH 反映水体酸碱性
养殖水温 °C 反映养殖水环境温度
氧气浓度 % 反映供氧环境状态

对应的执行设备包括:

  • 增氧机
  • 补水泵
  • 排水阀
  • 循环泵
  • 恒温调节器
  • pH 调节泵
  • 氧气调节阀

最初容易把系统做成一个“数据看板”:ModSim 改数值,页面显示数值。但这种效果比较薄,答辩时也很难体现“控制”。因此实现中额外加入了设备连续运行模型,让设备开关和运转速率可以持续改变传感器指标。

例如打开补水泵后,水位会持续上升;打开增氧机后,溶解氧和氧气浓度会持续上升;pH 调节泵则会让 pH 逐步靠近后台设置的目标值。

技术架构

系统可以分为六层:

  1. 传感器模拟层:ModSim32 模拟保持寄存器。
  2. 通信层:Python 实现 Modbus TCP 读取和写入。
  3. 数据处理层:采集线程处理设备联动、报警、存储。
  4. 服务接口层:HTTP API 和 SSE 实时推送。
  5. 前端展示层:场景监控、曲线、历史、用户管理。
  6. 桌面封装层:pywebview + PyInstaller。

核心代码集中在几个文件中:

文件 作用
aquaculture_iot/app.py 后端主程序,包含数据库、Modbus、采集线程、算法和接口
aquaculture_iot/static/app.js 前端交互逻辑,处理实时刷新、设备控制和曲线绘制
aquaculture_iot/static/index.html 页面结构
aquaculture_iot/static/style.css 页面样式
desktop_app.py 桌面程序入口
build_exe.ps1 打包脚本

Modbus 寄存器设计

系统使用 Modbus TCP 保持寄存器。程序内部地址从 0 开始,而 ModSim 页面通常显示为 40001 起算。

ModSim 地址 程序地址 数据项 缩放
40001 0 溶解氧含量 原始值 × 0.01
40002 1 水位值 原始值 × 0.001
40003 2 pH 值 原始值 × 0.01
40004 3 养殖水温 原始值 × 0.1
40005 4 氧气浓度 原始值 × 0.1
40011-40017 10-16 执行器速率/开度 0-100

后端 ModbusTcpClient 实现了三个功能码:

  • 03:读取保持寄存器。
  • 06:写单个保持寄存器。
  • 16:批量写保持寄存器。

设备控制时,页面会把执行器速率写入 40011-40017。采集线程读取传感器值后,会根据设备状态计算新的指标值,并尝试回写到 40001-40005。这样在 ModSim 中也能看到数据随设备运行变化。

设备联动算法

这个项目比较关键的部分是设备联动算法。为了让控制逻辑可解释,系统没有写死各种 if-else,而是设计了一张设备影响比例矩阵。

直接影响型设备使用公式:

1
新值 = 当前值 + (速率 / 100) × 整体倍率 × 影响比例 × 采样间隔

目标调节型设备使用公式:

1
新值 = 当前值 + (基础目标值 - 当前值) × (速率 / 100) × 整体倍率 × 影响比例 × 采样间隔

默认矩阵如下:

设备 溶解氧 水位 pH 水温 氧气浓度 类型
增氧机 +0.280 0 0 0 +0.140 直接影响
补水泵 0 +0.040 0 0 0 直接影响
排水阀 0 -0.045 0 0 0 直接影响
循环泵 +0.060 0 +0.055 +0.055 0 目标调节
恒温调节器 0 0 0 +0.140 0 目标调节
pH 调节泵 0 0 +0.180 0 0 目标调节
氧气调节阀 0 0 0 0 +0.350 直接影响

例如补水泵速率为 60%,水位影响比例为 0.040,则每秒水位变化约为:

1
0.60 × 1.0 × 0.040 = 0.024 m/s

前端设备卡片会实时显示这个换算结果。用户拖动速率滑块时,卡片中的“实际影响值”也会同步变化,这比只显示一个固定比例更直观。

一个实际修复:水位为什么会卡在 1.55m

开发中遇到过一个很典型的问题:当用户把水位阈值上限调高后,补水泵仍然只能把水位推到 1.55 m,不再继续增加。

原因是早期代码里为了避免仿真数据跑飞,把水位硬编码限制在 1.55 m。这个限制在默认阈值下没有问题,但当用户手动把报警上限调高时,就变成了 bug。

后来改成动态过程边界:

1
2
过程上限 = max(默认过程上限, 当前报警上限 + 0.10)
过程下限 = min(默认过程下限, 当前报警下限 - 0.10)

同时再设置一个绝对安全边界,例如水位不超过 5.0 m,pH 不超过 14。这样既能尊重用户设置的阈值,又不会让仿真值无限增长。

对应代码在:

1
2
process_limits()
SensorCollector._apply_process_effects()

前端实现细节

前端没有使用大型框架,而是使用原生 JavaScript。原因很简单:这是课程设计项目,减少构建工具和依赖能降低交付风险。

前端主要做了几件事:

  1. 登录后加载配置。
  2. 根据传感器配置生成指标卡片。
  3. 根据执行器配置生成设备控制卡片。
  4. 使用 SSE 接收后端实时数据。
  5. 使用 Canvas 绘制动态曲线。
  6. 根据报警记录高亮场景传感器。
  7. 支持历史数据查询、CSV 导出和用户管理。

其中 SSE 是比较适合这个项目的方案。相比前端每秒轮询,SSE 可以由服务端主动推送数据,代码也比 WebSocket 简单。

关键函数包括:

函数 作用
bootstrap() 页面初始化,检查登录状态
startEvents() 建立 SSE 实时连接
applySnapshot() 将后端快照同步到页面
renderActuatorCards() 渲染设备卡片
formatEffectChip() 显示当前速率下的实际影响值
drawTrend() 绘制实时曲线
refreshUsers() 管理员用户管理

桌面封装

桌面封装的入口是 desktop_app.py。它不是重新写一个桌面 GUI,而是启动本地 Web 服务,再用 pywebview 打开本地页面。

流程如下:

  1. 从 8000-8999 中寻找可用端口。
  2. 启动 Python HTTP 服务。
  3. 创建 pywebview 桌面窗口。
  4. 窗口关闭时停止服务。

这种方案的好处是:开发时可以直接浏览器调试,交付时又可以打包成 EXE,兼顾开发效率和交付体验。

项目收获

这个项目看起来是一个课程设计,但里面包含了不少真实交付中常见的问题:

  • 如何在不引入复杂依赖的情况下完成本地客户端。
  • 如何让模拟数据不是静态变化,而是有设备控制反馈。
  • 如何处理 EXE 首次启动时数据库初始化顺序。
  • 如何让客户调参数时,页面展示和后台算法保持一致。
  • 如何排除客户资料、交付包、运行数据库等不适合公开的内容。

最终系统不只是“能显示数据”,而是具备通信、控制、存储、报警、用户管理和打包交付的一套完整本地测控软件。

代码仓

GitHub:https://github.com/ORI2333/aquaculture-iot-control-system
如果对您有帮助,请帮我点个star!

赞助喵
非常感谢您的喜欢!
赞助喵
分享这篇文章
分享链接会先进入线路选择页,读者可选择稳定访问、腾讯云 CDN 或备用镜像。