Skip to content

Commit 227765c

Browse files
author
Alan Tai
committed
Add a visual timer for children who have ADHD
1 parent d8afed0 commit 227765c

27 files changed

Lines changed: 1042 additions & 368 deletions

backend/src/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from fastapi.staticfiles import StaticFiles
88
from sentry_sdk import init
99

10-
from .routers import system
10+
from .routers import system, websocket
1111

1212
load_dotenv()
1313

@@ -25,6 +25,7 @@ def lookup_path(self, path: str):
2525

2626
app = FastAPI(title='BentoPi API', version='v1')
2727
app.include_router(system.router)
28+
app.include_router(websocket.router)
2829
app.add_middleware(CORSMiddleware, allow_headers=['*'], allow_methods=['*'], allow_origins=['*'])
2930

3031
if argv[1] != 'dev':

backend/src/routers/websocket.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
2+
3+
from ..services import DeviceManager
4+
5+
router = APIRouter(prefix='/ws', tags=['websocket'])
6+
manager = DeviceManager()
7+
8+
9+
@router.websocket('/{device_id}')
10+
async def websocket_endpoint(websocket: WebSocket, device_id: str) -> None:
11+
await manager.connect(device_id, websocket)
12+
13+
try:
14+
while True:
15+
message = await websocket.receive_json()
16+
target_id = message.get('target_id')
17+
18+
if target_id:
19+
await manager.send(target_id, message.get('payload'))
20+
except WebSocketDisconnect:
21+
manager.disconnect(device_id)

backend/src/services/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .device_manager import DeviceManager
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from fastapi import WebSocket, WebSocketDisconnect
2+
3+
4+
class DeviceManager:
5+
def __init__(self):
6+
self.devices: dict[str, WebSocket] = {}
7+
8+
async def connect(self, device_id: str, websocket: WebSocket) -> None:
9+
await websocket.accept()
10+
11+
self.devices[device_id] = websocket
12+
13+
def disconnect(self, device_id: str) -> None:
14+
if device_id in self.devices:
15+
del self.devices[device_id]
16+
17+
async def send(self, device_id: str, payload: dict[str, ...]) -> bool:
18+
websocket = self.devices.get(device_id)
19+
if websocket:
20+
try:
21+
await websocket.send_json(payload)
22+
23+
return True
24+
except WebSocketDisconnect:
25+
self.disconnect(device_id)
26+
27+
return False

frontend/package.json

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,33 +38,34 @@
3838
"@fortawesome/free-solid-svg-icons" : "^7.1.0",
3939
"@fortawesome/react-fontawesome" : "^3.1.1",
4040
"@reduxjs/toolkit" : "^2.11.2",
41-
"@sentry/react" : "^10.32.1",
42-
"antd" : "^6.1.4",
41+
"@sentry/react" : "^10.34.0",
42+
"antd" : "^6.2.0",
4343
"date-fns" : "^4.1.0",
4444
"i18next" : "^25.7.4",
4545
"react" : "^19.2.3",
4646
"react-dom" : "^19.2.3",
4747
"react-gauge-component" : "^1.2.64",
48-
"react-i18next" : "^16.5.1",
48+
"react-i18next" : "^16.5.3",
4949
"react-redux" : "^9.2.0",
5050
"react-router" : "^7.12.0",
51-
"redux-persist" : "^6.0.0"
51+
"redux-persist" : "^6.0.0",
52+
"uuid" : "^13.0.0"
5253
},
5354
"devDependencies" : {
5455
"@eslint/eslintrc" : "^3.3.3",
5556
"@eslint/js" : "^9.39.2",
56-
"@stylistic/eslint-plugin" : "^5.6.1",
57+
"@stylistic/eslint-plugin" : "^5.7.0",
5758
"@testing-library/jest-dom" : "^6.9.1",
5859
"@testing-library/react" : "^16.3.1",
59-
"@types/node" : "^25.0.3",
60-
"@types/react" : "^19.2.7",
60+
"@types/node" : "^25.0.9",
61+
"@types/react" : "^19.2.8",
6162
"@types/react-dom" : "^19.2.3",
6263
"@types/react-test-renderer" : "^19.1.0",
63-
"@typescript-eslint/parser" : "^8.52.0",
64+
"@typescript-eslint/parser" : "^8.53.0",
6465
"@vitejs/plugin-react-swc" : "^4.2.2",
65-
"@vitest/coverage-v8" : "^4.0.16",
66-
"@vitest/ui" : "^4.0.16",
67-
"baseline-browser-mapping" : "^2.9.12",
66+
"@vitest/coverage-v8" : "^4.0.17",
67+
"@vitest/ui" : "^4.0.17",
68+
"baseline-browser-mapping" : "^2.9.15",
6869
"eslint" : "^9.39.2",
6970
"eslint-plugin-import" : "^2.32.0",
7071
"eslint-plugin-prefer-arrow" : "^1.2.3",
@@ -75,9 +76,9 @@
7576
"jsdom" : "^27.4.0",
7677
"prop-types" : "^15.8.1",
7778
"typescript" : "^5.9.3",
78-
"typescript-eslint" : "^8.52.0",
79+
"typescript-eslint" : "^8.53.0",
7980
"vite" : "^7.3.1",
80-
"vitest" : "^4.0.16",
81+
"vitest" : "^4.0.17",
8182
"vitest-fetch-mock" : "^0.4.5"
8283
},
8384
"engines" : {

0 commit comments

Comments
 (0)