# Modbus HTTP 接口说明 ## 目标 本服务通过 HTTP 接口连接 Modbus TCP 设备,并返回与 Modbus Poll `Communication` 窗口一致风格的原始 Tx/Rx 报文。 当前仅支持 `ModbusTCP`。 ## 接口列表 - `POST /api/dc-gateway/modbus/read`:原始 Modbus 读取,只返回通信报文,不返回解析值。 - `POST /api/dc-gateway/modbus/read_points`:按点位定义读取,返回点位值。 - `GET /api/dc-gateway/health`:健康检查。 ## 通用返回约定 接口业务结果统一使用 HTTP `200` 返回,是否成功由 JSON 中的 `code` 判断。 成功: ```json { "code": 0, "msg": "success", "data": {} } ``` 失败: ```json { "code": 1, "msg": "failed to connect to 192.168.75.240:505", "data": {} } ``` `data` 固定为对象。两个 Modbus 读取接口都会在 `data.device` 返回设备信息;`/modbus/read` 的通信报文返回在 `data.communication`;`/modbus/read_points` 的点位返回在 `data.points`。 ## 设备参数校验 | 字段 | 是否必传 | 校验 | |---|---|---| | `device_type` | 否 | 默认 `ModbusTCP`,目前仅支持 `ModbusTCP` | | `ip` | 是 | 必须是合法 IP 地址 | | `port` | 是 | `1 <= port <= 65535` | | `word_byte_order` | 否 | 默认 `ABCD`,可选 `ABCD`、`BADC`、`CDAB`、`DCBA` | | `address_base` | 否 | 默认 `0`,必须大于等于 `0` | | `slave_id` | 否 | 默认 `1`,范围 `0..247` | ## communication 格式 `communication` 是字符串数组,每项格式如下: ```text Tx:001-00 00 33 00 00 00 06 01 03 00 00 00 04 Rx:002-00 00 33 00 00 00 0B 01 03 08 00 01 42 A8 00 00 40 F8 ``` 说明: - `Tx` 表示发送给设备的 Modbus TCP ADU。 - `Rx` 表示设备返回的 Modbus TCP ADU。 - `001`、`002` 是当前 HTTP 请求内的报文序号。 - `-` 后面是大写十六进制字节,使用空格分隔。 - 每个 HTTP 请求都会创建独立 trace,不使用全局 trace,并发请求不会互相清空或串包。 - 若 pymodbus 因重试产生多次发送/接收,数组会包含多条 `Tx/Rx`。 ## 地址规则 接口只按照入参格式处理地址。`address_base` 作为显式地址偏移,实际发送给 Modbus 协议的地址为: ```python protocol_address = address + address_base ``` 常规情况下传: ```json "address_base": 0 ``` ## Function Code 支持以下功能码: | function_code | 含义 | |---:|---| | 1 | 读线圈 Read Coils | | 2 | 读离散输入 Read Discrete Inputs | | 3 | 读保持寄存器 Read Holding Registers | | 4 | 读输入寄存器 Read Input Registers | ## 读取数量限制 `/api/dc-gateway/modbus/read` 的 `quantity` 范围为: ```text 1 <= quantity <= 125 ``` 超过范围不会返回 HTTP `422`,而是返回: ```json { "code": 1, "msg": "read.quantity: Input should be less than or equal to 125", "data": { "communication": [] } } ``` ## 接口一:原始读取 ### URL ```http POST /api/dc-gateway/modbus/read ``` ### 请求体 ```json { "device_type": "ModbusTCP", "ip": "192.168.75.240", "port": 505, "word_byte_order": "ABCD", "address_base": 0, "slave_id": 1, "read": { "function_code": 3, "address": 0, "quantity": 4 } } ``` ### 成功返回 ```json { "code": 0, "msg": "success", "data": { "device": { "device_type": "ModbusTCP", "ip": "192.168.75.240", "port": 505, "word_byte_order": "ABCD", "address_base": 0, "slave_id": 1 }, "communication": [ "Tx:001-00 00 33 00 00 00 06 01 03 00 00 00 04", "Rx:002-00 00 33 00 00 00 0B 01 03 08 00 01 42 A8 00 00 40 F8" ] } } ``` 该接口不返回 `values`。如果需要按 `int16`、`float32` 等类型解析数据,请使用点位读取接口。 ### 错误返回 ```json { "code": 1, "msg": "Modbus Error: [Input/Output] No response received after 3 retries, continue with next request", "data": { "device": { "device_type": "ModbusTCP", "ip": "192.168.75.240", "port": 505, "word_byte_order": "ABCD", "address_base": 0, "slave_id": 1 }, "communication": [ "Tx:001-00 00 33 00 00 00 06 01 03 00 00 00 04" ] } } ``` ## 接口二:点位读取并转换 ### URL ```http POST /api/dc-gateway/modbus/read_points ``` ### 请求体 ```json { "device_type": "ModbusTCP", "ip": "192.168.75.240", "port": 505, "word_byte_order": "ABCD", "address_base": 0, "slave_id": 1, "points": [ { "function_code": 3, "address": 7, "type": "int16" }, { "function_code": 3, "address": 1, "type": "float32" }, { "function_code": 1, "address": 0, "type": "bool" } ] } ``` ### 支持的数据类型 | 类型 | 读取长度 | 说明 | |---|---:|---| | `bool` | 1 bit 或 1 register | 布尔值 | | `int16` | 1 register | 有符号 16 位整数 | | `uint16` | 1 register | 无符号 16 位整数 | | `int32` | 2 registers | 有符号 32 位整数 | | `uint32` | 2 registers | 无符号 32 位整数 | | `float32` | 2 registers | IEEE 754 单精度浮点数 | | `int64` | 4 registers | 有符号 64 位整数 | | `uint64` | 4 registers | 无符号 64 位整数 | | `float64` | 4 registers | IEEE 754 双精度浮点数 | ### 成功返回 ```json { "code": 0, "msg": "success", "data": { "device": { "device_type": "ModbusTCP", "ip": "192.168.75.240", "port": 505, "word_byte_order": "ABCD", "address_base": 0, "slave_id": 1 }, "points": [ { "function_code": 3, "address": 7, "type": "int16", "value": -321 } ] } } ``` ## 运行方式 ```bash uvicorn main:app --host 0.0.0.0 --port 8000 ``` 也可以直接运行: ```bash python main.py ``` ## 验证方式 编译检查: ```bash python -m compileall app main.py ``` 调用原始读取接口: ```bash curl -X POST http://127.0.0.1:8000/api/dc-gateway/modbus/read \ -H "Content-Type: application/json" \ -d '{ "device_type": "ModbusTCP", "ip": "192.168.75.240", "port": 505, "word_byte_order": "ABCD", "address_base": 0, "slave_id": 1, "read": { "function_code": 3, "address": 0, "quantity": 4 } }' ``` 运行接口测试: ```bash python -m unittest discover -s intergration/modbus -p "test_*.py" ``` 默认测试设备参数参考 `D:\Projects\BACnet-Client\autotest\Integration\modbus`: ```text MODBUS_DEVICE_IP=192.168.75.240 MODBUS_TCP_PORT=505 MODBUS_SLAVE_ID=1 ``` 可通过环境变量覆盖: ```bash set DATA_COLLECTOR_BASE_URL=http://127.0.0.1:8000 set MODBUS_DEVICE_IP=192.168.75.240 set MODBUS_TCP_PORT=505 set MODBUS_SLAVE_ID=1 ```