Compare commits
5 Commits
1b5fee77c2
...
c23d99726d
Author | SHA1 | Date | |
---|---|---|---|
c23d99726d | |||
a83f0d0937 | |||
38ab26a659 | |||
d923a4ac61 | |||
dd53b40909 |
50
server.py
50
server.py
@@ -4,6 +4,7 @@ from aiohttp import web
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import io
|
import io
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
import torch.nn.functional as F
|
import torch.nn.functional as F
|
||||||
@@ -25,6 +26,9 @@ MODEL_PATH = 'garage_door_cnn.pth'
|
|||||||
CLASS_NAMES = ['closed', 'open'] # From training, sorted alphabetically
|
CLASS_NAMES = ['closed', 'open'] # From training, sorted alphabetically
|
||||||
POLL_INTERVAL_SECONDS = 10
|
POLL_INTERVAL_SECONDS = 10
|
||||||
REQUEST_TIMEOUT_SECONDS = 5
|
REQUEST_TIMEOUT_SECONDS = 5
|
||||||
|
UNSURE_CONFIDENCE_THRESHOLD = 0.97
|
||||||
|
PREDICTION_HISTORY = []
|
||||||
|
PREDICTION_HISTORY_MAX_LENGTH = 3
|
||||||
|
|
||||||
# --- Model Inference ---
|
# --- Model Inference ---
|
||||||
def get_prediction(model, image_bytes, device):
|
def get_prediction(model, image_bytes, device):
|
||||||
@@ -71,13 +75,46 @@ async def monitor_garage_door(app):
|
|||||||
if result:
|
if result:
|
||||||
prediction, confidence = result
|
prediction, confidence = result
|
||||||
logging.debug(f"Garage door status: {prediction} (confidence: {confidence:.4f})")
|
logging.debug(f"Garage door status: {prediction} (confidence: {confidence:.4f})")
|
||||||
|
|
||||||
|
# Update prediction history
|
||||||
|
if confidence >= UNSURE_CONFIDENCE_THRESHOLD:
|
||||||
|
PREDICTION_HISTORY.append(prediction)
|
||||||
|
else:
|
||||||
|
PREDICTION_HISTORY.append('unknown')
|
||||||
|
|
||||||
|
# Trim history if it's too long
|
||||||
|
if len(PREDICTION_HISTORY) > PREDICTION_HISTORY_MAX_LENGTH:
|
||||||
|
PREDICTION_HISTORY.pop(0)
|
||||||
|
|
||||||
|
if confidence < UNSURE_CONFIDENCE_THRESHOLD:
|
||||||
|
# Sanitize timestamp for use in filename
|
||||||
|
timestamp = datetime.now().isoformat().replace(':', '-')
|
||||||
|
filename = f"{timestamp}.jpg"
|
||||||
|
|
||||||
|
# Construct path and save file
|
||||||
|
unsure_dir = os.path.join('data', 'unsure', prediction)
|
||||||
|
os.makedirs(unsure_dir, exist_ok=True)
|
||||||
|
filepath = os.path.join(unsure_dir, filename)
|
||||||
|
|
||||||
|
with open(filepath, 'wb') as f:
|
||||||
|
f.write(image_bytes)
|
||||||
|
|
||||||
|
logging.info(f"Low confidence prediction: {prediction} ({confidence:.4f}). Saved for review: {filepath}")
|
||||||
else:
|
else:
|
||||||
logging.error(f"Failed to fetch image. Status: {response.status}, Reason: {response.reason}")
|
logging.error(f"Failed to fetch image. Status: {response.status}, Reason: {response.reason}")
|
||||||
|
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
logging.warning("Request to camera timed out.")
|
logging.warning("Request to camera timed out.")
|
||||||
|
|
||||||
|
PREDICTION_HISTORY.append('unknown')
|
||||||
|
if len(PREDICTION_HISTORY) > PREDICTION_HISTORY_MAX_LENGTH:
|
||||||
|
PREDICTION_HISTORY.pop(0)
|
||||||
except aiohttp.ClientError as e:
|
except aiohttp.ClientError as e:
|
||||||
logging.error(f"Client error during image fetch: {e}")
|
logging.error(f"Client error during image fetch: {e}")
|
||||||
|
|
||||||
|
PREDICTION_HISTORY.append('unknown')
|
||||||
|
if len(PREDICTION_HISTORY) > PREDICTION_HISTORY_MAX_LENGTH:
|
||||||
|
PREDICTION_HISTORY.pop(0)
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
logging.info("Monitoring task cancelled.")
|
logging.info("Monitoring task cancelled.")
|
||||||
break
|
break
|
||||||
@@ -92,6 +129,18 @@ async def handle_root(request):
|
|||||||
"""Handler for the root GET request."""
|
"""Handler for the root GET request."""
|
||||||
return web.Response(text="hello world")
|
return web.Response(text="hello world")
|
||||||
|
|
||||||
|
async def handle_state(request):
|
||||||
|
"""Handler for the /state GET request."""
|
||||||
|
state = "unknown"
|
||||||
|
|
||||||
|
if len(PREDICTION_HISTORY) == PREDICTION_HISTORY_MAX_LENGTH:
|
||||||
|
if all(s == "open" for s in PREDICTION_HISTORY):
|
||||||
|
state = "open"
|
||||||
|
elif all(s == "closed" for s in PREDICTION_HISTORY):
|
||||||
|
state = "closed"
|
||||||
|
|
||||||
|
return web.Response(text=state)
|
||||||
|
|
||||||
async def on_startup(app):
|
async def on_startup(app):
|
||||||
"""Actions to perform on application startup."""
|
"""Actions to perform on application startup."""
|
||||||
# Set up device
|
# Set up device
|
||||||
@@ -126,6 +175,7 @@ async def on_cleanup(app):
|
|||||||
def main():
|
def main():
|
||||||
app = web.Application()
|
app = web.Application()
|
||||||
app.router.add_get('/', handle_root)
|
app.router.add_get('/', handle_root)
|
||||||
|
app.router.add_get('/state', handle_state)
|
||||||
app.on_startup.append(on_startup)
|
app.on_startup.append(on_startup)
|
||||||
app.on_cleanup.append(on_cleanup)
|
app.on_cleanup.append(on_cleanup)
|
||||||
web.run_app(app, port=8081)
|
web.run_app(app, port=8081)
|
||||||
|
Reference in New Issue
Block a user