diff --git a/backend/main.py b/backend/main.py index 3c4cb6f..cf8b9b4 100644 --- a/backend/main.py +++ b/backend/main.py @@ -251,7 +251,7 @@ app.add_middleware( ) # Gate control -async def trigger_gate(): +async def trigger_gate(source: str = "api"): """Trigger the gate relay""" try: settings = app.state.current_settings @@ -268,7 +268,7 @@ async def trigger_gate(): # Log event timestamp = datetime.now().isoformat() - await add_event(timestamp, "gate triggered", "api") + await add_event(timestamp, "gate triggered", source) # Wait for specified duration await asyncio.sleep(trigger_duration) @@ -282,7 +282,7 @@ async def trigger_gate(): logger.error(f"Failed to trigger gate: {e}", exc_info=True) # Log failure timestamp = datetime.now().isoformat() - await add_event(timestamp, "gate trigger failed", "api", False) + await add_event(timestamp, "gate trigger failed", source, False) return False last_open_time = None @@ -437,6 +437,10 @@ async def cleanup_old_events(): "DELETE FROM events WHERE timestamp < ?", (cutoff_date,) ) + await db.execute( + "DELETE FROM gate_status WHERE timestamp < ?", + (cutoff_date,) + ) await db.commit() logger.info(f"Cleaned up {count} events older than {cutoff_date}") @@ -462,7 +466,7 @@ async def handle_mqtt_command(should_open: bool): status_pin = settings.gpio.statusPin if should_open != (GPIO.input(status_pin) == GPIO.HIGH): - await trigger_gate() + await trigger_gate("mqtt") except Exception as e: logger.error(f"Error handling MQTT command: {e}") @@ -471,17 +475,40 @@ async def handle_mqtt_command(should_open: bool): async def trigger(): """Trigger the gate""" try: - success = await trigger_gate() - timestamp = datetime.now().isoformat() - - # Get current status after trigger - settings = app.state.current_settings or Settings() - current_status = GPIO.input(settings.gpio.statusPin) == GPIO.HIGH - - return {"success": success, "timestamp": timestamp, "isOpen": current_status} + result = await trigger_gate("api") + if result: + status = await get_status() + return {"success": True, "isOpen": status["isOpen"]} + return {"success": False} except Exception as e: - logger.error("Error triggering gate", exc_info=True) - raise HTTPException(status_code=500, detail="Failed to trigger gate") + logger.error(f"Failed to trigger gate: {e}", exc_info=True) + return {"success": False} + +@app.post("/api/events/clear") +async def clear_events(): + """Clear all events from the database except the latest gate status""" + try: + async with DBConnection() as db: + # Delete all events + await db.execute("DELETE FROM events") + + # Keep only the most recent gate status + await db.execute(""" + DELETE FROM gate_status + WHERE timestamp NOT IN ( + SELECT timestamp + FROM gate_status + ORDER BY timestamp DESC + LIMIT 1 + ) + """) + await db.commit() + + logger.info("Event logs cleared (preserved latest gate status)") + return {"success": True} + except Exception as e: + logger.error(f"Failed to clear events: {e}", exc_info=True) + return {"success": False} @app.get("/api/status") async def get_status(): @@ -491,6 +518,8 @@ async def get_status(): # HIGH (3.3V) means gate is open (receiving voltage) # LOW (0V) means gate is closed (no voltage) is_open = GPIO.input(settings.gpio.statusPin) == GPIO.HIGH + + # Update state machine gate_status.update(is_open) return {"isOpen": gate_status.is_open, "lastChanged": gate_status.last_changed} diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 9967251..609e23c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -198,7 +198,29 @@ function App() { {/* Recent Events */}