Compare commits
4 Commits
c23d99726d
...
16709de883
Author | SHA1 | Date | |
---|---|---|---|
16709de883 | |||
59b02e18e9 | |||
de4c99bc1d | |||
914e8f9ce8 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -143,6 +143,7 @@ sdkconfig.old
|
|||||||
|
|
||||||
data/
|
data/
|
||||||
secrets.py
|
secrets.py
|
||||||
|
mysecrets.py
|
||||||
secrets.h
|
secrets.h
|
||||||
*.bin
|
*.bin
|
||||||
output.*
|
output.*
|
||||||
|
0
mysecrets.py.example
Normal file
0
mysecrets.py.example
Normal file
37
requirements.txt
Normal file
37
requirements.txt
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
aiohappyeyeballs==2.6.1
|
||||||
|
aiohttp==3.12.15
|
||||||
|
aiosignal==1.4.0
|
||||||
|
attrs==25.3.0
|
||||||
|
filelock==3.18.0
|
||||||
|
frozenlist==1.7.0
|
||||||
|
fsspec==2025.7.0
|
||||||
|
idna==3.10
|
||||||
|
jinja2==3.1.6
|
||||||
|
markupsafe==3.0.2
|
||||||
|
mpmath==1.3.0
|
||||||
|
multidict==6.6.3
|
||||||
|
networkx==3.5
|
||||||
|
numpy==2.3.2
|
||||||
|
nvidia-cublas-cu12==12.6.4.1
|
||||||
|
nvidia-cuda-cupti-cu12==12.6.80
|
||||||
|
nvidia-cuda-nvrtc-cu12==12.6.77
|
||||||
|
nvidia-cuda-runtime-cu12==12.6.77
|
||||||
|
nvidia-cudnn-cu12==9.5.1.17
|
||||||
|
nvidia-cufft-cu12==11.3.0.4
|
||||||
|
nvidia-cufile-cu12==1.11.1.6
|
||||||
|
nvidia-curand-cu12==10.3.7.77
|
||||||
|
nvidia-cusolver-cu12==11.7.1.2
|
||||||
|
nvidia-cusparse-cu12==12.5.4.2
|
||||||
|
nvidia-cusparselt-cu12==0.6.3
|
||||||
|
nvidia-nccl-cu12==2.26.2
|
||||||
|
nvidia-nvjitlink-cu12==12.6.85
|
||||||
|
nvidia-nvtx-cu12==12.6.77
|
||||||
|
pillow==11.3.0
|
||||||
|
propcache==0.3.2
|
||||||
|
setuptools==80.9.0
|
||||||
|
sympy==1.14.0
|
||||||
|
torch==2.7.1
|
||||||
|
torchvision==0.22.1
|
||||||
|
triton==3.3.1
|
||||||
|
typing-extensions==4.14.1
|
||||||
|
yarl==1.20.1
|
59
server.py
59
server.py
@@ -1,8 +1,13 @@
|
|||||||
|
import os, logging
|
||||||
|
DEBUG = os.environ.get('DEBUG')
|
||||||
|
logging.basicConfig(
|
||||||
|
format='[%(asctime)s] %(levelname)s %(module)s/%(funcName)s - %(message)s',
|
||||||
|
level=logging.DEBUG if DEBUG else logging.INFO)
|
||||||
|
logging.getLogger('aiohttp').setLevel(logging.DEBUG if DEBUG else logging.WARNING)
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import io
|
import io
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
@@ -11,16 +16,13 @@ import torch.nn.functional as F
|
|||||||
from torchvision import transforms
|
from torchvision import transforms
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
import mysecrets
|
||||||
from model import (CropLowerRightTriangle, GarageDoorCNN, TRIANGLE_CROP_WIDTH,
|
from model import (CropLowerRightTriangle, GarageDoorCNN, TRIANGLE_CROP_WIDTH,
|
||||||
TRIANGLE_CROP_HEIGHT, RESIZE_DIM)
|
TRIANGLE_CROP_HEIGHT, RESIZE_DIM)
|
||||||
|
|
||||||
# --- Configuration ---
|
# --- Configuration ---
|
||||||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
BLUEIRIS_KEY = os.getenv('BLUEIRIS_KEY')
|
|
||||||
if not BLUEIRIS_KEY:
|
|
||||||
raise ValueError("BLUEIRIS_KEY environment variable not set.")
|
|
||||||
|
|
||||||
CAMERA_URL = "http://cameras.dns.t0.vc/image/SE-S?&w=9999&decode=1"
|
CAMERA_URL = "http://cameras.dns.t0.vc/image/SE-S?&w=9999&decode=1"
|
||||||
MODEL_PATH = 'garage_door_cnn.pth'
|
MODEL_PATH = 'garage_door_cnn.pth'
|
||||||
CLASS_NAMES = ['closed', 'open'] # From training, sorted alphabetically
|
CLASS_NAMES = ['closed', 'open'] # From training, sorted alphabetically
|
||||||
@@ -29,6 +31,7 @@ REQUEST_TIMEOUT_SECONDS = 5
|
|||||||
UNSURE_CONFIDENCE_THRESHOLD = 0.97
|
UNSURE_CONFIDENCE_THRESHOLD = 0.97
|
||||||
PREDICTION_HISTORY = []
|
PREDICTION_HISTORY = []
|
||||||
PREDICTION_HISTORY_MAX_LENGTH = 3
|
PREDICTION_HISTORY_MAX_LENGTH = 3
|
||||||
|
PREVIOUS_STATE = "unknown"
|
||||||
|
|
||||||
# --- Model Inference ---
|
# --- Model Inference ---
|
||||||
def get_prediction(model, image_bytes, device):
|
def get_prediction(model, image_bytes, device):
|
||||||
@@ -62,7 +65,7 @@ async def monitor_garage_door(app):
|
|||||||
session = app['client_session']
|
session = app['client_session']
|
||||||
model = app['model']
|
model = app['model']
|
||||||
device = app['device']
|
device = app['device']
|
||||||
headers = {'Authorization': 'Basic ' + BLUEIRIS_KEY}
|
headers = {'Authorization': 'Basic ' + mysecrets.BLUEIRIS_KEY}
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@@ -124,21 +127,44 @@ async def monitor_garage_door(app):
|
|||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
|
|
||||||
|
async def monitor_state_transitions(app):
|
||||||
|
"""Periodically checks for state transitions and logs them."""
|
||||||
|
global PREVIOUS_STATE
|
||||||
|
logging.info("Starting state transition monitoring task.")
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
current_state = get_derived_state()
|
||||||
|
if current_state != "unknown" and current_state != PREVIOUS_STATE:
|
||||||
|
logging.info(f"State transitioned from '{PREVIOUS_STATE}' to '{current_state}'.")
|
||||||
|
PREVIOUS_STATE = current_state
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
logging.info("State transition monitoring task cancelled.")
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"An unexpected error occurred in the state monitoring task: {e}", exc_info=True)
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
|
|
||||||
# --- Web Server ---
|
# --- Web Server ---
|
||||||
|
def get_derived_state():
|
||||||
|
"""Derives the state from the prediction history."""
|
||||||
|
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 state
|
||||||
|
|
||||||
|
|
||||||
async def handle_root(request):
|
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):
|
async def handle_state(request):
|
||||||
"""Handler for the /state GET request."""
|
"""Handler for the /state GET request."""
|
||||||
state = "unknown"
|
state = get_derived_state()
|
||||||
|
|
||||||
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)
|
return web.Response(text=state)
|
||||||
|
|
||||||
async def on_startup(app):
|
async def on_startup(app):
|
||||||
@@ -160,13 +186,16 @@ async def on_startup(app):
|
|||||||
|
|
||||||
# Start background task
|
# Start background task
|
||||||
app['monitor_task'] = asyncio.create_task(monitor_garage_door(app))
|
app['monitor_task'] = asyncio.create_task(monitor_garage_door(app))
|
||||||
|
app['state_monitor_task'] = asyncio.create_task(monitor_state_transitions(app))
|
||||||
|
|
||||||
async def on_cleanup(app):
|
async def on_cleanup(app):
|
||||||
"""Actions to perform on application cleanup."""
|
"""Actions to perform on application cleanup."""
|
||||||
logging.info("Cleaning up...")
|
logging.info("Cleaning up...")
|
||||||
app['monitor_task'].cancel()
|
app['monitor_task'].cancel()
|
||||||
|
app['state_monitor_task'].cancel()
|
||||||
try:
|
try:
|
||||||
await app['monitor_task']
|
await app['monitor_task']
|
||||||
|
await app['state_monitor_task']
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
pass
|
pass
|
||||||
await app['client_session'].close()
|
await app['client_session'].close()
|
||||||
|
Reference in New Issue
Block a user