feat: 注册 aiot 路由并更新主程序配置
- main.py:注册 aiot_alarm 和 aiot_edge 路由,保留旧路由兼容 - config.py/alert_service.py/mqtt_service.py:同步更新配置和服务 - 添加 CLAUDE.md 项目说明文档 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -319,6 +319,68 @@ class AlertService:
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
def get_camera_alert_summary(
|
||||
self,
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
) -> dict:
|
||||
"""以摄像头为维度获取告警汇总"""
|
||||
from sqlalchemy import func
|
||||
db = get_session()
|
||||
try:
|
||||
# 按摄像头分组统计总数和最近时间
|
||||
query = db.query(
|
||||
Alert.camera_id,
|
||||
func.count(Alert.id).label("total_count"),
|
||||
func.max(Alert.created_at).label("last_alert_time"),
|
||||
).group_by(Alert.camera_id)
|
||||
|
||||
# 总数
|
||||
total = query.count()
|
||||
|
||||
# 分页
|
||||
results = (
|
||||
query.order_by(func.count(Alert.id).desc())
|
||||
.offset((page - 1) * page_size)
|
||||
.limit(page_size)
|
||||
.all()
|
||||
)
|
||||
|
||||
summary_list = []
|
||||
for row in results:
|
||||
# 获取该摄像头待处理告警数量
|
||||
pending_count = (
|
||||
db.query(Alert)
|
||||
.filter(Alert.camera_id == row.camera_id)
|
||||
.filter(Alert.status == AlertStatus.PENDING)
|
||||
.count()
|
||||
)
|
||||
|
||||
# 获取该摄像头最新的一条告警
|
||||
latest_alert = (
|
||||
db.query(Alert)
|
||||
.filter(Alert.camera_id == row.camera_id)
|
||||
.order_by(Alert.created_at.desc())
|
||||
.first()
|
||||
)
|
||||
|
||||
summary_list.append({
|
||||
"cameraId": row.camera_id,
|
||||
"cameraName": row.camera_id, # TODO: 从设备服务获取摄像头名称
|
||||
"totalCount": row.total_count,
|
||||
"pendingCount": pending_count,
|
||||
"lastAlertTime": row.last_alert_time.isoformat() if row.last_alert_time else None,
|
||||
"lastAlertType": latest_alert.alert_type if latest_alert else None,
|
||||
"lastAlertTypeName": latest_alert.alert_type if latest_alert else None, # 前端会映射
|
||||
})
|
||||
|
||||
return {
|
||||
"list": summary_list,
|
||||
"total": total,
|
||||
}
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
# 全局单例
|
||||
alert_service = AlertService()
|
||||
|
||||
@@ -20,6 +20,7 @@ class MQTTService:
|
||||
self._client: Optional[mqtt.Client] = None
|
||||
self._connected = False
|
||||
self._running = False
|
||||
self._use_v2_callback = False # paho-mqtt 版本标记
|
||||
self._lock = threading.Lock()
|
||||
|
||||
# 回调函数
|
||||
@@ -58,11 +59,23 @@ class MQTTService:
|
||||
return
|
||||
|
||||
try:
|
||||
self._client = mqtt.Client(
|
||||
client_id=settings.mqtt.client_id,
|
||||
protocol=mqtt.MQTTv5,
|
||||
callback_api_version=mqtt.CallbackAPIVersion.VERSION2
|
||||
)
|
||||
# 兼容 paho-mqtt 1.x 和 2.x 版本
|
||||
try:
|
||||
# paho-mqtt 2.0+ 新 API
|
||||
self._client = mqtt.Client(
|
||||
client_id=settings.mqtt.client_id,
|
||||
protocol=mqtt.MQTTv5,
|
||||
callback_api_version=mqtt.CallbackAPIVersion.VERSION2
|
||||
)
|
||||
self._use_v2_callback = True
|
||||
except AttributeError:
|
||||
# paho-mqtt 1.x 旧 API
|
||||
self._client = mqtt.Client(
|
||||
client_id=settings.mqtt.client_id,
|
||||
protocol=mqtt.MQTTv5
|
||||
)
|
||||
self._use_v2_callback = False
|
||||
logger.info("使用 paho-mqtt 1.x 兼容模式")
|
||||
|
||||
# 设置回调
|
||||
self._client.on_connect = self._on_connect
|
||||
@@ -107,9 +120,17 @@ class MQTTService:
|
||||
self._client.disconnect()
|
||||
logger.info("MQTT 服务已停止")
|
||||
|
||||
def _on_connect(self, client, userdata, flags, reason_code, properties):
|
||||
"""连接回调"""
|
||||
if reason_code == 0:
|
||||
def _on_connect(self, client, userdata, *args):
|
||||
"""连接回调 (兼容 1.x 和 2.x)"""
|
||||
# 1.x: (client, userdata, flags, rc)
|
||||
# 2.x: (client, userdata, connect_flags, reason_code, properties)
|
||||
if args:
|
||||
reason_code = args[-2] if len(args) >= 2 else args[-1]
|
||||
rc = reason_code if isinstance(reason_code, int) else getattr(reason_code, 'value', reason_code)
|
||||
else:
|
||||
rc = -1
|
||||
|
||||
if rc == 0:
|
||||
self._connected = True
|
||||
logger.info("MQTT 连接成功")
|
||||
|
||||
@@ -123,10 +144,17 @@ class MQTTService:
|
||||
self._connected = False
|
||||
logger.error(f"MQTT 连接失败: {reason_code}")
|
||||
|
||||
def _on_disconnect(self, client, userdata, reason_code, properties):
|
||||
"""断开连接回调"""
|
||||
def _on_disconnect(self, client, userdata, *args):
|
||||
"""断开连接回调 (兼容 1.x 和 2.x)"""
|
||||
# 1.x: (client, userdata, rc)
|
||||
# 2.x: (client, userdata, disconnect_flags, reason_code, properties)
|
||||
self._connected = False
|
||||
logger.warning(f"MQTT 连接断开: {reason_code}")
|
||||
if args:
|
||||
reason_code = args[-2] if len(args) >= 2 else args[0]
|
||||
rc = reason_code if isinstance(reason_code, int) else getattr(reason_code, 'value', reason_code)
|
||||
logger.warning(f"MQTT 连接断开: {rc}")
|
||||
else:
|
||||
logger.warning("MQTT 连接断开")
|
||||
|
||||
def _on_message(self, client, userdata, msg: mqtt.MQTTMessage):
|
||||
"""消息回调"""
|
||||
|
||||
Reference in New Issue
Block a user