feat(aiot): 边缘告警HTTP上报 + 移除配置中转层

- 新增 edge/report 端点接收边缘端HTTP告警上报
- alarm_event_service 新增 create_from_edge_report 幂等创建
- schemas 新增 EdgeAlarmReport 模型
- 移除 config_service/redis_service/yudao_aiot_config 配置中转
- MQTT 服务标记废弃,告警上报改为HTTP+COS
- config 新增 COS/Redis 配置项
- requirements 新增 redis 依赖

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-10 15:22:01 +08:00
parent 6cf1524013
commit 9f4cea0810
8 changed files with 207 additions and 307 deletions

View File

@@ -126,6 +126,97 @@ class AlarmEventService:
finally:
db.close()
def create_from_edge_report(self, data: Dict[str, Any]) -> Optional[AlarmEvent]:
"""
从边缘端 HTTP 上报创建告警事件
边缘端通过 POST /admin-api/aiot/alarm/edge/report 上报告警。
使用边缘端生成的 alarm_id支持幂等重复 alarm_id 跳过)。
Args:
data: 边缘端上报数据,字段与 alarm_event 表对齐
Returns:
AlarmEvent 或 None
"""
db = get_session()
try:
alarm_id = data.get("alarm_id")
if not alarm_id:
logger.error("边缘上报缺少 alarm_id")
return None
# 幂等校验alarm_id 已存在则跳过
existing = db.query(AlarmEvent).filter(AlarmEvent.alarm_id == alarm_id).first()
if existing:
logger.info(f"告警已存在,跳过: {alarm_id}")
return existing
# 解析时间
event_time_str = data.get("event_time")
if event_time_str:
try:
event_time = datetime.fromisoformat(event_time_str.replace("Z", "+00:00"))
except ValueError:
event_time = datetime.now(timezone.utc)
else:
event_time = datetime.now(timezone.utc)
# 置信度
confidence = data.get("confidence_score")
if confidence is not None:
confidence = float(confidence)
if confidence > 1:
confidence = confidence / 100.0
alarm_type = data.get("alarm_type", "unknown")
alarm_level = data.get("alarm_level")
if alarm_level is None:
# 从 ext_data 取 duration_ms
ext_data = data.get("ext_data") or {}
duration_ms = ext_data.get("duration_ms")
alarm_level = _determine_alarm_level(alarm_type, confidence or 0, duration_ms)
alarm = AlarmEvent(
alarm_id=alarm_id,
alarm_type=alarm_type,
algorithm_code=data.get("algorithm_code"),
device_id=data.get("device_id", "unknown"),
scene_id=data.get("scene_id"),
event_time=event_time,
alarm_level=alarm_level,
confidence_score=confidence,
alarm_status="NEW",
handle_status="UNHANDLED",
snapshot_url=data.get("snapshot_url"), # COS object_key
edge_node_id=data.get("ext_data", {}).get("edge_node_id") if data.get("ext_data") else None,
)
db.add(alarm)
# 写入扩展表
ext_data = data.get("ext_data")
if ext_data:
ext = AlarmEventExt(
alarm_id=alarm_id,
ext_type="EDGE_HTTP",
ext_data=ext_data,
)
db.add(ext)
db.commit()
db.refresh(alarm)
logger.info(f"边缘端告警创建成功: {alarm_id}, type={alarm_type}, device={data.get('device_id')}")
return alarm
except Exception as e:
db.rollback()
logger.error(f"创建边缘端告警失败: {e}")
return None
finally:
db.close()
def create_from_http(self, data: Dict[str, Any], snapshot_data: Optional[bytes] = None) -> Optional[AlarmEvent]:
"""从 HTTP 请求创建告警事件"""
db = get_session()