Files
ESP32_GDEY042T81_server/api/devices.py
jeremygan2021 a2682dc040 first commit
2025-11-16 17:21:25 +08:00

183 lines
5.4 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List, Optional
from datetime import datetime
import secrets
from database import get_db
from schemas import Device as DeviceSchema, DeviceCreate, DeviceUpdate, BootstrapResponse
from models import Device as DeviceModel
from database import Content as ContentModel
from mqtt_manager import mqtt_manager
router = APIRouter(
prefix="/api/devices",
tags=["devices"]
)
@router.post("/", response_model=DeviceSchema, status_code=status.HTTP_201_CREATED)
async def create_device(device: DeviceCreate, db: Session = Depends(get_db)):
"""
注册新设备
"""
# 检查设备ID是否已存在
db_device = db.query(DeviceModel).filter(DeviceModel.device_id == device.device_id).first()
if db_device:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="设备ID已存在"
)
# 创建新设备
secret = device.secret if device.secret else secrets.token_urlsafe(32)
db_device = DeviceModel(
device_id=device.device_id,
secret=secret,
name=device.name,
scene=device.scene
)
db.add(db_device)
db.commit()
db.refresh(db_device)
# 订阅设备状态
mqtt_manager.subscribe_to_device_status(device.device_id)
return db_device
@router.get("/", response_model=List[DeviceSchema])
async def list_devices(
skip: int = 0,
limit: int = 100,
scene: Optional[str] = None,
is_active: Optional[bool] = None,
db: Session = Depends(get_db)
):
"""
获取设备列表
"""
query = db.query(DeviceModel)
if scene:
query = query.filter(DeviceModel.scene == scene)
if is_active is not None:
query = query.filter(DeviceModel.is_active == is_active)
devices = query.offset(skip).limit(limit).all()
return devices
@router.get("/{device_id}", response_model=DeviceSchema)
async def get_device(device_id: str, db: Session = Depends(get_db)):
"""
获取设备详情
"""
device = db.query(DeviceModel).filter(DeviceModel.device_id == device_id).first()
if not device:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="设备不存在"
)
return device
@router.put("/{device_id}", response_model=DeviceSchema)
async def update_device(
device_id: str,
device_update: DeviceUpdate,
db: Session = Depends(get_db)
):
"""
更新设备信息
"""
device = db.query(DeviceModel).filter(DeviceModel.device_id == device_id).first()
if not device:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="设备不存在"
)
# 更新设备信息
update_data = device_update.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(device, field, value)
device.updated_at = datetime.utcnow()
db.commit()
db.refresh(device)
return device
@router.delete("/{device_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_device(device_id: str, db: Session = Depends(get_db)):
"""
删除设备
"""
device = db.query(DeviceModel).filter(DeviceModel.device_id == device_id).first()
if not device:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="设备不存在"
)
# 取消订阅设备状态
mqtt_manager.unsubscribe_from_device_status(device_id)
db.delete(device)
db.commit()
@router.get("/{device_id}/bootstrap", response_model=BootstrapResponse)
async def device_bootstrap(device_id: str, db: Session = Depends(get_db)):
"""
设备启动获取当前版本信息
"""
device = db.query(DeviceModel).filter(DeviceModel.device_id == device_id).first()
if not device:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="设备不存在"
)
# 更新设备最后在线时间
device.last_online = datetime.utcnow()
db.commit()
# 获取最新的活跃内容
latest_content = db.query(ContentModel).filter(
ContentModel.device_id == device_id,
ContentModel.is_active == True
).order_by(ContentModel.version.desc()).first()
response = BootstrapResponse(
device_id=device_id,
timezone=latest_content.timezone if latest_content else "Asia/Shanghai",
time_format=latest_content.time_format if latest_content else "%Y-%m-%d %H:%M"
)
if latest_content:
response.content_version = latest_content.version
response.last_updated = latest_content.created_at
return response
@router.get("/{device_id}/status")
async def get_device_status(device_id: str, db: Session = Depends(get_db)):
"""
获取设备状态
"""
device = db.query(DeviceModel).filter(DeviceModel.device_id == device_id).first()
if not device:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="设备不存在"
)
return {
"device_id": device_id,
"name": device.name,
"scene": device.scene,
"is_active": device.is_active,
"last_online": device.last_online,
"created_at": device.created_at,
"updated_at": device.updated_at
}