ams_history.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. """API routes for AMS sensor history."""
  2. from datetime import datetime, timedelta
  3. from fastapi import APIRouter, Depends, Query
  4. from pydantic import BaseModel
  5. from sqlalchemy import and_, func, select
  6. from sqlalchemy.ext.asyncio import AsyncSession
  7. from backend.app.core.database import get_db
  8. from backend.app.models.ams_history import AMSSensorHistory
  9. router = APIRouter(prefix="/ams-history", tags=["ams-history"])
  10. class AMSHistoryPoint(BaseModel):
  11. recorded_at: datetime
  12. humidity: float | None
  13. humidity_raw: float | None
  14. temperature: float | None
  15. class AMSHistoryResponse(BaseModel):
  16. printer_id: int
  17. ams_id: int
  18. data: list[AMSHistoryPoint]
  19. min_humidity: float | None
  20. max_humidity: float | None
  21. avg_humidity: float | None
  22. min_temperature: float | None
  23. max_temperature: float | None
  24. avg_temperature: float | None
  25. @router.get("/{printer_id}/{ams_id}", response_model=AMSHistoryResponse)
  26. async def get_ams_history(
  27. printer_id: int,
  28. ams_id: int,
  29. hours: int = Query(default=24, ge=1, le=168, description="Hours of history (1-168)"),
  30. db: AsyncSession = Depends(get_db),
  31. ):
  32. """Get AMS sensor history for a specific printer and AMS unit."""
  33. since = datetime.now() - timedelta(hours=hours)
  34. # Get data points
  35. result = await db.execute(
  36. select(AMSSensorHistory)
  37. .where(
  38. and_(
  39. AMSSensorHistory.printer_id == printer_id,
  40. AMSSensorHistory.ams_id == ams_id,
  41. AMSSensorHistory.recorded_at >= since,
  42. )
  43. )
  44. .order_by(AMSSensorHistory.recorded_at)
  45. )
  46. records = result.scalars().all()
  47. # Calculate stats
  48. stats_result = await db.execute(
  49. select(
  50. func.min(AMSSensorHistory.humidity).label("min_humidity"),
  51. func.max(AMSSensorHistory.humidity).label("max_humidity"),
  52. func.avg(AMSSensorHistory.humidity).label("avg_humidity"),
  53. func.min(AMSSensorHistory.temperature).label("min_temp"),
  54. func.max(AMSSensorHistory.temperature).label("max_temp"),
  55. func.avg(AMSSensorHistory.temperature).label("avg_temp"),
  56. ).where(
  57. and_(
  58. AMSSensorHistory.printer_id == printer_id,
  59. AMSSensorHistory.ams_id == ams_id,
  60. AMSSensorHistory.recorded_at >= since,
  61. )
  62. )
  63. )
  64. stats = stats_result.one()
  65. return AMSHistoryResponse(
  66. printer_id=printer_id,
  67. ams_id=ams_id,
  68. data=[
  69. AMSHistoryPoint(
  70. recorded_at=r.recorded_at,
  71. humidity=r.humidity,
  72. humidity_raw=r.humidity_raw,
  73. temperature=r.temperature,
  74. )
  75. for r in records
  76. ],
  77. min_humidity=stats.min_humidity,
  78. max_humidity=stats.max_humidity,
  79. avg_humidity=round(stats.avg_humidity, 1) if stats.avg_humidity else None,
  80. min_temperature=stats.min_temp,
  81. max_temperature=stats.max_temp,
  82. avg_temperature=round(stats.avg_temp, 1) if stats.avg_temp else None,
  83. )
  84. @router.delete("/{printer_id}")
  85. async def delete_old_history(
  86. printer_id: int,
  87. days: int = Query(default=30, ge=1, le=365, description="Delete data older than X days"),
  88. db: AsyncSession = Depends(get_db),
  89. ):
  90. """Delete old AMS history data for a printer."""
  91. cutoff = datetime.now() - timedelta(days=days)
  92. result = await db.execute(
  93. select(func.count(AMSSensorHistory.id)).where(
  94. and_(
  95. AMSSensorHistory.printer_id == printer_id,
  96. AMSSensorHistory.recorded_at < cutoff,
  97. )
  98. )
  99. )
  100. count = result.scalar()
  101. await db.execute(
  102. AMSSensorHistory.__table__.delete().where(
  103. and_(
  104. AMSSensorHistory.printer_id == printer_id,
  105. AMSSensorHistory.recorded_at < cutoff,
  106. )
  107. )
  108. )
  109. await db.commit()
  110. return {"deleted": count, "message": f"Deleted {count} records older than {days} days"}