280 lines
7.6 KiB
Markdown
280 lines
7.6 KiB
Markdown
|
|
# 摄像头名称格式化配置
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
摄像头名称格式化服务提供了灵活、可配置的方式来格式化摄像头显示名称。所有配置通过环境变量控制,无需修改代码即可调整显示格式。
|
|||
|
|
|
|||
|
|
## 架构设计
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────┐
|
|||
|
|
│ 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集成
|