fix: support MQTT location refresh

This commit is contained in:
stu2not
2026-05-15 15:34:59 +08:00
parent 02410e2922
commit 3164d81bb0
2 changed files with 36 additions and 29 deletions

View File

@@ -1,7 +1,6 @@
import logging import logging
from collections.abc import Mapping from collections.abc import Mapping
from datetime import datetime, time from datetime import datetime, time
from services.connection_manager import connection_manager
from fastapi import APIRouter, Depends, HTTPException, Query, Request from fastapi import APIRouter, Depends, HTTPException, Query, Request
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from sqlalchemy import text from sqlalchemy import text
@@ -573,15 +572,12 @@ async def get_current_device_location(
service = await TalkingQMQTTService.get_instance() service = await TalkingQMQTTService.get_instance()
if service is None: if service is None:
raise HTTPException(status_code=503, detail="MQTT 服务未初始化") raise HTTPException(status_code=503, detail="MQTT 服务未初始化")
query_started_at = datetime.now()
await service.send_gps_query(device_id) await service.send_gps_query(device_id)
try: try:
# 每隔1s 获取一次GPS数据最多3次 # MQTT 设备没有 WebSocket 连接时,也可以通过 GPS 回包刷新定位。
# 先判断设备是否在线不在线直接提示设备没有在线通过websocket判断 row = None
target_websocket = await connection_manager.get_connection(device_id) for _ in range(3):
if not target_websocket or target_websocket.client_state.name != "CONNECTED":
raise HTTPException(status_code=408, detail="设备未在线")
i=0
while i<1:
try: try:
row = await location_service.get_device_current_location( row = await location_service.get_device_current_location(
device_id=device_id, device_id=device_id,
@@ -590,12 +586,10 @@ async def get_current_device_location(
except Exception as e: except Exception as e:
await asyncio.sleep(1) await asyncio.sleep(1)
continue continue
if row is None: if row is not None and row["updated_at"] is not None:
await asyncio.sleep(1) updated_at = row["updated_at"]
else: if updated_at >= query_started_at - timedelta(seconds=1):
if row["updated_at"] is not None \
and (datetime.now() - row['updated_at']) <= timedelta(seconds=10):
logger.info( logger.info(
"device current location fetched", "device current location fetched",
extra={ extra={
@@ -607,22 +601,13 @@ async def get_current_device_location(
}, },
) )
return _row_to_current_location_response(row) return _row_to_current_location_response(row)
i+=1 await asyncio.sleep(1)
if row is None: if row is None:
raise HTTPException(status_code=408, detail="GPS数据上报超时") raise HTTPException(status_code=408, detail="GPS数据上报超时")
logger.info( raise HTTPException(status_code=408, detail="GPS数据未刷新")
"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"]),
},
)
except Exception as e: except Exception as e:
raise HTTPException(status_code=408, detail=f"GPS数据上报失败: {e}") raise HTTPException(status_code=408, detail=f"GPS数据上报失败: {e}")

View File

@@ -109,7 +109,7 @@ class LocationService(DatabaseServiceBase):
altitude_m: float | None = None, altitude_m: float | None = None,
speed_mps: float | None = None, speed_mps: float | None = None,
heading_deg: int | None = None, heading_deg: int | None = None,
source: int | None = None, source: int | str | None = None,
battery_pct: int | None = None, battery_pct: int | None = None,
device_time: datetime | None = None, device_time: datetime | None = None,
) -> Mapping[str, Any] | None: ) -> Mapping[str, Any] | None:
@@ -129,6 +129,8 @@ class LocationService(DatabaseServiceBase):
battery_pct: int | None battery_pct: int | None
device_time: datetime device_time: datetime
source_value = self._normalize_location_source(source)
db_session = await self.get_session() db_session = await self.get_session()
try: try:
dao = LocationDAO(db_session) dao = LocationDAO(db_session)
@@ -144,7 +146,7 @@ class LocationService(DatabaseServiceBase):
altitude_m=altitude_m, altitude_m=altitude_m,
speed_mps=speed_mps, speed_mps=speed_mps,
heading_deg=heading_deg, heading_deg=heading_deg,
source=source if source is not None else 0, source=source_value,
battery_pct=battery_pct, battery_pct=battery_pct,
device_time=device_time or datetime.now(), device_time=device_time or datetime.now(),
) )
@@ -156,5 +158,25 @@ class LocationService(DatabaseServiceBase):
finally: finally:
await db_session.close() 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 实例 # 创建全局 LocationService 实例
location_service = LocationService() location_service = LocationService()