From 3164d81bb03ba343319cc5a3a02b6508eb0c5de8 Mon Sep 17 00:00:00 2001 From: stu2not Date: Fri, 15 May 2026 15:34:59 +0800 Subject: [PATCH] fix: support MQTT location refresh --- talkingq-url/banban/routers/devices.py | 39 ++++++++----------------- talkingq-url/banban/service/location.py | 26 +++++++++++++++-- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/talkingq-url/banban/routers/devices.py b/talkingq-url/banban/routers/devices.py index c61839a..6dd9ab4 100644 --- a/talkingq-url/banban/routers/devices.py +++ b/talkingq-url/banban/routers/devices.py @@ -1,7 +1,6 @@ import logging from collections.abc import Mapping from datetime import datetime, time -from services.connection_manager import connection_manager from fastapi import APIRouter, Depends, HTTPException, Query, Request from pydantic import BaseModel, Field from sqlalchemy import text @@ -573,15 +572,12 @@ async def get_current_device_location( service = await TalkingQMQTTService.get_instance() if service is None: raise HTTPException(status_code=503, detail="MQTT 服务未初始化") + query_started_at = datetime.now() await service.send_gps_query(device_id) try: - # 每隔1s 获取一次GPS数据,最多3次 - # 先判断设备是否在线,不在线直接提示设备没有在线,通过websocket判断 - target_websocket = await connection_manager.get_connection(device_id) - if not target_websocket or target_websocket.client_state.name != "CONNECTED": - raise HTTPException(status_code=408, detail="设备未在线") - i=0 - while i<1: + # MQTT 设备没有 WebSocket 连接时,也可以通过 GPS 回包刷新定位。 + row = None + for _ in range(3): try: row = await location_service.get_device_current_location( device_id=device_id, @@ -590,12 +586,10 @@ async def get_current_device_location( except Exception as e: await asyncio.sleep(1) continue - - if row is None: - await asyncio.sleep(1) - else: - if row["updated_at"] is not None \ - and (datetime.now() - row['updated_at']) <= timedelta(seconds=10): + + if row is not None and row["updated_at"] is not None: + updated_at = row["updated_at"] + if updated_at >= query_started_at - timedelta(seconds=1): logger.info( "device current location fetched", extra={ @@ -607,22 +601,13 @@ async def get_current_device_location( }, ) return _row_to_current_location_response(row) - - i+=1 + + await asyncio.sleep(1) + if row is None: raise HTTPException(status_code=408, detail="GPS数据上报超时") - logger.info( - "device location reported", - extra={ - "event": "device_location_report", - "request_id": getattr(request.state, "request_id", None), - "device_id": device_id, - "child_id": int(row["child_id"]), - "lat": float(row["lat"]), - "lng": float(row["lng"]), - }, - ) + raise HTTPException(status_code=408, detail="GPS数据未刷新") except Exception as e: raise HTTPException(status_code=408, detail=f"GPS数据上报失败: {e}") diff --git a/talkingq-url/banban/service/location.py b/talkingq-url/banban/service/location.py index a60b5a8..7c94057 100644 --- a/talkingq-url/banban/service/location.py +++ b/talkingq-url/banban/service/location.py @@ -109,7 +109,7 @@ class LocationService(DatabaseServiceBase): altitude_m: float | None = None, speed_mps: float | None = None, heading_deg: int | None = None, - source: int | None = None, + source: int | str | None = None, battery_pct: int | None = None, device_time: datetime | None = None, ) -> Mapping[str, Any] | None: @@ -129,6 +129,8 @@ class LocationService(DatabaseServiceBase): battery_pct: int | None device_time: datetime + source_value = self._normalize_location_source(source) + db_session = await self.get_session() try: dao = LocationDAO(db_session) @@ -144,7 +146,7 @@ class LocationService(DatabaseServiceBase): altitude_m=altitude_m, speed_mps=speed_mps, heading_deg=heading_deg, - source=source if source is not None else 0, + source=source_value, battery_pct=battery_pct, device_time=device_time or datetime.now(), ) @@ -156,5 +158,25 @@ class LocationService(DatabaseServiceBase): finally: await db_session.close() + @staticmethod + def _normalize_location_source(source: int | str | None) -> int: + if source is None: + return 0 + if isinstance(source, int): + return source + text = str(source).strip().lower() + if not text: + return 0 + if text.isdigit(): + return int(text) + return { + "gps": 1, + "wifi": 2, + "cell": 3, + "base_station": 3, + "manual": 4, + "mock": 9, + }.get(text, 0) + # 创建全局 LocationService 实例 location_service = LocationService()