更新了配置功能

This commit is contained in:
root 2026-05-18 17:05:23 +08:00
parent 622fff10fe
commit eaa89f597c
6 changed files with 535 additions and 125 deletions

View File

@ -1,6 +1,6 @@
from typing import Any, Dict, List
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, Query
from app.core.response import success_response
from app.core.security import verify_api_token
@ -32,8 +32,8 @@ def save_channel_config(payload: ChannelConfigIn) -> Dict[str, Any]:
@router.get("/line_alarm_setting", dependencies=[Depends(verify_api_token)])
def get_line_alarm_setting() -> Dict[str, Any]:
return success_response(platform_service.get_line_alarm_setting(), msg="获取线路报警设置成功")
def get_line_alarm_setting(line_no: int = Query(default=1, ge=1)) -> Dict[str, Any]:
return success_response(platform_service.get_line_alarm_setting(line_no=line_no), msg="获取线路报警设置成功")
@router.post("/line_alarm_setting", dependencies=[Depends(verify_api_token)])

View File

@ -93,21 +93,9 @@ class PlatformService:
data.update(current)
return data
def save_line_alarm_setting(self, payload: LineAlarmSettingIn) -> Dict[str, Any]:
current = self.config_repo.read_json("setting.json")
if not isinstance(current, dict):
current = {}
current["line_alarm_setting"] = payload.model_dump()
path = self.config_repo.write_setting_config(current)
device_result = self.device_client.send_line_alarm_setting(payload)
return {"save_path": f"/config/{path.name}", **device_result}
def get_line_alarm_setting(self) -> Dict[str, Any]:
current = self.config_repo.read_setting_section("line_alarm_setting")
if isinstance(current, dict):
return current
def _default_line_alarm_setting(self, line_no: int) -> Dict[str, Any]:
return {
"line_no": 1,
"line_no": line_no,
"over_limit_alarm": [
{"category": "电压", "limit": 180, "delay": 180, "output_node": "开出1", "enabled": True},
{"category": "电流", "limit": 180, "delay": 180, "output_node": "开出1", "enabled": True},
@ -117,6 +105,42 @@ class PlatformService:
"fault_alarm": [{"category": "PT断线", "delay": 180, "output_node": "开出1", "enabled": True}],
}
def _normalize_line_alarm_settings(self, raw: Any) -> List[Dict[str, Any]]:
if isinstance(raw, list):
return [item for item in raw if isinstance(item, dict)]
if isinstance(raw, dict):
return [raw]
return []
def save_line_alarm_setting(self, payload: LineAlarmSettingIn) -> Dict[str, Any]:
current = self.config_repo.read_json("setting.json")
if not isinstance(current, dict):
current = {}
line_alarm_list = self._normalize_line_alarm_settings(current.get("line_alarm_setting"))
payload_data = payload.model_dump()
updated = False
for index, item in enumerate(line_alarm_list):
if item.get("line_no") == payload.line_no:
line_alarm_list[index] = payload_data
updated = True
break
if not updated:
line_alarm_list.append(payload_data)
current["line_alarm_setting"] = line_alarm_list
path = self.config_repo.write_setting_config(current)
device_result = self.device_client.send_line_alarm_setting(payload)
return {"save_path": f"/config/{path.name}", **device_result}
def get_line_alarm_setting(self, line_no: int = 1) -> Dict[str, Any]:
current = self.config_repo.read_setting_section("line_alarm_setting")
line_alarm_list = self._normalize_line_alarm_settings(current)
for item in line_alarm_list:
if item.get("line_no") == line_no:
return item
return self._default_line_alarm_setting(line_no)
def save_ai_alarm_setting(self, payload: List[AiAlarmSettingIn]) -> Dict[str, Any]:
current = self.config_repo.read_json("setting.json")
if not isinstance(current, dict):

View File

@ -2,11 +2,99 @@
"ai_channel": [
{
"ch": 1,
"singal_type": "4-20mA22222",
"line_no": 1,
"singal_type": "1-5v",
"line_no": 2,
"type": "UA",
"limit_low": 0.0,
"limit_high": 20.0
},
{
"ch": 2,
"singal_type": "1~5V",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 3,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 4,
"singal_type": "1~5V",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 5,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 6,
"singal_type": "1~5V",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 7,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 8,
"singal_type": "1~5V",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 9,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 10,
"singal_type": "1~5V",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 11,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 12,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
}
],
"ao_channel": [
@ -15,8 +103,96 @@
"singal_type": "1-5v",
"line_no": 2,
"type": "UA",
"limit_low": 0.0,
"limit_low": 10.0,
"limit_high": 20.0
},
{
"ch": 2,
"singal_type": "1~5V",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 3,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 4,
"singal_type": "1~5V",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 5,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 6,
"singal_type": "1~5V",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 7,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 8,
"singal_type": "1~5V",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 9,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 10,
"singal_type": "1~5V",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 11,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
},
{
"ch": 12,
"singal_type": "4~20mA",
"line_no": 1,
"type": "UA",
"limit_low": 1.0,
"limit_high": 8.0
}
]
}

