Files
iot-device-management-service/docs/camera_name_config.md
16337 6996423f7d 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

7.6 KiB
Raw Permalink Blame History

摄像头名称格式化配置

概述

摄像头名称格式化服务提供了灵活、可配置的方式来格式化摄像头显示名称。所有配置通过环境变量控制,无需修改代码即可调整显示格式。

架构设计

┌─────────────────────────────────────────────────────┐
│  config.py (CameraNameConfig)                       │
│  - 显示格式模板                                       │
│  - 字段优先级                                         │
│  - WVP API配置                                       │
└────────────────┬────────────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────────────────┐
│  camera_name_service.py (CameraNameService)         │
│  - 查询摄像头信息                                     │
│  - 提取名称字段                                       │
│  - 格式化显示名称                                     │
└────────────────┬────────────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────────────────┐
│  yudao_aiot_alarm.py (路由层)                        │
│  - 告警列表                                           │
│  - 设备汇总                                           │
└─────────────────────────────────────────────────────┘

配置参数

环境变量

变量名 说明 默认值 示例
WVP_API_BASE WVP API基础URL http://localhost:18080 http://192.168.1.100:18080
CAMERA_NAME_FORMAT 显示格式模板 {camera_code} {name}/{stream} {name}
CAMERA_QUERY_TIMEOUT 查询超时(秒) 5 10

显示格式模板

支持以下变量:

变量 说明 示例值
{camera_code} 摄像头编码 cam_1f0e3dad9990
{name} 摄像头名称(根据字段优先级提取) 大堂吧台3
{stream} 流ID 012

常用格式示例

  1. 完整格式(默认):

    CAMERA_NAME_FORMAT="{camera_code} {name}/{stream}"
    结果cam_1f0e3dad9990 大堂吧台3/012
    
  2. 仅名称+流ID

    CAMERA_NAME_FORMAT="{name}/{stream}"
    结果大堂吧台3/012
    
  3. 仅名称

    CAMERA_NAME_FORMAT="{name}"
    结果大堂吧台3
    
  4. 仅编码

    CAMERA_NAME_FORMAT="{camera_code}"
    结果cam_1f0e3dad9990
    
  5. 自定义分隔符

    CAMERA_NAME_FORMAT="{name} - {stream}"
    结果大堂吧台3 - 012
    

名称字段优先级

服务会按以下优先级从 StreamProxy 对象中提取名称:

  1. gbName(国标名称)- 自动去除 "/" 后缀
  2. app(应用名)
  3. stream流ID

此优先级在代码中硬编码,如需修改请编辑 app/services/camera_name_service.py

self.name_field_priority = ["gbName", "app", "stream"]

使用方式

1. 在环境变量中配置

.env 文件:

WVP_API_BASE=http://192.168.0.104:18080
CAMERA_NAME_FORMAT={camera_code} {name}/{stream}
CAMERA_QUERY_TIMEOUT=5

2. 服务自动加载配置

from app.services.camera_name_service import get_camera_name_service

camera_service = get_camera_name_service()
display_name = await camera_service.get_display_name("cam_1f0e3dad9990")
# 返回: "cam_1f0e3dad9990 大堂吧台3/012"

3. 修改格式只需重启服务

# 修改环境变量
export CAMERA_NAME_FORMAT="{name}"

# 重启服务
systemctl restart service

API 示例

查询摄像头信息

camera_info = await camera_service.get_camera_info("cam_1f0e3dad9990")
# 返回: {
#     "cameraCode": "cam_1f0e3dad9990",
#     "app": "大堂吧台3",
#     "stream": "012",
#     "gbName": "大堂吧台3/",
#     ...
# }

提取名称

name = camera_service.extract_name(camera_info)
# 返回: "大堂吧台3" (从 gbName 提取并去除 "/")

格式化显示名称

display_name = camera_service.format_display_name("cam_xxx", camera_info)
# 根据模板返回格式化结果

一站式查询

display_name = await camera_service.get_display_name("cam_1f0e3dad9990")
# 自动查询 + 格式化

扩展性

添加新的显示格式

只需修改环境变量即可:

# 添加前缀
CAMERA_NAME_FORMAT="[摄像头] {name}"

# 添加位置信息(需要在 WVP 中配置 gbAddress
CAMERA_NAME_FORMAT="{name} ({gbAddress})"

如需使用新字段,需要修改 camera_name_service.py 中的 format_display_name 方法。

支持多种 device_id 格式

当前支持:

  • cam_xxxxxxxxxxxx(推荐)
  • app/stream(遗留格式,日志会警告)

如需支持其他格式,修改 get_camera_info 方法。

缓存支持

如需添加缓存以减少 WVP 查询:

from functools import lru_cache

@lru_cache(maxsize=1000)
async def get_camera_info_cached(self, device_id: str):
    return await self.get_camera_info(device_id)

或使用 Redis 缓存(需集成 Redis 服务)。

故障排查

1. 显示名称为 device_id未格式化

可能原因

  • WVP API 无法访问
  • camera_code 不存在
  • 摄像头信息字段缺失

检查方法

# 测试 WVP API
curl "http://localhost:18080/api/ai/camera/get?cameraCode=cam_xxx"

# 查看服务日志
tail -f logs/app.log | grep "camera"

2. 格式化模板错误

错误示例

KeyError: 'invalid_field'

解决方法 检查模板中的变量名是否正确(只支持 {camera_code}, {name}, {stream}

3. 查询超时

错误日志

WVP查询异常: camera_code=cam_xxx, error=Timeout

解决方法 增加超时时间:

CAMERA_QUERY_TIMEOUT=10

最佳实践

  1. 使用 camera_code 格式:推荐在数据库中存储 camera_code 而不是 app/stream
  2. 配置监控:监控 WVP API 可用性,查询失败时告警
  3. 缓存策略:高并发场景下添加缓存减少 WVP 负载
  4. 日志级别:生产环境设置 WARNING 级别,开发环境使用 INFO
  5. 格式统一:所有页面使用相同的 get_display_name 方法,保证一致性

性能优化

并发查询

告警列表使用 asyncio.gather 并发查询多个摄像头:

alarm_list = await asyncio.gather(*[
    _alarm_to_camel(a.to_dict(), current_user) for a in alarms
])

批量查询优化

如需批量查询,可以添加 get_display_names_batch 方法:

async def get_display_names_batch(self, device_ids: List[str]) -> Dict[str, str]:
    """批量查询摄像头显示名称"""
    tasks = [self.get_display_name(device_id) for device_id in device_ids]
    results = await asyncio.gather(*tasks)
    return dict(zip(device_ids, results))

版本历史

  • v1.0.0 (2026-02-24): 初始版本支持配置化格式、字段优先级、WVP集成