[功能] fam-edge 运动心跳支持 - /api/ss/motion 空 events 心跳刷新, has_motion_in_range_local 按 max_heartbeat_age_sec(900s) fail-open
This commit is contained in:
@@ -47,17 +47,18 @@ video_processing:
|
|||||||
# 降级顺序:先 gemini 整视频,失败再 nvidia 整视频;两者都失败 -> 标记 failed
|
# 降级顺序:先 gemini 整视频,失败再 nvidia 整视频;两者都失败 -> 标记 failed
|
||||||
vision_order: ["gemini", "nvidia"]
|
vision_order: ["gemini", "nvidia"]
|
||||||
|
|
||||||
# 运动侦测预过滤(2026-08-22 重构):
|
# 运动侦测预过滤(2026-08-22 重构,2026-08-22 补心跳):
|
||||||
# - 甲骨文【不再反向访问 NAS】。原 dsm_motion_client(甲骨文主动查 SS API)已停用,
|
# - 甲骨文【不再反向访问 NAS】。原 dsm_motion_client(甲骨文主动查 SS API)已停用,
|
||||||
# 改由 NAS 端 fam-core 的 MotionNotifier 轮询/接收 SS 事件后,主动 POST 推送到
|
# 改由 NAS 端 fam-core 的 MotionNotifier 接收 SS Webhook 后,主动 POST 推送到
|
||||||
# 甲骨文 /api/ss/motion,落库 ss_motion_events。
|
# 甲骨文 /api/ss/motion,落库 ss_motion_events;NAS 侧还会定期用空 events 单纯
|
||||||
|
# 调一次这个接口当心跳(不要求真的有事件),证明推送链路还活着。
|
||||||
# - video_processor 分析前调用 db.has_motion_in_range_local()(本地运动事件表)做
|
# - video_processor 分析前调用 db.has_motion_in_range_local()(本地运动事件表)做
|
||||||
# 预过滤:窗口内无运动事件则跳过云端分析(compute_provider=skipped_no_motion)。
|
# 预过滤:窗口内无运动事件则跳过云端分析(compute_provider=skipped_no_motion)。
|
||||||
# - 本地运动事件表为空(冷启动/尚未收到推送)一律 fail-open(照常分析),不漏检。
|
# - 安全阀门: 距上次心跳超过 max_heartbeat_age_sec 没更新(NAS 服务挂了/网络断了/
|
||||||
# 此 block 仅保留 min_motion_seconds 语义参考;host/account 等反向访问字段已弃用。
|
# DSM Webhook 规则被误关,历史数据表非空但推送链路已经死了),一律 fail-open
|
||||||
|
# (照常分析),不能仅凭"表里曾经有数据"就信任"这段时间确认无运动"的结论。
|
||||||
dsm_motion_prefilter:
|
dsm_motion_prefilter:
|
||||||
enabled: false # 已停用:甲骨文不再主动访问 NAS SS
|
max_heartbeat_age_sec: 900 # 心跳超过 15 分钟没更新 -> 判定推送链路可能已死,fail-open
|
||||||
min_motion_seconds: 0 # 窗口内运动事件总时长需 ≥ 此值才算"有运动"(0=有事件就算)
|
|
||||||
|
|
||||||
# 智能问答降级链(与视频分析独立):Gemini -> NVIDIA -> 本地 Ollama
|
# 智能问答降级链(与视频分析独立):Gemini -> NVIDIA -> 本地 Ollama
|
||||||
models:
|
models:
|
||||||
|
|||||||
@@ -205,7 +205,10 @@ def ss_motion():
|
|||||||
{"event_id": 25349, "camera_id": 2, "event_type": 10,
|
{"event_id": 25349, "camera_id": 2, "event_type": 10,
|
||||||
"start_time": 1787318023, "duration": 149, "thumbnail_url": "107471,12075"}
|
"start_time": 1787318023, "duration": 149, "thumbnail_url": "107471,12075"}
|
||||||
]}
|
]}
|
||||||
start_time/duration 为 Unix epoch(与 SS 同源,时区无关)。
|
start_time/duration 为 Unix epoch(与 SS 同源,时区无关)。events 可以是空数组
|
||||||
|
——NAS 侧也会定期用空 events 单纯调一次这个接口当心跳,证明推送链路还活着
|
||||||
|
(鉴权通过就刷新心跳,不要求 stored>0),供 has_motion_in_range_local() 判断
|
||||||
|
"无运动"结论是否可信。
|
||||||
落库 ss_motion_events(按 event_id 幂等),供 video_processor 本地预过滤使用。
|
落库 ss_motion_events(按 event_id 幂等),供 video_processor 本地预过滤使用。
|
||||||
"""
|
"""
|
||||||
if not _check_token():
|
if not _check_token():
|
||||||
@@ -218,6 +221,7 @@ def ss_motion():
|
|||||||
return jsonify({"error": "events 必须是数组"}), 400
|
return jsonify({"error": "events 必须是数组"}), 400
|
||||||
try:
|
try:
|
||||||
stored = state.get_db().record_motion_events(events)
|
stored = state.get_db().record_motion_events(events)
|
||||||
|
state.get_db().record_motion_heartbeat()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"ss_motion 落库异常: {e}")
|
logger.error(f"ss_motion 落库异常: {e}")
|
||||||
return jsonify({"error": str(e)}), 500
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|||||||
Reference in New Issue
Block a user