项目结构
依赖
# python 3.7
fastapi==0.103.2
loguru==0.7.3
minimalmodbus==2.0.1
pyinstaller==5.13.2
uvicorn==0.22.0
config.ini
[modbus]
port = COM1
address = 1
baudrate = 9600
bytesize = 8
parity = N
stopbits = 1
timeout = 1
[webserver]
port = 8001
main.py
# coding: utf-8
# python 3.7
import random
import time
import minimalmodbus
import uvicorn
import configparser
from fastapi import FastAPI, Request
from starlette.middleware.cors import CORSMiddleware
from loguru import logger
import os
class Setting(object):
'''配置相关'''
def __init__(self):
self.base_dir = os.path.dirname(__file__)
self.config_ini = os.path.join(self.base_dir, 'config.ini')
self.config = configparser.ConfigParser()
self.config.read(self.config_ini)
self.modbus_config = self.config['modbus']
self.webserver_config = self.config['webserver']
self._analysis_conf()
self._init_instrument()
def _analysis_conf(self):
'''解析配置'''
self.port = self.modbus_config.get('port')
self.address = self.modbus_config.getint('address')
self.baudrate = self.modbus_config.getint('baudrate')
self.bytesize = self.modbus_config.getint('bytesize')
self.parity = self.modbus_config.get('parity')
self.stopbits = self.modbus_config.getint('stopbits')
self.timeout = self.modbus_config.getfloat('timeout')
self.websever_port = self.webserver_config.getint('port')
if self.parity == 'E':
self.parity = minimalmodbus.serial.PARITY_EVEN
elif self.parity == 'O':
self.parity = minimalmodbus.serial.PARITY_ODD
else:
self.parity = minimalmodbus.serial.PARITY_NONE
def _init_instrument(self):
'''实例化modbus'''
self.instrument = minimalmodbus.Instrument(self.port, self.address)
self.instrument.serial.baudrate = self.baudrate
self.instrument.serial.bytesize = self.bytesize
self.instrument.serial.parity = self.parity
self.instrument.serial.stopbits = self.stopbits
self.instrument.serial.timeout = self.timeout
self.instrument.mode = minimalmodbus.MODE_RTU # rtu
app = FastAPI()
modbus = Setting()
app.add_middleware( # 跨域
CORSMiddleware,
allow_origins=["*", ],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.middleware("http")
async def middleware(request: Request, call_next):
'''中间件'''
now = time.strftime("%Y/%m/%d #H:%M:%S")
client_host = request.client.host
method = request.method
path = request.url.path
http_version = request.scope.get("http_version")
logger.warning(f'当前请求IP为-->{client_host}')
# print(f"[{now}] {method} {path} {http_version}")
logger.debug(f'{method} {path} HTTP/{http_version}')
response = await call_next(request)
return response
@app.post('/rtu_write') # 安全帽检测
async def rtu_write(request: Request) -> dict:
'''
写入寄存器
@params address --> 写入寄存器地址;
@params values --> 写入的数据;数组;
'''
params = await request.json() # 请求参数
logger.warning(f'参数:【{params}】')
address, values = [params.get(key) for key in params]
try:
modbus.instrument.write_registers(address, values)
logger.success(f'写入成功')
return {'code': 0, 'msg': 'success'}
except Exception as e:
logger.error(f'写入失败:【{e}】')
return {'code': 500, 'msg': f'{e}'}
@app.post('/rtu_read') # 安全帽检测
async def rtu_write(request: Request) -> dict:
'''
写入寄存器
@params address --> 写入寄存器地址;
@params start_address --> 开始的寄存器地址;
@params num_registers --> 从开始地址读的具体个数;
'''
params = await request.json() # 请求参数
logger.warning(f'参数:【{params}】')
address, start_address, num_registers = [params.get(key) for key in params]
try:
all_register_values = modbus.instrument.read_registers(start_address, num_registers)
# register_value = instrument.read_register(address) 读取单个寄存器的值
logger.success(f"成功读取从寄存器地址 {start_address} 开始的 {num_registers} 个寄存器的值: {all_register_values}")
return {'code': 0, 'msg': 'success', 'results': all_register_values}
except Exception as e:
logger.error(f'写入失败:【{e}】')
return {'code': 500, 'msg': f'{e}'}
if __name__ == '__main__':
uvicorn.run(app, host='0.0.0.0', port=modbus.websever_port, workers=1)
文档
RTU服务API文档与配置详解
config.ini参数解释
参数名 | 功能 |
---|---|
modbus | 寄存器相关 |
webserver | web框架提供的服务配置 |
参数名 | 功能 | 类型 |
---|---|---|
port | windows: COM1 、COM2 Linux: /dev/ttySx/ 或/dev/ttyUSBx 物理端口 | str |
address | 从站地址 | int |
baudrate | 波特率(默认:9600) | int |
bytesize | 数据位数。常见的数据位设置有 7 位或 8 位(默认:8) | int |
parity | 奇偶校验(可选:[‘E’, ‘O’, ‘N’]) 默认:N | str |
stopbits | 停止位;常见的停止位设置有 1 位或 2 位 | int |
timeout | 设置为 1 秒,意味着主站最多等待 1 秒 | int |
HTTP接口相关
给寄存器写数据
/rtu_write # 请求方法: POST
请求参数
参数名 | 功能 | 参数类型 |
---|---|---|
address | 写入的寄存器地址 | int |
values | 写入的值;示例[1,2,3,4,5,6,7,8,9] | 数组list |
返回值
参数名 | 功能 |
---|---|
code | 0(成功) 500(失败) |
msg | 当code等于0时固定返回’success’ 当code等于500时 返回具体错误信息 |
读数据
/rtu_read # 请求方法: POST
请求参数
参数名 | 功能 | 参数类型 |
---|---|---|
address | 读的寄存器地址 | int |
start_address | 需要读取开始地址 | int |
num_registers | 从开始地址向后读取的具体数量; start_address 给3 num_registers给3 则读3,4,5的值 | int |
调试工具(windows)
链接: https://pan.baidu.com/s/1oQ1khlS8Bo-VtYcwX7Wobw 提取码: 899k