From b6fba4639d9ef2dc3513629595471940fd5c3c83 Mon Sep 17 00:00:00 2001 From: 16337 <1633794139@qq.com> Date: Wed, 11 Feb 2026 10:01:20 +0800 Subject: [PATCH] =?UTF-8?q?fix(aiot):=20=E4=BF=AE=E5=A4=8D=E7=A6=BB?= =?UTF-8?q?=E5=B2=97=E6=A3=80=E6=B5=8B=E5=90=AF=E5=8A=A8=E7=AB=8B=E5=8D=B3?= =?UTF-8?q?=E6=8A=A5=E8=AD=A6=E7=9A=84=E4=B8=89=E4=B8=AABug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug#1(严重): 无人帧不调用算法 - _batch_process_rois 中 len(boxes)>0 才调用 _handle_detections - 导致离岗检测永远收不到"人走了"的信号 - 修复: 无论检测结果是否为空都调用算法 - 同时移除 _handle_detections 中 tracks 为空的 early return Bug#2(高): WAITING 一帧就跳 ON_DUTY - 检测到人第一帧就立即从 WAITING 跳到 ON_DUTY - confirm_on_duty_sec 参数完全未被使用 - 修复: 新增 CONFIRMING 状态,需连续 10s 检测到人才确认上岗 Bug#3(中): confirm_leave_sec 默认值过短 - 默认 10 秒,用户预期 30 秒 - 修复: 所有默认值统一改为 30s Co-Authored-By: Claude Opus 4.6 --- algorithms.py | 26 +++++++++++++++++++++----- config/database.py | 2 +- main.py | 15 +++++++-------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/algorithms.py b/algorithms.py index ef07d0d..eff814f 100644 --- a/algorithms.py +++ b/algorithms.py @@ -18,6 +18,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) class LeavePostAlgorithm: STATE_WAITING = "WAITING" + STATE_CONFIRMING = "CONFIRMING" STATE_ON_DUTY = "ON_DUTY" STATE_LEAVING = "LEAVING" STATE_OFF_DUTY = "OFF_DUTY" @@ -26,7 +27,7 @@ class LeavePostAlgorithm: def __init__( self, confirm_on_duty_sec: int = 10, - confirm_leave_sec: int = 10, + confirm_leave_sec: int = 30, cooldown_sec: int = 600, working_hours: Optional[List[Dict]] = None, target_class: Optional[str] = "person", @@ -140,13 +141,28 @@ class LeavePostAlgorithm: if self.state == self.STATE_WAITING: if roi_has_person: - self.state = self.STATE_ON_DUTY + # 检测到人,进入上岗确认阶段 + self.state = self.STATE_CONFIRMING self.state_start_time = current_time self.detection_history.clear() self.detection_history.append((current_time, True)) else: pass + elif self.state == self.STATE_CONFIRMING: + self.detection_history.append((current_time, roi_has_person)) + if not roi_has_person: + # 人消失,回到等待状态 + self.state = self.STATE_WAITING + self.state_start_time = None + self.detection_history.clear() + else: + elapsed = (current_time - self.state_start_time).total_seconds() + if elapsed >= self.confirm_on_duty_sec: + # 持续在岗达到确认时长,正式确认上岗 + self.state = self.STATE_ON_DUTY + self.state_start_time = current_time + elif self.state == self.STATE_ON_DUTY: self.detection_history.append((current_time, roi_has_person)) if not roi_has_person: @@ -395,7 +411,7 @@ class AlgorithmManager: self.default_params = { "leave_post": { "confirm_on_duty_sec": 10, - "confirm_leave_sec": 10, + "confirm_leave_sec": 30, "cooldown_sec": 600, "target_class": "person", }, @@ -520,7 +536,7 @@ class AlgorithmManager: if algo_code == "leave_post": algo_params = { "confirm_on_duty_sec": params.get("confirm_on_duty_sec", 10), - "confirm_leave_sec": params.get("confirm_leave_sec", 10), + "confirm_leave_sec": params.get("confirm_leave_sec", 30), "cooldown_sec": params.get("cooldown_sec", 600), "working_hours": params.get("working_hours", []), "target_class": params.get("target_class", bind_config.get("target_class", "person")), @@ -638,7 +654,7 @@ class AlgorithmManager: roi_working_hours = algo_params.get("working_hours") or self.working_hours self.algorithms[roi_id][key]["leave_post"] = LeavePostAlgorithm( confirm_on_duty_sec=algo_params.get("confirm_on_duty_sec", 10), - confirm_leave_sec=algo_params.get("confirm_leave_sec", 10), + confirm_leave_sec=algo_params.get("confirm_leave_sec", 30), cooldown_sec=algo_params.get("cooldown_sec", 600), working_hours=roi_working_hours, target_class=algo_params.get("target_class", "person"), diff --git a/config/database.py b/config/database.py index 3048745..b1eda4e 100644 --- a/config/database.py +++ b/config/database.py @@ -265,7 +265,7 @@ class SQLiteManager: 'target_class': 'person', 'param_schema': json.dumps({ "confirm_on_duty_sec": {"type": "int", "default": 10, "min": 1}, - "confirm_leave_sec": {"type": "int", "default": 10, "min": 1}, + "confirm_leave_sec": {"type": "int", "default": 30, "min": 1}, "cooldown_sec": {"type": "int", "default": 600, "min": 0}, "working_hours": {"type": "list", "default": []}, }), diff --git a/main.py b/main.py index 47a384f..01e8e2d 100644 --- a/main.py +++ b/main.py @@ -404,12 +404,12 @@ class EdgeInferenceService: for idx, (camera_id, roi, bind, frame, _, scale_info) in enumerate(roi_items): boxes, scores, class_ids = batch_results[idx] - if len(boxes) > 0: - self._handle_detections( - camera_id, roi, bind, frame, - boxes, scores, class_ids, - scale_info - ) + # 无论是否检测到目标都要调用算法(离岗检测需要"无人"信号) + self._handle_detections( + camera_id, roi, bind, frame, + boxes, scores, class_ids, + scale_info + ) except Exception as e: self._logger.error(f"批量处理 ROI 失败: {e}") @@ -489,8 +489,7 @@ class EdgeInferenceService: tracks = self._build_tracks(roi, boxes, scores, class_ids, scale_info) - if not tracks: - return + # 离岗检测需要"无人"信号,不能因为 tracks 为空就跳过算法 # 诊断日志:tracks 内容(非告警诊断日志,使用 DEBUG 级别) self._logger.debug(f"[{camera_id}] tracks: {[t.get('class') for t in tracks]}, target_class={bind.target_class}")