# server/camera_endpoint.py # Add these models and endpoint to the server's main.py alongside the existing BLE endpoints. # Requires: camera_records table (see migrations/004_camera_records.sql) # # IMPORTANT: Before deploying, verify the HMAC message format in verify_device_hmac # matches what the firmware computes: # HMAC-SHA256(secret, f"{device_id}:{timestamp}:{sha256_hex(body)}") # Headers expected: X-Device-Id, X-Timestamp, X-HMAC-Signature import sqlite3 from typing import List from fastapi import Depends from pydantic import BaseModel class CameraRecord(BaseModel): period_start: int period_end: int entries: int exits: int class CameraEventsRequest(BaseModel): location_id: str records: List[CameraRecord] class CameraEventsResponse(BaseModel): status: str accepted: int # Add this endpoint to your FastAPI app (alongside receive_batch_events): # # @app.post("/api/v1/camera/events/batch", response_model=CameraEventsResponse) # async def receive_camera_events( # batch: CameraEventsRequest, # device_id: str = Depends(verify_device_hmac), # db: sqlite3.Connection = Depends(get_db), # ): def receive_camera_events_impl( batch: CameraEventsRequest, device_id: str, db: sqlite3.Connection, ) -> CameraEventsResponse: """Receive hourly camera entry/exit records; idempotent on (device_id, period_start).""" cursor = db.cursor() accepted = 0 for record in batch.records: try: cursor.execute( """INSERT INTO camera_records (device_id, location_id, period_start, period_end, entries, exits) VALUES (?, ?, ?, ?, ?, ?)""", ( device_id, batch.location_id, record.period_start, record.period_end, record.entries, record.exits, ), ) accepted += 1 except sqlite3.IntegrityError: pass # duplicate (device_id, period_start) — idempotent db.commit() return CameraEventsResponse(status="ok", accepted=accepted)