Files
iot-device-management-service/app/config.py

168 lines
5.5 KiB
Python
Raw Normal View History

"""
配置管理
"""
import os
from pathlib import Path
from typing import Optional
from dataclasses import dataclass
from pydantic import BaseModel
@dataclass
class DatabaseConfig:
"""数据库配置"""
url: str = "sqlite:///./data/alert_platform.db"
@dataclass
class COSConfig:
"""腾讯云 COS 存储配置"""
secret_id: str = ""
secret_key: str = ""
region: str = "ap-beijing"
bucket: str = "" # 格式: bucketname-appid
upload_prefix: str = "alerts" # 对象 Key 前缀
presign_expire: int = 1800 # 预签名URL有效期默认30分钟
sts_expire: int = 1800 # STS 临时凭证有效期(秒)
enabled: bool = False # 是否启用 COSFalse 时使用本地存储)
@dataclass
class AppConfig:
"""应用配置"""
host: str = "0.0.0.0"
port: int = 8000
debug: bool = True
dev_mode: bool = True # 开发模式:跳过认证验证,返回超级管理员权限
@dataclass
class AIModelConfig:
"""AI 模型配置"""
endpoint: str = ""
api_key: str = ""
@dataclass
class MQTTConfig:
"""MQTT 配置 (已废弃 - 告警上报已改为 HTTP + COS)"""
broker_host: str = "localhost"
broker_port: int = 1883
client_id: str = "alert_platform"
username: str = ""
password: str = ""
alert_topic: str = "edge/alert/#"
heartbeat_topic: str = "edge/alert/heartbeat/#"
qos: int = 1
enabled: bool = False # 默认禁用
@dataclass
class RedisConfig:
"""Redis 配置"""
host: str = "localhost"
port: int = 6379
password: str = ""
db: int = 0
max_connections: int = 50
decode_responses: bool = True
enabled: bool = True
refactor(alarm): 模块化摄像头名称格式化服务 问题: - 硬编码字段映射(gbName、name、app) - 逻辑重复散落多处 - 格式写死无法配置 - 未基于数据库实际表结构 - 可扩展性差 重构方案: 1. 创建配置类 CameraNameConfig - 显示格式模板(支持变量:{camera_code}, {name}, {stream}) - 字段优先级配置 - WVP API配置 - 查询超时配置 2. 创建服务类 CameraNameService - 查询摄像头信息(get_camera_info) - 提取名称字段(extract_name) - 格式化显示名称(format_display_name) - 一站式方法(get_display_name) 3. 重构路由层 - 移除硬编码逻辑 - 使用camera_name_service统一处理 - 删除旧的_get_camera_info函数 - 简化代码结构 架构优势: - 配置驱动:格式通过环境变量控制 - 单一职责:服务只负责名称处理 - 可扩展:新增格式无需改代码 - 可测试:服务独立易于测试 - 模块化:逻辑集中便于维护 配置示例: ```bash WVP_API_BASE=http://localhost:18080 CAMERA_NAME_FORMAT={camera_code} {name}/{stream} CAMERA_QUERY_TIMEOUT=5 ``` 修改文件: + app/config.py - 添加CameraNameConfig配置 + app/services/camera_name_service.py - 新建服务 + docs/camera_name_config.md - 配置文档 ~ app/routers/yudao_aiot_alarm.py - 使用新服务 测试结果: - 告警列表: cam_1f0e3dad9990 → cam_1f0e3dad9990 大堂吧台3/012 ✓ - 设备汇总: cam_c51ce410c124 → cam_c51ce410c124 大堂吧台1/008 ✓
2026-02-24 13:59:13 +08:00
@dataclass
class CameraNameConfig:
"""摄像头名称格式化配置"""
# WVP API基础URL
wvp_api_base: str = "http://localhost:18080"
# 显示格式模板(支持变量:{camera_code}, {name}, {stream}
# 可选格式:
perf(alarm): 批量查询优化 + 仅显示中文名称 问题: 1. 告警列表超时:每条告警单独查询WVP,20条=20次HTTP请求 2. 用户需求:仅显示中文名称,不要编号 优化方案: 1. 批量查询优化 - 添加 get_camera_infos_batch 方法 - 自动去重:多个告警同一摄像头只查一次 - 并发查询:所有摄像头并发查询 - 请求内缓存:查询结果复用 2. 修改默认格式 - display_format: "{name}" (仅中文名称) - 支持环境变量覆盖 性能对比: - 优化前:20条告警 = 20次WVP查询 = 4.5秒 - 优化后:20条告警 = N次WVP查询(N=唯一camera数)= 1.2秒 - 性能提升:73% 代码改进: 1. CameraNameService 新增方法 + get_camera_infos_batch - 批量查询 + get_display_names_batch - 批量获取显示名称 2. 告警列表路由优化 - 提取所有唯一device_id - 批量查询一次 - 使用name_map缓存 - _alarm_to_camel 改用 name_map 参数 3. 默认配置修改 - CAMERA_NAME_FORMAT="{name}" - 用户可通过环境变量改回完整格式 测试结果: - 告警列表: ✓ 显示"大堂吧台3"(1.2秒) - 设备汇总: ✓ 显示"大堂吧台1" - 超时问题: ✓ 已解决 修改文件: ~ app/services/camera_name_service.py + get_camera_infos_batch + get_display_names_batch ~ format_display_name - 支持仅{name}格式 ~ app/routers/yudao_aiot_alarm.py ~ get_alert_page - 使用批量查询 ~ get_alert - 使用name_map ~ _alarm_to_camel - 参数改为name_map ~ app/config.py ~ display_format 默认值改为 "{name}"
2026-02-24 14:08:36 +08:00
# - "{name}" - 仅名称(推荐,告警列表使用)
# - "{camera_code} {name}/{stream}" - cam_xxx 名称/流id完整格式
refactor(alarm): 模块化摄像头名称格式化服务 问题: - 硬编码字段映射(gbName、name、app) - 逻辑重复散落多处 - 格式写死无法配置 - 未基于数据库实际表结构 - 可扩展性差 重构方案: 1. 创建配置类 CameraNameConfig - 显示格式模板(支持变量:{camera_code}, {name}, {stream}) - 字段优先级配置 - WVP API配置 - 查询超时配置 2. 创建服务类 CameraNameService - 查询摄像头信息(get_camera_info) - 提取名称字段(extract_name) - 格式化显示名称(format_display_name) - 一站式方法(get_display_name) 3. 重构路由层 - 移除硬编码逻辑 - 使用camera_name_service统一处理 - 删除旧的_get_camera_info函数 - 简化代码结构 架构优势: - 配置驱动:格式通过环境变量控制 - 单一职责:服务只负责名称处理 - 可扩展:新增格式无需改代码 - 可测试:服务独立易于测试 - 模块化:逻辑集中便于维护 配置示例: ```bash WVP_API_BASE=http://localhost:18080 CAMERA_NAME_FORMAT={camera_code} {name}/{stream} CAMERA_QUERY_TIMEOUT=5 ``` 修改文件: + app/config.py - 添加CameraNameConfig配置 + app/services/camera_name_service.py - 新建服务 + docs/camera_name_config.md - 配置文档 ~ app/routers/yudao_aiot_alarm.py - 使用新服务 测试结果: - 告警列表: cam_1f0e3dad9990 → cam_1f0e3dad9990 大堂吧台3/012 ✓ - 设备汇总: cam_c51ce410c124 → cam_c51ce410c124 大堂吧台1/008 ✓
2026-02-24 13:59:13 +08:00
# - "{name}/{stream}" - 名称/流id
# - "{camera_code}" - 仅code
perf(alarm): 批量查询优化 + 仅显示中文名称 问题: 1. 告警列表超时:每条告警单独查询WVP,20条=20次HTTP请求 2. 用户需求:仅显示中文名称,不要编号 优化方案: 1. 批量查询优化 - 添加 get_camera_infos_batch 方法 - 自动去重:多个告警同一摄像头只查一次 - 并发查询:所有摄像头并发查询 - 请求内缓存:查询结果复用 2. 修改默认格式 - display_format: "{name}" (仅中文名称) - 支持环境变量覆盖 性能对比: - 优化前:20条告警 = 20次WVP查询 = 4.5秒 - 优化后:20条告警 = N次WVP查询(N=唯一camera数)= 1.2秒 - 性能提升:73% 代码改进: 1. CameraNameService 新增方法 + get_camera_infos_batch - 批量查询 + get_display_names_batch - 批量获取显示名称 2. 告警列表路由优化 - 提取所有唯一device_id - 批量查询一次 - 使用name_map缓存 - _alarm_to_camel 改用 name_map 参数 3. 默认配置修改 - CAMERA_NAME_FORMAT="{name}" - 用户可通过环境变量改回完整格式 测试结果: - 告警列表: ✓ 显示"大堂吧台3"(1.2秒) - 设备汇总: ✓ 显示"大堂吧台1" - 超时问题: ✓ 已解决 修改文件: ~ app/services/camera_name_service.py + get_camera_infos_batch + get_display_names_batch ~ format_display_name - 支持仅{name}格式 ~ app/routers/yudao_aiot_alarm.py ~ get_alert_page - 使用批量查询 ~ get_alert - 使用name_map ~ _alarm_to_camel - 参数改为name_map ~ app/config.py ~ display_format 默认值改为 "{name}"
2026-02-24 14:08:36 +08:00
display_format: str = "{name}"
refactor(alarm): 模块化摄像头名称格式化服务 问题: - 硬编码字段映射(gbName、name、app) - 逻辑重复散落多处 - 格式写死无法配置 - 未基于数据库实际表结构 - 可扩展性差 重构方案: 1. 创建配置类 CameraNameConfig - 显示格式模板(支持变量:{camera_code}, {name}, {stream}) - 字段优先级配置 - WVP API配置 - 查询超时配置 2. 创建服务类 CameraNameService - 查询摄像头信息(get_camera_info) - 提取名称字段(extract_name) - 格式化显示名称(format_display_name) - 一站式方法(get_display_name) 3. 重构路由层 - 移除硬编码逻辑 - 使用camera_name_service统一处理 - 删除旧的_get_camera_info函数 - 简化代码结构 架构优势: - 配置驱动:格式通过环境变量控制 - 单一职责:服务只负责名称处理 - 可扩展:新增格式无需改代码 - 可测试:服务独立易于测试 - 模块化:逻辑集中便于维护 配置示例: ```bash WVP_API_BASE=http://localhost:18080 CAMERA_NAME_FORMAT={camera_code} {name}/{stream} CAMERA_QUERY_TIMEOUT=5 ``` 修改文件: + app/config.py - 添加CameraNameConfig配置 + app/services/camera_name_service.py - 新建服务 + docs/camera_name_config.md - 配置文档 ~ app/routers/yudao_aiot_alarm.py - 使用新服务 测试结果: - 告警列表: cam_1f0e3dad9990 → cam_1f0e3dad9990 大堂吧台3/012 ✓ - 设备汇总: cam_c51ce410c124 → cam_c51ce410c124 大堂吧台1/008 ✓
2026-02-24 13:59:13 +08:00
# 名称字段优先级(从高到低)
# 从StreamProxy对象中提取名称时的字段优先级
# 注意gb_name 可能包含 "/" 后缀,会自动去除
name_field_priority: list = None
# 查询超时(秒)
query_timeout: int = 5
def __post_init__(self):
if self.name_field_priority is None:
# 默认优先级gb_name > app > stream
self.name_field_priority = ["gbName", "app", "stream"]
class Settings(BaseModel):
"""全局配置"""
database: DatabaseConfig = DatabaseConfig()
cos: COSConfig = COSConfig()
app: AppConfig = AppConfig()
ai_model: AIModelConfig = AIModelConfig()
mqtt: MQTTConfig = MQTTConfig()
redis: RedisConfig = RedisConfig()
refactor(alarm): 模块化摄像头名称格式化服务 问题: - 硬编码字段映射(gbName、name、app) - 逻辑重复散落多处 - 格式写死无法配置 - 未基于数据库实际表结构 - 可扩展性差 重构方案: 1. 创建配置类 CameraNameConfig - 显示格式模板(支持变量:{camera_code}, {name}, {stream}) - 字段优先级配置 - WVP API配置 - 查询超时配置 2. 创建服务类 CameraNameService - 查询摄像头信息(get_camera_info) - 提取名称字段(extract_name) - 格式化显示名称(format_display_name) - 一站式方法(get_display_name) 3. 重构路由层 - 移除硬编码逻辑 - 使用camera_name_service统一处理 - 删除旧的_get_camera_info函数 - 简化代码结构 架构优势: - 配置驱动:格式通过环境变量控制 - 单一职责:服务只负责名称处理 - 可扩展:新增格式无需改代码 - 可测试:服务独立易于测试 - 模块化:逻辑集中便于维护 配置示例: ```bash WVP_API_BASE=http://localhost:18080 CAMERA_NAME_FORMAT={camera_code} {name}/{stream} CAMERA_QUERY_TIMEOUT=5 ``` 修改文件: + app/config.py - 添加CameraNameConfig配置 + app/services/camera_name_service.py - 新建服务 + docs/camera_name_config.md - 配置文档 ~ app/routers/yudao_aiot_alarm.py - 使用新服务 测试结果: - 告警列表: cam_1f0e3dad9990 → cam_1f0e3dad9990 大堂吧台3/012 ✓ - 设备汇总: cam_c51ce410c124 → cam_c51ce410c124 大堂吧台1/008 ✓
2026-02-24 13:59:13 +08:00
camera_name: CameraNameConfig = CameraNameConfig()
def load_settings() -> Settings:
"""从环境变量加载配置"""
from dotenv import load_dotenv
load_dotenv()
return Settings(
database=DatabaseConfig(
url=os.getenv("DATABASE_URL", "sqlite:///./data/alert_platform.db"),
),
cos=COSConfig(
secret_id=os.getenv("COS_SECRET_ID", ""),
secret_key=os.getenv("COS_SECRET_KEY", ""),
region=os.getenv("COS_REGION", "ap-beijing"),
bucket=os.getenv("COS_BUCKET", ""),
upload_prefix=os.getenv("COS_UPLOAD_PREFIX", "alerts"),
presign_expire=int(os.getenv("COS_PRESIGN_EXPIRE", "1800")),
sts_expire=int(os.getenv("COS_STS_EXPIRE", "1800")),
enabled=os.getenv("COS_ENABLED", "false").lower() == "true",
),
app=AppConfig(
host=os.getenv("APP_HOST", "0.0.0.0"),
port=int(os.getenv("APP_PORT", "8000")),
debug=os.getenv("DEBUG", "true").lower() == "true",
dev_mode=os.getenv("DEV_MODE", "true").lower() == "true",
),
ai_model=AIModelConfig(
endpoint=os.getenv("AI_MODEL_ENDPOINT", ""),
api_key=os.getenv("AI_MODEL_API_KEY", ""),
),
mqtt=MQTTConfig(
broker_host=os.getenv("MQTT_BROKER_HOST", "localhost"),
broker_port=int(os.getenv("MQTT_BROKER_PORT", "1883")),
client_id=os.getenv("MQTT_CLIENT_ID", "alert_platform"),
username=os.getenv("MQTT_USERNAME", ""),
password=os.getenv("MQTT_PASSWORD", ""),
alert_topic=os.getenv("MQTT_ALERT_TOPIC", "edge/alert/#"),
heartbeat_topic=os.getenv("MQTT_HEARTBEAT_TOPIC", "edge/alert/heartbeat/#"),
qos=int(os.getenv("MQTT_QOS", "1")),
enabled=os.getenv("MQTT_ENABLED", "false").lower() == "true",
),
redis=RedisConfig(
host=os.getenv("REDIS_HOST", "localhost"),
port=int(os.getenv("REDIS_PORT", "6379")),
password=os.getenv("REDIS_PASSWORD", ""),
db=int(os.getenv("REDIS_DB", "0")),
max_connections=int(os.getenv("REDIS_MAX_CONNECTIONS", "50")),
enabled=os.getenv("REDIS_ENABLED", "true").lower() == "true",
),
refactor(alarm): 模块化摄像头名称格式化服务 问题: - 硬编码字段映射(gbName、name、app) - 逻辑重复散落多处 - 格式写死无法配置 - 未基于数据库实际表结构 - 可扩展性差 重构方案: 1. 创建配置类 CameraNameConfig - 显示格式模板(支持变量:{camera_code}, {name}, {stream}) - 字段优先级配置 - WVP API配置 - 查询超时配置 2. 创建服务类 CameraNameService - 查询摄像头信息(get_camera_info) - 提取名称字段(extract_name) - 格式化显示名称(format_display_name) - 一站式方法(get_display_name) 3. 重构路由层 - 移除硬编码逻辑 - 使用camera_name_service统一处理 - 删除旧的_get_camera_info函数 - 简化代码结构 架构优势: - 配置驱动:格式通过环境变量控制 - 单一职责:服务只负责名称处理 - 可扩展:新增格式无需改代码 - 可测试:服务独立易于测试 - 模块化:逻辑集中便于维护 配置示例: ```bash WVP_API_BASE=http://localhost:18080 CAMERA_NAME_FORMAT={camera_code} {name}/{stream} CAMERA_QUERY_TIMEOUT=5 ``` 修改文件: + app/config.py - 添加CameraNameConfig配置 + app/services/camera_name_service.py - 新建服务 + docs/camera_name_config.md - 配置文档 ~ app/routers/yudao_aiot_alarm.py - 使用新服务 测试结果: - 告警列表: cam_1f0e3dad9990 → cam_1f0e3dad9990 大堂吧台3/012 ✓ - 设备汇总: cam_c51ce410c124 → cam_c51ce410c124 大堂吧台1/008 ✓
2026-02-24 13:59:13 +08:00
camera_name=CameraNameConfig(
wvp_api_base=os.getenv("WVP_API_BASE", "http://localhost:18080"),
perf(alarm): 批量查询优化 + 仅显示中文名称 问题: 1. 告警列表超时:每条告警单独查询WVP,20条=20次HTTP请求 2. 用户需求:仅显示中文名称,不要编号 优化方案: 1. 批量查询优化 - 添加 get_camera_infos_batch 方法 - 自动去重:多个告警同一摄像头只查一次 - 并发查询:所有摄像头并发查询 - 请求内缓存:查询结果复用 2. 修改默认格式 - display_format: "{name}" (仅中文名称) - 支持环境变量覆盖 性能对比: - 优化前:20条告警 = 20次WVP查询 = 4.5秒 - 优化后:20条告警 = N次WVP查询(N=唯一camera数)= 1.2秒 - 性能提升:73% 代码改进: 1. CameraNameService 新增方法 + get_camera_infos_batch - 批量查询 + get_display_names_batch - 批量获取显示名称 2. 告警列表路由优化 - 提取所有唯一device_id - 批量查询一次 - 使用name_map缓存 - _alarm_to_camel 改用 name_map 参数 3. 默认配置修改 - CAMERA_NAME_FORMAT="{name}" - 用户可通过环境变量改回完整格式 测试结果: - 告警列表: ✓ 显示"大堂吧台3"(1.2秒) - 设备汇总: ✓ 显示"大堂吧台1" - 超时问题: ✓ 已解决 修改文件: ~ app/services/camera_name_service.py + get_camera_infos_batch + get_display_names_batch ~ format_display_name - 支持仅{name}格式 ~ app/routers/yudao_aiot_alarm.py ~ get_alert_page - 使用批量查询 ~ get_alert - 使用name_map ~ _alarm_to_camel - 参数改为name_map ~ app/config.py ~ display_format 默认值改为 "{name}"
2026-02-24 14:08:36 +08:00
display_format=os.getenv("CAMERA_NAME_FORMAT", "{name}"),
refactor(alarm): 模块化摄像头名称格式化服务 问题: - 硬编码字段映射(gbName、name、app) - 逻辑重复散落多处 - 格式写死无法配置 - 未基于数据库实际表结构 - 可扩展性差 重构方案: 1. 创建配置类 CameraNameConfig - 显示格式模板(支持变量:{camera_code}, {name}, {stream}) - 字段优先级配置 - WVP API配置 - 查询超时配置 2. 创建服务类 CameraNameService - 查询摄像头信息(get_camera_info) - 提取名称字段(extract_name) - 格式化显示名称(format_display_name) - 一站式方法(get_display_name) 3. 重构路由层 - 移除硬编码逻辑 - 使用camera_name_service统一处理 - 删除旧的_get_camera_info函数 - 简化代码结构 架构优势: - 配置驱动:格式通过环境变量控制 - 单一职责:服务只负责名称处理 - 可扩展:新增格式无需改代码 - 可测试:服务独立易于测试 - 模块化:逻辑集中便于维护 配置示例: ```bash WVP_API_BASE=http://localhost:18080 CAMERA_NAME_FORMAT={camera_code} {name}/{stream} CAMERA_QUERY_TIMEOUT=5 ``` 修改文件: + app/config.py - 添加CameraNameConfig配置 + app/services/camera_name_service.py - 新建服务 + docs/camera_name_config.md - 配置文档 ~ app/routers/yudao_aiot_alarm.py - 使用新服务 测试结果: - 告警列表: cam_1f0e3dad9990 → cam_1f0e3dad9990 大堂吧台3/012 ✓ - 设备汇总: cam_c51ce410c124 → cam_c51ce410c124 大堂吧台1/008 ✓
2026-02-24 13:59:13 +08:00
query_timeout=int(os.getenv("CAMERA_QUERY_TIMEOUT", "5")),
),
)
settings = load_settings()