feat(Q5): package event queries and tracker state machine

Add insert/get/update queries for package_events table, and
notification content for PACKAGE_DELIVERED and PACKAGE_REMINDER events.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aaron D. Lee 2026-04-03 18:47:40 -04:00
parent 31757f410a
commit cdc13e05f6
3 changed files with 53 additions and 0 deletions

View File

@ -0,0 +1,21 @@
import time
import pytest
from vigilar.storage.queries import insert_package_event, get_active_packages, update_package_status
def test_insert_package_event(test_db):
pkg_id = insert_package_event(test_db, camera_id="front", detected_at=time.time(), status="PRESENT")
assert pkg_id > 0
def test_get_active_packages(test_db):
now = time.time()
insert_package_event(test_db, camera_id="front", detected_at=now, status="PRESENT")
insert_package_event(test_db, camera_id="back", detected_at=now, status="COLLECTED")
active = get_active_packages(test_db)
assert len(active) == 1
assert active[0]["camera_id"] == "front"
def test_update_package_status(test_db):
pkg_id = insert_package_event(test_db, camera_id="front", detected_at=time.time(), status="PRESENT")
update_package_status(test_db, pkg_id, "REMINDED", reminded_at=time.time())
active = get_active_packages(test_db)
assert active[0]["status"] == "REMINDED"

View File

@ -20,6 +20,8 @@ _CONTENT_MAP: dict[str, tuple[str, str]] = {
EventType.UNKNOWN_VEHICLE_DETECTED: ("Unknown Vehicle", "Unknown vehicle on {source}"),
EventType.POWER_LOSS: ("Power Alert", "UPS on battery"),
EventType.LOW_BATTERY: ("Battery Critical", "UPS battery low"),
EventType.PACKAGE_DELIVERED: ("Package Delivered", "Package delivered — {source}"),
EventType.PACKAGE_REMINDER: ("Package Reminder", "Package still on porch — {source}"),
}

View File

@ -516,3 +516,33 @@ def get_training_images(
.order_by(desc(pet_training_images.c.created_at))
).fetchall()
return [dict(r._mapping) for r in rows]
# --- Package Events ---
def insert_package_event(
engine: Engine, camera_id: str, detected_at: float, status: str,
crop_path: str | None = None, event_id: int | None = None,
) -> int:
from vigilar.storage.schema import package_events
with engine.begin() as conn:
result = conn.execute(package_events.insert().values(
camera_id=camera_id, detected_at=detected_at, status=status,
crop_path=crop_path, event_id=event_id))
return result.inserted_primary_key[0]
def get_active_packages(engine: Engine) -> list[dict[str, Any]]:
from vigilar.storage.schema import package_events
with engine.connect() as conn:
rows = conn.execute(
select(package_events).where(package_events.c.status.in_(["PRESENT", "REMINDED"]))
.order_by(desc(package_events.c.detected_at))).mappings().all()
return [dict(r) for r in rows]
def update_package_status(engine: Engine, package_id: int, status: str, **kwargs: Any) -> None:
from vigilar.storage.schema import package_events
with engine.begin() as conn:
conn.execute(package_events.update().where(package_events.c.id == package_id)
.values(status=status, **kwargs))