View File

@ -1,5 +1,7 @@
{
"line_alarm_setting": {
"line_alarm_setting":
[
{
"line_no": 1,
"over_limit_alarm": [
{
@ -19,7 +21,9 @@
"enabled": true
}
]
},
}
]
,
"ai_alarm_setting": [
{
"channel_no": 1,
@ -29,11 +33,110 @@
"delay": 180,
"output_node": "开出1",
"enabled": true
},
{
"channel_no": 2,
"singal_type": "1~5V",
"limit_low": 0.0,
"limit_high": 8.0,
"delay": 8,
"output_node": "",
"enabled": true
},
{
"channel_no": 3,
"singal_type": "4~20mA",
"limit_low": 0.0,
"limit_high": 8.0,
"delay": 8,
"output_node": "",
"enabled": false
},
{
"channel_no": 4,
"singal_type": "1~5V",
"limit_low": 0.0,
"limit_high": 8.0,
"delay": 8,
"output_node": "",
"enabled": false
},
{
"channel_no": 5,
"singal_type": "4~20mA",
"limit_low": 0.0,
"limit_high": 8.0,
"delay": 8,
"output_node": "",
"enabled": false
},
{
"channel_no": 6,
"singal_type": "1~5V",
"limit_low": 0.0,
"limit_high": 8.0,
"delay": 8,
"output_node": "",
"enabled": false
},
{
"channel_no": 7,
"singal_type": "4~20mA",
"limit_low": 0.0,
"limit_high": 8.0,
"delay": 8,
"output_node": "",
"enabled": false
},
{
"channel_no": 8,
"singal_type": "1~5V",
"limit_low": 0.0,
"limit_high": 8.0,
"delay": 8,
"output_node": "",
"enabled": false
},
{
"channel_no": 9,
"singal_type": "4~20mA",
"limit_low": 0.0,
"limit_high": 8.0,
"delay": 8,
"output_node": "",
"enabled": false
},
{
"channel_no": 10,
"singal_type": "1~5V",
"limit_low": 0.0,
"limit_high": 8.0,
"delay": 8,
"output_node": "",
"enabled": false
},
{
"channel_no": 11,
"singal_type": "4~20mA",
"limit_low": 0.0,
"limit_high": 8.0,
"delay": 8,
"output_node": "",
"enabled": false
},
{
"channel_no": 12,
"singal_type": "1~5V",
"limit_low": 0.0,
"limit_high": 8.0,
"delay": 8,
"output_node": "",
"enabled": false
}
],
"system_config": {
"time_sync": "manual",
"brightness": 83,
"screen_saver": 60
"screen_saver": 120
}
}

View File

