fix(service): Alarm creation without duration - aligns with ai_edge changes
Changes: 1. Modified create_from_mqtt to parse first_frame_time from MQTT data 2. Removed duration_minutes processing logic 3. Set duration_ms=None and last_frame_time=None on alarm creation 4. Updated _determine_alarm_level to handle duration_ms=None (returns level 2 for leave_post) This ensures alarms are created with status=NEW and no duration/end time, which will be populated later when the alarm is resolved. Test: test_alarm_create_no_duration.py validates the new behavior. Related: Task 2 of alarm status management fix Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,9 +28,14 @@ def _determine_alarm_level(alarm_type: str, confidence: float, duration_ms: Opti
|
|||||||
if alarm_type == "intrusion":
|
if alarm_type == "intrusion":
|
||||||
return 3 # 严重
|
return 3 # 严重
|
||||||
elif alarm_type == "leave_post":
|
elif alarm_type == "leave_post":
|
||||||
if duration_ms and duration_ms > 30 * 60 * 1000:
|
# 告警触发时 duration_ms 为 None,设置为一般级别
|
||||||
|
if duration_ms is None:
|
||||||
|
return 2 # 一般级别(刚触发,持续时长未知)
|
||||||
|
|
||||||
|
# 根据持续时长判断级别
|
||||||
|
if duration_ms > 30 * 60 * 1000:
|
||||||
return 3 # 严重
|
return 3 # 严重
|
||||||
elif duration_ms and duration_ms > 10 * 60 * 1000:
|
elif duration_ms > 10 * 60 * 1000:
|
||||||
return 2 # 一般
|
return 2 # 一般
|
||||||
return 1 # 提醒
|
return 1 # 提醒
|
||||||
elif confidence and confidence > 0.9:
|
elif confidence and confidence > 0.9:
|
||||||
@@ -63,6 +68,15 @@ class AlarmEventService:
|
|||||||
else:
|
else:
|
||||||
event_time = datetime.now(timezone.utc)
|
event_time = datetime.now(timezone.utc)
|
||||||
|
|
||||||
|
# 解析 first_frame_time(告警首次触发时间)
|
||||||
|
first_frame_str = mqtt_data.get("first_frame_time")
|
||||||
|
first_frame_time = None
|
||||||
|
if first_frame_str:
|
||||||
|
try:
|
||||||
|
first_frame_time = datetime.fromisoformat(first_frame_str.replace("Z", "+00:00"))
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
# 置信度保持 float 0-1
|
# 置信度保持 float 0-1
|
||||||
confidence = mqtt_data.get("confidence")
|
confidence = mqtt_data.get("confidence")
|
||||||
if confidence is not None:
|
if confidence is not None:
|
||||||
@@ -71,14 +85,9 @@ class AlarmEventService:
|
|||||||
if confidence > 1:
|
if confidence > 1:
|
||||||
confidence = confidence / 100.0
|
confidence = confidence / 100.0
|
||||||
|
|
||||||
# duration_minutes → duration_ms
|
|
||||||
duration_minutes = mqtt_data.get("duration_minutes")
|
|
||||||
duration_ms = None
|
|
||||||
if duration_minutes is not None:
|
|
||||||
duration_ms = int(float(duration_minutes) * 60 * 1000)
|
|
||||||
|
|
||||||
alarm_type = mqtt_data.get("alert_type", "unknown")
|
alarm_type = mqtt_data.get("alert_type", "unknown")
|
||||||
alarm_level = _determine_alarm_level(alarm_type, confidence or 0, duration_ms)
|
# 告警创建时不传递 duration_ms,传递 None
|
||||||
|
alarm_level = _determine_alarm_level(alarm_type, confidence or 0, None)
|
||||||
|
|
||||||
alarm = AlarmEvent(
|
alarm = AlarmEvent(
|
||||||
alarm_id=alarm_id,
|
alarm_id=alarm_id,
|
||||||
@@ -87,7 +96,9 @@ class AlarmEventService:
|
|||||||
device_id=mqtt_data.get("camera_id", "unknown"),
|
device_id=mqtt_data.get("camera_id", "unknown"),
|
||||||
scene_id=mqtt_data.get("roi_id"),
|
scene_id=mqtt_data.get("roi_id"),
|
||||||
event_time=event_time,
|
event_time=event_time,
|
||||||
duration_ms=duration_ms,
|
first_frame_time=first_frame_time,
|
||||||
|
duration_ms=None,
|
||||||
|
last_frame_time=None,
|
||||||
alarm_level=alarm_level,
|
alarm_level=alarm_level,
|
||||||
confidence_score=confidence,
|
confidence_score=confidence,
|
||||||
alarm_status="NEW",
|
alarm_status="NEW",
|
||||||
|
|||||||
53
test_alarm_create_no_duration.py
Normal file
53
test_alarm_create_no_duration.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
"""
|
||||||
|
Test alarm creation without duration
|
||||||
|
Verify:
|
||||||
|
1. Alarm creation with duration_ms as None
|
||||||
|
2. last_frame_time should be None
|
||||||
|
3. first_frame_time should have value
|
||||||
|
4. alarm_status should be NEW
|
||||||
|
5. handle_status should be UNHANDLED
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, 'C:/Users/16337/PycharmProjects/service')
|
||||||
|
|
||||||
|
from app.services.alarm_event_service import AlarmEventService
|
||||||
|
|
||||||
|
def test_create_alarm_no_duration():
|
||||||
|
"""Test creating alarm without duration"""
|
||||||
|
service = AlarmEventService()
|
||||||
|
|
||||||
|
mqtt_data = {
|
||||||
|
"alert_type": "leave_post",
|
||||||
|
"camera_id": "cam001",
|
||||||
|
"roi_id": "roi001",
|
||||||
|
"timestamp": "2026-02-12 14:30:00",
|
||||||
|
"first_frame_time": "2026-02-12 14:23:00",
|
||||||
|
"message": "Leave post alarm",
|
||||||
|
"confidence": 0.95,
|
||||||
|
# No longer sending duration_minutes
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Creating alarm test...")
|
||||||
|
alarm = service.create_from_mqtt(mqtt_data)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert alarm is not None, "Alarm creation failed"
|
||||||
|
assert alarm.alarm_status == "NEW", f"Status should be NEW, but got {alarm.alarm_status}"
|
||||||
|
assert alarm.handle_status == "UNHANDLED", f"Handle status should be UNHANDLED, but got {alarm.handle_status}"
|
||||||
|
assert alarm.duration_ms is None, f"duration_ms should be None, but got {alarm.duration_ms}"
|
||||||
|
assert alarm.last_frame_time is None, f"last_frame_time should be None, but got {alarm.last_frame_time}"
|
||||||
|
assert alarm.first_frame_time is not None, "first_frame_time should have value"
|
||||||
|
assert alarm.alarm_level == 2, f"alarm_level should be 2 (general level), but got {alarm.alarm_level}"
|
||||||
|
|
||||||
|
print("[PASS] Test passed: Alarm created without duration")
|
||||||
|
print(f" alarm_id: {alarm.alarm_id}")
|
||||||
|
print(f" alarm_type: {alarm.alarm_type}")
|
||||||
|
print(f" alarm_status: {alarm.alarm_status}")
|
||||||
|
print(f" alarm_level: {alarm.alarm_level}")
|
||||||
|
print(f" duration_ms: {alarm.duration_ms}")
|
||||||
|
print(f" first_frame_time: {alarm.first_frame_time}")
|
||||||
|
print(f" last_frame_time: {alarm.last_frame_time}")
|
||||||
|
print(f" event_time: {alarm.event_time}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_create_alarm_no_duration()
|
||||||
Reference in New Issue
Block a user