add mqtt and device test
This commit is contained in:
@@ -4,6 +4,7 @@ from api.roles import router as roles_router
|
||||
from api.auth import router as auth_router
|
||||
from api.device_control import router as device_control_router
|
||||
from api.ota import router as ota_router # 新增OTA路由
|
||||
from api.mqtt_router import router as mqtt_router # 新增MQTT路由
|
||||
|
||||
api_router = APIRouter()
|
||||
api_router.include_router(websocket_router, tags=["WebSocket"])
|
||||
@@ -11,4 +12,5 @@ api_router.include_router(roles_router, tags=["Roles"])
|
||||
api_router.include_router(auth_router, tags=["Auth"])
|
||||
api_router.include_router(device_control_router, tags=["Device Control"])
|
||||
api_router.include_router(ota_router, tags=["OTA"]) # 注册OTA路由
|
||||
api_router.include_router(mqtt_router, tags=["MQTT"]) # 注册MQTT路由
|
||||
|
||||
|
||||
57
talkingq-url/api/mqtt_models.py
Normal file
57
talkingq-url/api/mqtt_models.py
Normal file
@@ -0,0 +1,57 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class GPSQueryRequest(BaseModel):
|
||||
device_id: str = Field(..., description="设备ID,如 TalkingQ_001")
|
||||
|
||||
|
||||
class VolumeRequest(BaseModel):
|
||||
device_id: str = Field(..., description="设备ID")
|
||||
level: int = Field(..., ge=0, le=100, description="音量等级 0-100")
|
||||
|
||||
|
||||
class OTARequest(BaseModel):
|
||||
device_id: str = Field(..., description="设备ID")
|
||||
url: str = Field(..., description="固件下载地址")
|
||||
version: str = Field(..., description="目标版本号")
|
||||
|
||||
|
||||
class NFCNoticeRequest(BaseModel):
|
||||
device_id: str = Field(..., description="设备ID")
|
||||
url: str = Field(..., description="提示音地址")
|
||||
|
||||
|
||||
class NFCListenRequest(BaseModel):
|
||||
device_id: str = Field(..., description="设备ID")
|
||||
uuid: str = Field(..., description="NFC卡片UUID")
|
||||
|
||||
|
||||
class NFCUnreadRequest(BaseModel):
|
||||
device_id: str = Field(..., description="设备ID")
|
||||
url: str = Field(..., description="未读留言音频地址")
|
||||
|
||||
|
||||
class NFCBindRequest(BaseModel):
|
||||
device_id: str = Field(..., description="设备ID")
|
||||
uuid: str = Field(..., description="NFC卡片UUID")
|
||||
|
||||
|
||||
class CommandResponse(BaseModel):
|
||||
code: int = 0
|
||||
message: str = "success"
|
||||
msg_id: str = Field(..., description="消息ID")
|
||||
device_id: str = Field(..., description="设备ID")
|
||||
|
||||
|
||||
class DeviceResponseData(BaseModel):
|
||||
msg_id: str
|
||||
status: Optional[str] = None
|
||||
data: Optional[dict] = None
|
||||
timestamp: Optional[float] = None
|
||||
|
||||
|
||||
class DeviceStatusResponse(BaseModel):
|
||||
device_id: str
|
||||
online: bool
|
||||
last_seen: Optional[float] = None
|
||||
126
talkingq-url/api/mqtt_router.py
Normal file
126
talkingq-url/api/mqtt_router.py
Normal file
@@ -0,0 +1,126 @@
|
||||
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
|
||||
Reference in New Issue
Block a user