import logging from typing import Optional from fastapi import APIRouter, HTTPException, Query from services.offline_audio_cache import offline_audio_cache from api.mqtt_models import ( GPSQueryRequest, VolumeRequest, OTARequest, NFCNoticeRequest, NFCListenRequest, NFCUnreadRequest, NFCBindRequest, CommandResponse, DeviceResponseData, DeviceStatusResponse, ) from handlers.mqtt_handler import TalkingQMQTTService logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/mqtt", tags=["MQTT 服务"]) async def _get_service() -> TalkingQMQTTService: service = await TalkingQMQTTService.get_instance() if service is None: raise HTTPException(status_code=503, detail="MQTT 服务未初始化") return service @router.post("/gps", response_model=CommandResponse, summary="GPS位置查询") async def query_gps(req: GPSQueryRequest): service = await _get_service() msg_id = await service.send_gps_query(req.device_id) return CommandResponse(msg_id=msg_id, device_id=req.device_id) @router.post("/volume", response_model=CommandResponse, summary="音量调节") async def set_volume(req: VolumeRequest): service = await _get_service() msg_id = await service.send_volume_command(req.device_id, req.level) return CommandResponse(msg_id=msg_id, device_id=req.device_id) @router.post("/ota", response_model=CommandResponse, summary="OTA升级") async def start_ota(req: OTARequest): service = await _get_service() msg_id = await service.send_ota_command(req.device_id, req.url, req.version) return CommandResponse(msg_id=msg_id, device_id=req.device_id) @router.post("/nfc/notice", response_model=CommandResponse, summary="NFC留言下发提示") async def send_nfc_notice(req: NFCNoticeRequest): service = await _get_service() msg_id = await service.send_nfc_notice(req.device_id, req.url) return CommandResponse(msg_id=msg_id, device_id=req.device_id) @router.post("/nfc/listen", response_model=CommandResponse, summary="NFC收听留言") async def nfc_listen(req: NFCListenRequest): service = await _get_service() topic = f"device/{req.device_id}/event" payload = { "msg_id": "005", "params": {"uuid": req.uuid} } await service._publish(topic, payload) return CommandResponse(msg_id="005", device_id=req.device_id) @router.post("/nfc/unread", response_model=CommandResponse, summary="设置NFC未读留言") async def set_nfc_unread(req: NFCUnreadRequest): await offline_audio_cache.add_audio_url(req.device_id, req.url) return CommandResponse(msg_id="", device_id=req.device_id, message="已设置未读留言") @router.delete("/nfc/unread/{device_id}", response_model=CommandResponse, summary="清除NFC未读留言定时推送") async def clear_nfc_unread(device_id: str): await offline_audio_cache.clear_audio_urls(device_id) return CommandResponse(msg_id="", device_id=device_id, message="已清除未读留言") @router.post("/nfc/bind", response_model=CommandResponse, summary="NFC绑定卡片") async def bind_nfc(req: NFCBindRequest): service = await _get_service() msg_id = await service.send_bind_nfc_command(req.device_id, req.uuid) return CommandResponse(msg_id=msg_id, device_id=req.device_id) # @router.get("/nfc/unread", summary="查询所有未读留言设备列表") # async def get_nfc_unread_devices(): # service = await _get_service() # devices = service.get_nfc_unread_devices() # return {"count": len(devices), "devices": devices} # @router.get("/device/{device_id}/status", response_model=DeviceStatusResponse, summary="查询设备在线状态") # async def get_device_status(device_id: str): # service = await _get_service() # online = service.is_device_online(device_id) # last_seen = service.get_device_last_seen(device_id) # return DeviceStatusResponse(device_id=device_id, online=online, last_seen=last_seen) # @router.get("/device/{device_id}/responses", summary="查询设备上报记录") # async def get_device_responses( # device_id: str, # msg_id: Optional[str] = Query(None, description="按msg_id过滤"), # limit: int = Query(20, ge=1, le=100, description="返回条数"), # ): # service = await _get_service() # responses = service.get_device_responses(device_id, msg_id=msg_id, limit=limit) # return {"device_id": device_id, "count": len(responses), "responses": responses} # @router.get("/device/{device_id}/wait_response", summary="等待设备响应(同步阻塞)") # async def wait_device_response( # device_id: str, # msg_id: str = Query(..., description="等待的消息ID"), # timeout: float = Query(10.0, ge=1.0, le=60.0, description="超时时间(秒)"), # ): # service = await _get_service() # response = service.wait_for_response(device_id, msg_id, timeout=timeout) # if response is None: # raise HTTPException(status_code=408, detail=f"等待设备 {device_id} 的 msg_id={msg_id} 响应超时") # return response