@ -112,7 +112,10 @@ def test_config_query_endpoints(tmp_path) -> None:
)
platform_service.config_repo.write_setting_config(
{
"line_alarm_setting": {"line_no": 1, "over_limit_alarm": [{"category": "电压", "limit": 180, "delay": 180, "output_node": "开出1", "enabled": True}], "fault_alarm": []},
"line_alarm_setting": [
{"line_no": 1, "over_limit_alarm": [{"category": "电压", "limit": 180, "delay": 180, "output_node": "开出1", "enabled": True}], "fault_alarm": []},
{"line_no": 2, "over_limit_alarm": [{"category": "电流", "limit": 200, "delay": 120, "output_node": "开出2", "enabled": True}], "fault_alarm": []},
],
"ai_alarm_setting": [{"channel_no": 1, "singal_type": "4-20mA", "limit_low": 0, "limit_high": 20, "delay": 180, "output_node": "开出1", "enabled": True}],
"system_config": {"time_sync": "manual", "brightness": 83, "screen_saver": 60},
}
@ -122,7 +125,7 @@ def test_config_query_endpoints(tmp_path) -> None:
device_response = client.get("/api/config/device", headers=headers)
channel_response = client.get("/api/config/channel", headers=headers)
line_alarm_response = client.get("/api/config/line_alarm_setting", headers=headers)
line_alarm_response = client.get("/api/config/line_alarm_setting", headers=headers, params={"line_no": 2})
ai_alarm_response = client.get("/api/config/ai_alarm_setting", headers=headers)
system_response = client.get("/api/config/system", headers=headers)
@ -135,8 +138,34 @@ def test_config_query_endpoints(tmp_path) -> None:
assert device_response.json()["data"]["password"] == ""
assert device_response.json()["data"]["net"][0]["ip"] == "192.168.1.10"
assert channel_response.json()["data"]["ai_channel"][0]["singal_type"] == "4-20mA"
assert line_alarm_response.json()["data"]["line_no"] == 1
assert line_alarm_response.json()["data"]["line_no"] == 2
assert line_alarm_response.json()["data"]["over_limit_alarm"][0]["category"] == "电流"
assert ai_alarm_response.json()["data"][0]["channel_no"] == 1
assert system_response.json()["data"]["brightness"] == 83
finally:
platform_service.config_repo = old_repo
def test_save_line_alarm_setting_stores_list(tmp_path) -> None:
old_repo = platform_service.config_repo
platform_service.config_repo = JsonConfigRepository(tmp_path)
try:
headers = {"X-API-Token": settings.auth_password}
response = client.post(
"/api/config/line_alarm_setting",
headers=headers,
json={
"line_no": 3,
"over_limit_alarm": [{"category": "频率", "limit": 51.5, "delay": 30, "output_node": "开出1", "enabled": True}],
"fault_alarm": [{"category": "PT断线", "delay": 20, "output_node": "开出2", "enabled": False}],
},
)
assert response.status_code == 200
saved = platform_service.config_repo.read_setting_config()
assert isinstance(saved["line_alarm_setting"], list)
assert saved["line_alarm_setting"][0]["line_no"] == 3
finally:
platform_service.config_repo = old_repo

View File

@ -1,28 +1,38 @@
# 电气量测控平台系统需求分析与架构设计技术方案
**适配平台RK3568 嵌入式平台ubuntu 22.04系统)**
**技术栈FastAPI + HTTP + WebSocket + Python + Web前端**
## 一、文档概述
### 1.1 文档目的
本文档基于《电气量测控平台显示界面设计和数据接口说明》、`gui.h`头文件及项目功能描述,明确**RK3568嵌入式平台**上Python编写、Web界面展示的电气量测控配置软件的功能、性能、接口、数据存储需求完成系统架构设计为软件开发、测试及交付提供技术依据。
### 1.2 适用范围
本文档适用于**RK3568嵌入式硬件**以Python为开发语言、FastAPI为服务框架、Web为交互界面的电气量测控配置软件涵盖参数配置、实时数据交互、状态监测、报警管理等全流程功能设计。
### 1.3 参考资料
1. 《电气量测控平台显示界面设计和数据接口说明》
2. `gui.h`嵌入式程序头文件
3. 项目功能需求描述
## 二、系统需求分析
### 2.1 运行环境需求
- **硬件环境**RK3568嵌入式开发板支持Linux系统、文件系统、SQLite数据库
- **软件环境**Linux操作系统、Python 3.8、**FastAPI**、Uvicorn ASGI服务、SQLite数据库、JSON文件存储支持
- **交互环境**Web浏览器支持WebSocket、动态数据渲染、按钮交互、表格/波形展示)
### 2.2 功能需求
#### 2.2.1 参数配置管理功能
实现测控设备全维度参数配置,配置项支持**JSON文件本地存储**关键参数通过接口下发至C语言嵌入式程序具体配置项如下
1. **基础设备配置**
- 设备软件版本信息展示与配置
- 通讯参数设置:串口、网口参数配置
@ -39,49 +49,61 @@
- 已保存配置从本地JSON文件读取并通过HTTP查询接口返回给Web界面显示
#### 2.2.2 实时数据动态显示功能
1. **数据读取周期**:间隔**0.5秒**从C语言控制系统读取实时数据
2. **数据类型**模拟量、开关量、AI采集数据
3. **推送方式****WebSocket主动推送**至Web界面动态刷新展示
4. **存储规则**:动态数据仅内存缓存,**不保存到本地**
#### 2.2.3 设备状态实时监测功能
从嵌入式系统动态读取设备状态Web界面实时展示
- 装置自检状态(正常/异常)
- 网络1状态、网络2状态
- 串口1状态、串口2状态
#### 2.2.4 报警事件管理功能
1. **报警数据采集**:实时获取嵌入式设备报警事件
2. **数据存储**:报警事件保存至**SQLite数据库**
3. **展示方式****WebSocket实时推送**报警至Web界面支持弹窗提醒+历史查询
### 2.3 数据交互需求
#### 2.3.1 上行数据嵌入式系统→Python服务
- 实时数据0.5秒/次模拟量、开关量、AI采集数据
- 状态数据:装置自检、网络、串口状态
- 报警数据:实时报警事件数据
#### 2.3.2 下行数据Python服务→嵌入式系统
- 配置数据:设备参数、通道配置、定值、对时、灯光参数
- 控制指令:开关量分/合控制信号
### 2.4 数据存储需求
1. **JSON文件存储**设备版本、通讯参数、密码、AI/AO配置、定值配置等**非实时参数**
2. **SQLite数据库**:报警事件数据(支持历史查询)
3. **动态数据**:仅内存缓存,不持久化存储
### 2.5 性能需求
1. **数据刷新率**实时数据读取与WebSocket推送间隔≤0.5秒
2. **响应速度**参数配置下发、开关控制指令响应时间≤1秒
3. **稳定性**7×24小时连续运行
4. **兼容性**适配RK3568硬件兼容嵌入式C程序接口
### 2.6 通信服务需求
1. **HTTP服务**基于FastAPI提供**RESTful API**,用于参数配置、状态查询、报警查询、控制指令
2. **WebSocket服务**基于FastAPI提供双工通信用于**实时数据、报警数据主动推送**至Web界面
## 三、系统架构设计
### 3.1 总体架构
系统采用**分层架构 + 前后端分离**设计,从下到上分为:
**硬件层 → 嵌入式C程序层 → Python FastAPI服务层 → Web界面层**
@ -96,11 +118,14 @@ Python FastAPI服务层RESTful接口 + WebSocket推送 + 数据处理)
```
### 3.2 分层详细设计
#### 3.2.1 硬件层
- 核心硬件RK3568嵌入式开发板
- 外设模块AI/AO采集模块、开关量模块、网络/串口模块、显示屏
#### 3.2.2 嵌入式C程序层
- 数据采集模块20ms周期采集模拟量、开关量、AI数据
- 控制执行模块:接收参数与指令,执行配置、对时、灯光、开关控制
- 状态监测模块:自检、网口、串口状态实时上报
@ -108,7 +133,9 @@ Python FastAPI服务层RESTful接口 + WebSocket推送 + 数据处理)
- 通讯模块与Python服务双向数据交互
#### 3.2.3 Python FastAPI服务层核心
采用**FastAPI + Uvicorn**搭建,提供**HTTP接口**和**WebSocket推送**双服务:
1. **RESTful API模块**:处理配置提交、状态查询、报警查询、控制指令
2. **WebSocket推送模块**0.5秒推送实时数据、实时报警数据到Web端
3. **参数配置模块**JSON文件读写、配置下发C程序
@ -117,12 +144,14 @@ Python FastAPI服务层RESTful接口 + WebSocket推送 + 数据处理)
6. **设备状态模块**:采集并缓存设备运行状态
#### 3.2.4 Web界面层
- 菜单区:配置、状态、数据、报警、控制入口
- 状态区:自检、网络、串口实时状态
- 主显示区:实时数据表格、配置表单、控制按钮、报警列表
- 报警区WebSocket实时弹窗+滚动显示
### 3.3 数据流向设计
1. **实时/报警数据流向**
嵌入式C程序 → Python → WebSocket主动推送 → Web界面0.5秒刷新)
2. **参数配置流向**
@ -133,8 +162,11 @@ Web界面 → HTTP GET → Python → 返回数据展示
Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配置 → 返回当前配置数据 → Web界面显示
## 四、接口详细设计RESTful + WebSocket
### 4.1 RESTful API 接口详情(完整参数+返回值)
所有接口统一返回格式:
```json
{
"code": 200, // 200=成功400=参数错误500=服务异常
@ -143,9 +175,10 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
}
```
---
***
#### 1. GET /api/real-time-data
**作用**获取最新一次实时数据备用主用WebSocket
**参数**:无
**返回data**
@ -275,12 +308,14 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
}
```
---
***
#### 2. GET /api/device-status
**作用**:获取设备当前运行状态
**参数**:无
**返回data**
```json
{
"self_check": "正常",
@ -291,12 +326,14 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
}
```
---
***
#### 3. GET /api/config/device
**作用**:读取设备基础配置,用于设备/网络配置界面打开时回显当前参数
**参数**:无
**返回data**
```json
{
"password": "",
@ -332,11 +369,13 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
}
```
---
***
#### 4. POST /api/config/device
**作用**:提交设备基础配置(版本、通讯、密码)
**请求body参数**
```json
{
"password": "123456",
@ -386,14 +425,17 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
]
}
```
**返回data**`{"save_path":"/config/device.json","send_status":"成功"}`
---
***
#### 5. GET /api/config/channel
**作用**:读取通道配置,用于通道配置界面打开时回显当前参数
**参数**:无
**返回data**
```json
{
"ai_channel": [{"ch":1,"singal_type":"4-20mA","line_no":1,"type":"UA","limit_low":0,"limit_high":20}],
@ -401,9 +443,10 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
}
```
---
***
#### 6. POST /api/config/channel
**作用**提交AI/AO通道配置(AI12通道AO12通道)
**请求body参数**
@ -413,14 +456,18 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
"ao_channel": [{"ch":1,"singal_type":"1-5v","line_no":2,"type":"UA","limit_low":0,"limit_high":20}]
}
```
**返回data**`{"save_path":"/config/channel.json","send_status":"成功"}`
---
***
#### 7. GET /api/config/line\_alarm\_setting
#### 7. GET /api/config/line_alarm_setting
**作用**:读取线路报警设置,用于报警设置界面打开时回显当前线路参数
**参数**:无
**参数**
- `line_no=1`:按线路号读取对应线路的报警设置
**返回data**
```json
{
"line_no": 1,
@ -444,15 +491,16 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
}
```
---
***
#### 8. POST /api/config/line\_alarm\_setting
#### 8. POST /api/config/line_alarm_setting
**作用**:提交定值报警阈值配置
**请求body参数**
```json
[
{"line_no": 1,
{
"line_no": 1,
"over_limit_alarm": [
{
"category": "电压",
@ -505,16 +553,23 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
}
]
}
]
```
**返回data**`{"save_path":"/config/setting.json","send_status":"成功"}`
---
说明:
- `setting.json` 中的 `line_alarm_setting` 按数组对象存储
- 保存接口按单条线路配置提交
- 服务端会根据 `line_no` 对数组中的对应线路进行覆盖更新,不存在时追加
***
#### 9. GET /api/config/ai\_alarm\_setting
#### 9. GET /api/config/ai_alarm_setting
**作用**读取AI报警设置用于报警设置界面打开时回显当前AI报警参数
**参数**:无
**返回data**
```json
[
{
@ -529,9 +584,9 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
]
```
---
***
#### 10. POST /api/config/ai_alarm_setting
#### 10. POST /api/config/ai\_alarm\_setting
**作用**提交AI报警设置
**请求body参数**
@ -562,9 +617,11 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
**返回data**`{"save_path":"/config/setting.json","send_status":"成功"}`
#### 11. GET /api/config/system
**作用**:读取系统设置,用于系统设置界面打开时回显当前参数
**参数**:无
**返回data**
```json
{
"time_sync": "auto",
@ -573,12 +630,13 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
}
```
---
***
#### 12. POST /api/config/system
**作用**:提交系统对时、灯光配置
**请求body参数**
```json
{
"time_sync": "auto",
@ -586,13 +644,16 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
"screen_saver": 60
}
```
**返回data**`{"send_status":"成功"}`
---
***
#### 13. GET /api/alarm/list
**作用**:分页查询历史报警
**参数**
- `page=1`:页码,从 `1` 开始
- `size=20`:每页条数,最大 `100`
- `no=L1`:按线路号/通道号精确筛选
@ -601,16 +662,19 @@ Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配
- `end_time=2026-05-16T11:30:00`:按报警结束时间筛选
**示例请求**
```text
GET /api/alarm/list?page=1&size=20&no=L1&type=current&start_time=2026-05-16T10:30:00&end_time=2026-05-16T11:30:00
```
说明:
- 所有筛选条件均为可选
- 未传筛选条件时,默认按分页查询全部历史报警
- `start_time``end_time` 使用日期时间格式
**返回data**
```json
[
{
@ -625,21 +689,27 @@ GET /api/alarm/list?page=1&size=20&no=L1&type=current&start_time=2026-05-16T10:3
]
```
---
***
#### 14. POST /api/control/switch
**作用**:下发开关量控制指令
**请求body参数**
```json
{"ch":1,"action":1} // 1=合0=分
```
**返回data**`{"control_status":"执行成功"}`
---
***
### 4.2 WebSocket 接口(主动推送)
#### 1. WebSocket 地址:`ws://ip:port/ws/real-time`
**推送内容**实时数据0.5秒/次)
```json
{
"type": "real_time",
@ -765,7 +835,9 @@ GET /api/alarm/list?page=1&size=20&no=L1&type=current&start_time=2026-05-16T10:3
```
#### 2. WebSocket 地址:`ws://ip:port/ws/alarm`
**推送内容**:实时报警事件(触发即推)
```json
{
"alarm_type": "line_alarm",
@ -794,16 +866,20 @@ GET /api/alarm/list?page=1&size=20&no=L1&type=current&start_time=2026-05-16T10:3
```
## 五、数据存储设计
### 5.1 JSON配置文件
- 路径:`/config/`
- 文件:`device.json`、`channel.json`、`setting.json`
### 5.2 SQLite报警数据库
表:`alarm_event`
| 字段 | 类型 | 说明 |
|------|------|------|
| ----------- | -------- | ------------------------------------------ |
| id | INTEGER | 主键 |
| alarm_type | TEXT | 告警类型line_alarm,ai_alarm,operate_alarm |
| alarm\_type | TEXT | 告警类型line\_alarm,ai\_alarm,operate\_alarm |
| time | DATETIME | 事件发生时间 |
| no | TEXT | 线路号/通道号 |
| type | TEXT | 类型 |
@ -811,13 +887,16 @@ GET /api/alarm/list?page=1&size=20&no=L1&type=current&start_time=2026-05-16T10:3
| level | TEXT | 告警等级 |
## 六、安全与可靠性设计
1. **密码加密存储**,接口权限校验
2. WebSocket断线自动重连
3. 配置文件修改自动备份
4. 服务异常自动重启
## 七、总结
本方案基于**RK3568平台**,采用**FastAPI + HTTP + WebSocket**架构,满足电气量测控平台全部需求:
- RESTful API 负责配置、查询、控制
- WebSocket 负责实时数据、报警数据主动推送
- JSON 存储配置SQLite 存储报警
@ -825,5 +904,4 @@ GET /api/alarm/list?page=1&size=20&no=L1&type=current&start_time=2026-05-16T10:3
系统架构轻量化、高性能,完全适配嵌入式平台运行。
---
***