modify: cli命令更新
This commit is contained in:
@@ -102,7 +102,7 @@ message = { type = "str", default = "" }
|
||||
### 第四步:生成 Pydantic 模型
|
||||
|
||||
```bash
|
||||
uv run python -m chongming.scripts.gen_models
|
||||
uv run gen_models
|
||||
```
|
||||
|
||||
自动在 `src/plugins/<name>/models/` 下生成 `pydantic.py` 和 `__init__.py`。
|
||||
@@ -209,7 +209,7 @@ from .routes import router # 网关通过 getattr 自动发现
|
||||
## 为现有插件添加新端点
|
||||
|
||||
1. 创建 `config/workers/<name>/<new_op>.toml`
|
||||
2. 运行 `uv run python -m chongming.scripts.gen_models`
|
||||
2. 运行 `uv run gen_models`
|
||||
3. 创建 `router/<new_op>.py`,引用生成的模型
|
||||
4. 更新 `router/__init__.py`
|
||||
5. 重启服务
|
||||
|
||||
@@ -345,7 +345,7 @@ tags = ["aibox_sophon_adapter", "sophon", "adapter"]
|
||||
### 新增 RPC 端点
|
||||
|
||||
1. 在 `config/workers/aibox_sophon_adapter/` 下创建 `<操作>.toml`(参考 `list_devices.toml`)
|
||||
2. 运行 `uv run python -m chongming.scripts.gen_models` 生成模型
|
||||
2. 运行 `uv run gen_models` 生成模型
|
||||
3. 在 `src/plugins/aibox_sophon_adapter/router/` 下创建 `<操作>.py`,使用 `@rpc_method`
|
||||
4. 更新 `router/__init__.py` 的导入与 `__all__`
|
||||
5. 重启服务
|
||||
|
||||
@@ -21,6 +21,7 @@ MQTT 客户端启动块已抽取到 mqtt_clients 能力组件。
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
@@ -156,6 +157,14 @@ class AiboxSophonAdapterPlugin(Plugin):
|
||||
set_global_var("alarm_forward_video_url", alarm_fwd_video_url)
|
||||
set_global_var("alarm_forward_timeout", alarm_fwd_timeout)
|
||||
|
||||
# 探测 ffmpeg(RTSP 拉流依赖);缺失时心跳仍正常入库,仅跳过拉流
|
||||
ffmpeg_available = shutil.which("ffmpeg") is not None
|
||||
set_global_var("ffmpeg_available", ffmpeg_available)
|
||||
if not ffmpeg_available:
|
||||
logger.warning(
|
||||
"[aibox_sophon_adapter] 未检测到 ffmpeg,设备正常通道的 RTSP 拉流将跳过"
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"[aibox_sophon_adapter] 已初始化: "
|
||||
f"心跳间隔={hb_interval}s, 超时={hb_timeout}s, 检查间隔={check_interval}s"
|
||||
|
||||
@@ -57,6 +57,9 @@ heartbeat_timeout: float = 15.0
|
||||
# 心跳上报间隔(秒)
|
||||
heartbeat_interval: float = 5.0
|
||||
|
||||
# ffmpeg 是否可用(on_init 时探测;不可用时跳过 RTSP 拉流,不阻断心跳)
|
||||
ffmpeg_available: bool = True
|
||||
|
||||
|
||||
def set_global_var(name: str, value: Any) -> None:
|
||||
"""
|
||||
@@ -85,5 +88,6 @@ __all__ = [
|
||||
"alarm_forward_url",
|
||||
"alarm_forward_video_url",
|
||||
"alarm_forward_timeout",
|
||||
"ffmpeg_available",
|
||||
"set_global_var",
|
||||
]
|
||||
|
||||
@@ -27,10 +27,14 @@ async def board_ping(request: BoardPingRequest, worker_id: str = "") -> dict:
|
||||
设备通过 MQTT 主题 /board_ping 定期(默认 5 秒)上报系统状态。
|
||||
收到心跳后更新数据库中的设备记录,标记为在线。
|
||||
"""
|
||||
from ..global_var import db, heartbeat_timeout, stream_manager, link_path, mqtt_forward
|
||||
from ..global_var import (
|
||||
db, heartbeat_timeout, stream_manager, link_path, mqtt_forward, ffmpeg_available,
|
||||
)
|
||||
|
||||
board_id = request.BoardId
|
||||
ping_json = request.model_dump_json()
|
||||
|
||||
# ---- 心跳落库(核心步骤,失败才视为心跳处理失败) ----
|
||||
try:
|
||||
if db is None:
|
||||
raise RuntimeError("Database not initialized")
|
||||
@@ -43,7 +47,6 @@ async def board_ping(request: BoardPingRequest, worker_id: str = "") -> dict:
|
||||
record: BoardHeartbeat | None = result.scalar_one_or_none()
|
||||
|
||||
now = datetime.now()
|
||||
ping_json = request.model_dump_json()
|
||||
|
||||
if record is None:
|
||||
# 新设备,创建记录
|
||||
@@ -81,17 +84,31 @@ async def board_ping(request: BoardPingRequest, worker_id: str = "") -> dict:
|
||||
record.updated_at = now
|
||||
|
||||
await session.commit()
|
||||
except Exception as e:
|
||||
logger.error(f"[Heartbeat] 处理心跳失败 (board_id={board_id}): {e}")
|
||||
return {"error": str(e)}
|
||||
|
||||
if stream_manager is None:
|
||||
raise RuntimeError("StreamManager not initialized")
|
||||
|
||||
# ---- 以下为可选能力:失败只告警,不阻断心跳 ----
|
||||
ping_data = json.loads(ping_json)
|
||||
|
||||
# RTSP 拉流(依赖 ffmpeg;缺失时跳过并在启动日志提示)
|
||||
medias = ping_data.get("Medias", {})
|
||||
for media in medias:
|
||||
if "正常" in media.get("MediaStatus", {}).get("label", ""):
|
||||
pending = [
|
||||
media for media in medias
|
||||
if "正常" in media.get("MediaStatus", {}).get("label", "")
|
||||
]
|
||||
if pending and stream_manager is None:
|
||||
logger.warning("[Heartbeat] StreamManager 未初始化,跳过 RTSP 拉流")
|
||||
elif pending and not ffmpeg_available:
|
||||
logger.warning("[Heartbeat] ffmpeg 不可用,跳过 RTSP 拉流(安装 ffmpeg 后恢复)")
|
||||
else:
|
||||
for media in pending:
|
||||
stream_id = media["MediaName"]
|
||||
source_url = media["MediaUrl"].replace("/Link", link_path)
|
||||
try:
|
||||
await stream_manager.start_stream(f"/{stream_id}", source_url)
|
||||
except Exception as e:
|
||||
logger.warning(f"[Heartbeat] 通道 {stream_id} 拉流失败: {e}")
|
||||
|
||||
# 转发心跳数据到外部 MQTT Broker
|
||||
if mqtt_forward is not None:
|
||||
@@ -110,8 +127,4 @@ async def board_ping(request: BoardPingRequest, worker_id: str = "") -> dict:
|
||||
f"medias={len(request.Medias)}, tasks={len(request.Tasks)}"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[Heartbeat] 处理心跳失败 (board_id={board_id}): {e}")
|
||||
return {"error": str(e)}
|
||||
|
||||
return {"received": True, "board_id": board_id}
|
||||
|
||||
@@ -94,7 +94,7 @@ async def _analyze_with_doubao(zenoh_session, full_data: dict) -> bool:
|
||||
logger.info("[AlarmReport] 豆包分析已关闭 (doubao_analysis.enabled=false)")
|
||||
return True
|
||||
|
||||
async with Client(session=zenoh_session) as client:
|
||||
async with Client(session=zenoh_session, logger=logger) as client:
|
||||
try:
|
||||
result = await client.call(
|
||||
worker_type="doubao",
|
||||
|
||||
Reference in New Issue
Block a user