# 摄像头名称格式化配置 ## 概述 摄像头名称格式化服务提供了灵活、可配置的方式来格式化摄像头显示名称。所有配置通过环境变量控制,无需修改代码即可调整显示格式。 ## 架构设计 ``` ┌─────────────────────────────────────────────────────┐ │ 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`: ```python self.name_field_priority = ["gbName", "app", "stream"] ``` ## 使用方式 ### 1. 在环境变量中配置 `.env` 文件: ```bash WVP_API_BASE=http://192.168.0.104:18080 CAMERA_NAME_FORMAT={camera_code} {name}/{stream} CAMERA_QUERY_TIMEOUT=5 ``` ### 2. 服务自动加载配置 ```python 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. 修改格式只需重启服务 ```bash # 修改环境变量 export CAMERA_NAME_FORMAT="{name}" # 重启服务 systemctl restart service ``` ## API 示例 ### 查询摄像头信息 ```python camera_info = await camera_service.get_camera_info("cam_1f0e3dad9990") # 返回: { # "cameraCode": "cam_1f0e3dad9990", # "app": "大堂吧台3", # "stream": "012", # "gbName": "大堂吧台3/", # ... # } ``` ### 提取名称 ```python name = camera_service.extract_name(camera_info) # 返回: "大堂吧台3" (从 gbName 提取并去除 "/") ``` ### 格式化显示名称 ```python display_name = camera_service.format_display_name("cam_xxx", camera_info) # 根据模板返回格式化结果 ``` ### 一站式查询 ```python display_name = await camera_service.get_display_name("cam_1f0e3dad9990") # 自动查询 + 格式化 ``` ## 扩展性 ### 添加新的显示格式 只需修改环境变量即可: ```bash # 添加前缀 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 查询: ```python 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 不存在 - 摄像头信息字段缺失 **检查方法**: ```bash # 测试 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 ``` **解决方法**: 增加超时时间: ```bash 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` 并发查询多个摄像头: ```python alarm_list = await asyncio.gather(*[ _alarm_to_camel(a.to_dict(), current_user) for a in alarms ]) ``` ### 批量查询优化 如需批量查询,可以添加 `get_display_names_batch` 方法: ```python 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集成