# NexIoT-Simulator
**Repository Path**: thingscan/NexIoT-Simulator
## Basic Information
- **Project Name**: NexIoT-Simulator
- **Description**: A single-process device simulator covering 4 industrial protocols, for integration development and testing against host systems such as ThingsBoard Gateway.
- **Primary Language**: Python
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2026-08-28
- **Last Updated**: 2026-08-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# NexIoT Simulator(物联网协议模拟器)
> **中文** | [English](./README.md)
**一个单进程模拟 4 种工业协议的设备模拟器,用于 ThingsBoard Gateway 等上位系统的对接开发与测试。**
`python -m app` 一键启动后,同时运行 Modbus TCP、OPC UA、BACnet、Siemens S7 四个协议服务器与一个 FastAPI 管理接口,附带 Vue 3 前端点位配置界面。所有点位数据通过 REST API 即可配置与修改,**最多 1 秒内在协议线侧生效**。
[](https://www.python.org/)
[](https://fastapi.tiangolo.com/)
[](https://vuejs.org/)
[](LICENSE)
> 想看技术细节与内部机制?请阅读 [`doc/`](doc/README.md) 下的技术文档。
---
## 目录
- [功能特性](#功能特性)
- [界面预览](#界面预览)
- [支持的协议与端口](#支持的协议与端口)
- [快速开始](#快速开始)
- [Docker 一键安装(推荐)](#docker-一键安装推荐)
- [Docker Compose(开发方式)](#docker-compose开发方式)
- [本地运行(Python + 前端)](#本地运行python--前端)
- [使用说明](#使用说明)
- [API 概览](#api-概览)
- [技术文档](#技术文档)
- [项目结构](#项目结构)
- [测试与验证](#测试与验证)
- [环境变量覆盖初始值](#环境变量覆盖初始值)
- [常见问题](#常见问题)
- [贡献指南](#贡献指南)
- [许可证](#许可证)
---
## 功能特性
- **四大工业协议**:同时模拟 Modbus TCP(2 个从站)、OPC UA(2 个设备)、BACnet(15 个对象)、Siemens S7(4 个内存区域)设备。
- **配置即生效**:通过 REST API / 前端界面新建、修改、删除点位后,同步循环在 **≤1 秒** 内将值写入协议线侧(详见 [`doc/03-data-flow.md`](doc/03-data-flow.md))。
- **RPC 写入**:所有协议均支持原生写入(FC06/FC16、UA Write、BACnet WriteProperty、S7 write_area)及统一的 REST API 写入。
- **Web 管理界面**:Vue 3 + Pinia 前端,支持点位列表(按协议筛选)、详情、新建/编辑/删除、JSON 导入/导出。
- **完整 REST API**:点位 CRUD、值读写、导入导出、统计,附 Swagger 交互式文档。
- **灵活配置**:通过环境变量即可覆盖各协议初始值,无需重新构建镜像。
- **配置持久化**:点位配置与当前值自动保存到磁盘(默认 `./data/points.json`),容器重启 / 重建后自动恢复,无需重新配置。
- **开箱即用**:内置 49 个种子点位,涵盖多协议、多数据类型(bit/uint16/int32/float32/double/string/boolean 等)。
## 界面预览
**Web 管理界面** —— 点位列表、按协议筛选、统计与操作:

**Modbus TCP 客户端读取**(线圈 / 离散输入 / 保持寄存器):

**OPC UA 客户端读取**(MyDevice / MyDevice1 节点):

**S7 客户端读取**(I / Q / M 区)与 **DB1 数据块读取**:

## 支持的协议与端口
| 协议 | 端口 | 传输 | 说明 |
|------|------|------|------|
| Modbus TCP | `502` | TCP | 2 个从站设备(unit 1 / 2),含线圈、离散输入、输入/保持寄存器 |
| OPC UA | `53530` | TCP | `opc.tcp://0.0.0.0:53530/OPCUA/SimulationServer`,2 个设备 |
| BACnet | `47808` | UDP | 设备实例 1234(SimBACnetDevice),15 个对象 |
| S7 | `102` | TCP | Siemens S7 模拟,I / Q / M / DB1 四个内存区域 |
| HTTP | `8000` | TCP | FastAPI 管理接口 + 前端页面(可用 `API_PORT` 环境变量修改) |
> 端口多为 0–1024 特权端口(502 / 102),Linux 下直接本地运行需 root 权限,建议使用 [Docker 方式](#docker-一键安装推荐)。
## 快速开始
### Docker 一键安装(推荐)
直接运行预构建镜像,无需任何构建:
```bash
docker run -d --name nexiot-simulator --restart unless-stopped \
-p 502:502 \
-p 53530:53530 \
-p 47808:47808/udp \
-p 102:102 \
-p 8000:8000 \
-v nexiot-data:/app/data \
crpi-pormt4sdd35mkqt3.cn-hangzhou.personal.cr.aliyuncs.com/jettzhan/nexiot-simulator
```
- `--restart unless-stopped`:容器退出后自动重新拉起,开机自启。
- `-v nexiot-data:/app/data`:命名卷持久化。点位配置与当前值存于其中,容器重启 / 重建后自动恢复;首次启动无文件时自动写入 49 个种子点位。
- 如需覆盖初始值,追加 `-e 变量=值`(如 `-e "MB_FLOAT_0=42.5"`),详见[环境变量覆盖初始值](#环境变量覆盖初始值)。
启动后:
| 服务 | 地址 |
|------|------|
| Web 管理界面 | |
| Swagger API 文档 | |
| Modbus TCP | `localhost:502` |
| OPC UA | `opc.tcp://localhost:53530/OPCUA/SimulationServer` |
| BACnet | `localhost:47808` (UDP) |
| S7 | `localhost:102` |
### Docker Compose(开发方式)
适合开发调试:从本机构建镜像并以 Compose 编排运行,`docker-compose.yml` 已配置好端口映射与命名卷 `nexiot-data`。
```bash
docker compose up -d --build
```
### 本地运行(Python + 前端)
依赖 Python 3.11+ 与 Node.js 18+。
```bash
# 1. 安装后端依赖
pip install -r requirements.txt
# 2. 启动模拟器(默认 API 端口 8000)
python -m app
# 或自定义 API 端口:API_PORT=8001 python -m app
```
前端为可选构建(否则无 Web 界面,API 不受影响):
```bash
cd frontend
npm install
npx vite build # 构建产物输出到 ../app/static,重启 app 后由 FastAPI 托管
# 开发模式(热更新,代理 /api → localhost:8000):
npm run dev
```
## 使用说明
1. 打开 查看点位列表与统计,按协议筛选点位。
2. 在界面中新建 / 编辑 / 删除点位,或导入/导出 JSON 配置(所有变更自动保存)。
3. 修改点位值后,OPC UA / BACnet / S7 / Modbus 会在 **≤1 秒** 内同步到协议线侧,可直接被 ThingsBoard Gateway 等客户端读取。
4. 下次启动 / 重启容器后,之前配置的点位与当前值会自动恢复。
5. 详细点位表(每个寄存器/节点的地址与初始值)见 [`doc/02-data-model.md`](doc/02-data-model.md)。
## API 概览
Base URL:`http://:8000`,交互式文档:`http://:8000/docs`。
| 方法 | 路径 | 说明 |
|------|------|------|
| `GET` | `/api/points` | 点位列表 + 统计 |
| `POST` | `/api/points` | 新建点位 |
| `GET` | `/api/points/{id}` | 点位详情 + 当前值 |
| `PUT` | `/api/points/{id}` | 更新点位 |
| `DELETE` | `/api/points/{id}` | 删除点位 |
| `DELETE` | `/api/points` | 清空全部点位 |
| `GET` | `/api/points/{id}/value` | 读取当前值 |
| `PUT` | `/api/points/{id}/value` | 写入当前值(RPC) |
| `GET` | `/api/points/export` | 导出全部点位配置 |
| `POST` | `/api/points/import` | 全量导入点位配置 |
| `GET` | `/api/stats` | 点位统计 |
**快速上手:**
```bash
# 列出点位
curl http://localhost:8000/api/points
# 写入 OPC UA 点位值(1s 内同步到 UA 节点)
curl -X PUT http://localhost:8000/api/points/16/value \
-H "Content-Type: application/json" -d '{"value":200.5}'
# 新建 Modbus 点位
curl -X POST http://localhost:8000/api/points \
-H "Content-Type: application/json" \
-d '{"name":"MB_Test","protocol":"modbus","modbus":{"unitId":1,"functionCode":"03","address":30,"dataType":"uint16","byteOrder":"AB"},"initialValue":777,"changeMode":"fixed"}'
```
完整接口参考与请求/响应示例见 [`doc/05-api.md`](doc/05-api.md)。
## 技术文档
系统设计、数据模型、生效机制、协议实现等详细说明记录在 [`doc/`](doc/README.md) 目录:
| 文档 | 内容 |
|------|------|
| [doc/README.md](doc/README.md) | 技术文档索引与 30 秒架构速览 |
| [01-architecture.md](doc/01-architecture.md) | 系统架构、技术栈、进程/线程模型、端口分配 |
| [02-data-model.md](doc/02-data-model.md) | 点位数据模型、Registry 设计、49 个种子点位 |
| [03-data-flow.md](doc/03-data-flow.md) | **核心**:数据流与"配置即生效"机制 |
| [04-protocol-implementation.md](doc/04-protocol-implementation.md) | 四个协议服务器实现细节 |
| [05-api.md](doc/05-api.md) | REST API 参考(含请求/响应示例) |
| [06-run-deploy.md](doc/06-run-deploy.md) | 运行、前端构建、Docker 部署、环境变量覆盖 |
| [07-verification.md](doc/07-verification.md) | 验证与测试方法(三层验证体系) |
> 以上文档均提供英文版,见 [`doc/en/`](doc/en/README.md)(英文版 README 为默认主文档 [README.md](./README.md))。
## 项目结构
```
.
├── app/ # 后端(单进程运行)
│ ├── __main__.py # 启动入口:加载持久化配置/种子数据 + 4 个服务器线程 + uvicorn
│ ├── main.py # FastAPI 实例,挂载 /api 与静态资源
│ ├── api.py # REST 路由(点位 CRUD / 值读写 / 导入导出 / 统计)
│ ├── registry.py # PointRegistry:内存点位配置 + 值存储(线程安全)
│ ├── persistence.py # 点位配置与当前值的 JSON 持久化
│ ├── seed.py # 49 个种子点位
│ ├── static/ # 前端构建产物(由 FastAPI 托管在 /)
│ └── servers/ # 四个协议服务器
│ ├── modbus_server.py
│ ├── opcua_server.py
│ ├── bacnet_server.py
│ └── s7_server.py
├── frontend/ # Vue 3 + Pinia + Vite + TypeScript 前端
│ └── src/
│ ├── api/ # REST 封装(fetch)
│ ├── stores/ # Pinia store(点位列表/筛选/详情/操作)
│ ├── types/ # TypeScript 类型(与后端点位结构对应)
│ └── components/ # StatsBar / PointList / PointDetail / PointModal
├── doc/ # 技术文档
├── img/ # README 截图
├── tests/ # 单元 / 集成测试(pytest)
├── verify_point_config.py # 点位配置生效验证脚本(需启动服务后运行)
├── Dockerfile
└── docker-compose.yml
```
## 测试与验证
项目采用三层验证体系(详见 [`doc/07-verification.md`](doc/07-verification.md)):
```bash
# 1. 单元测试(37 项,无需启动服务)
python -m pytest tests -v -p no:cacheprovider
# 2. 线级综合测试(需先启动模拟器,162 项)
python tests/test_all_protocols.py
# 3. 点位配置生效验证(需先启动模拟器,10 项)
python verify_point_config.py
```
四个协议均已实测验证"API 配置 ≤1s 同步到线侧"(新建点位、改值、RPC 写入等),结论见 [`doc/07-verification.md`](doc/07-verification.md#6-已知结论验证过程中确认)。
## 环境变量覆盖初始值
无需修改代码即可在 `docker-compose.yml` 或 shell 中覆盖各协议初始值:
| 前缀 | 说明 | 示例 |
|------|------|------|
| `MB_*` | Modbus 初始值 | `MB_FLOAT_0=42.5`、`MB_COIL_BITS=1023` |
| `UA_*` | OPC UA 变量值 | `UA_MyDevice_Temperature=30.0` |
| `BAC_*` | BACnet 对象 presentValue | `BAC_AV_2=70.0`、`BAC_BV_1=inactive` |
| `S7_*` | S7 内存区字节 | `S7_DB1_DBD0=99999`、`S7_M_0=255` |
| `API_PORT` | FastAPI 端口(默认 8000) | `API_PORT=8001` |
```yaml
# docker-compose.yml 示例
environment:
- MB_FLOAT_0=42.5 # Modbus 第 1 个 float 改为 42.5
- UA_MyDevice_Count=999 # OPC UA MyDevice.Count 改为 999
- BAC_AV_2=70.0 # BACnet HumiditySetpoint 改为 70%
- S7_DB1_DBD0=88888 # S7 DB1.DBD0 改为 88888
```
完整变量清单见 [`doc/06-run-deploy.md`](doc/06-run-deploy.md#5-环境变量覆盖初始值)。
## 常见问题
**Q: Modbus / S7 端口启动失败(Permission denied)?**
端口 502 / 102 属于特权端口,Linux 下需 root 或使用 Docker(容器内以 root 运行)。
**Q: Docker 构建时基础镜像拉取失败?**
如网络受限无法访问 `python:3.11-slim`,将 `Dockerfile` 中的基础镜像替换为可访问的镜像源后重新构建。
**Q: 修改点位值后线侧没有变化?**
- OPC UA / BACnet / S7 / Modbus 均通过每秒同步循环从 Registry 拉值,理论上 ≤1s 生效。
- 外部工具原生写入的值会被同步循环以 Registry 值覆盖,如需持久请通过 REST API 写入保持一致(详见 [`doc/03-data-flow.md`](doc/03-data-flow.md))。
**Q: 验证/联调时读到的数据是旧的?**
可能有残留的旧模拟器进程占用端口,清理后重启即可。
## 贡献指南
欢迎提交 Issue 与 Pull Request。
- 提交 Bug 时请附上协议、端口、复现步骤与日志。
- 代码风格遵循 PEP 8;修改后请运行 `python -m pytest tests` 确保测试通过。
- 补充或修改协议行为时,请同步更新 [`doc/`](doc/README.md) 下对应的技术文档。
## 许可证
本项目基于 [Apache License 2.0](LICENSE) 开源。