diff --git a/vitallink/Dockerfile b/vitallink/Dockerfile index e79b7d9..b2157e1 100644 --- a/vitallink/Dockerfile +++ b/vitallink/Dockerfile @@ -4,6 +4,10 @@ FROM python:3.11-slim RUN apt-get update && apt-get install -y \ curl \ build-essential \ + bluez \ + bluetooth \ + libbluetooth-dev \ + libdbus-1-dev \ && rm -rf /var/lib/apt/lists/* # Install Node.js diff --git a/vitallink/backend/server.py b/vitallink/backend/server.py index 2f01230..69397b5 100644 --- a/vitallink/backend/server.py +++ b/vitallink/backend/server.py @@ -3,6 +3,8 @@ VitalLink Backend API FastAPI server for managing patients, wristbands, and real-time data """ +import os +import socket from fastapi import FastAPI, WebSocket, HTTPException from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel @@ -16,6 +18,37 @@ from collections import defaultdict from triage_engine import TriageEngine, VitalSigns, TriageLevel, triage_from_vitals from database import VitalLinkDatabase +# ============================================================================ +# NETWORK UTILITIES +# ============================================================================ + + +def get_host_ip(): + """ + Returns the actual LAN IP address. + Priority: + 1. HOST_IP environment variable (from docker-compose) + 2. Automatic detection via socket + 3. Fallback to localhost + """ + # 1. Check Environment Variable (The "Single Place") + env_ip = os.getenv("HOST_IP") + if env_ip: + return env_ip + + # 2. Auto-detect LAN IP + try: + # We don't actually connect, just check how we WOULD connect to Google + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.settimeout(0) + s.connect(("8.8.8.8", 1)) + ip = s.getsockname()[0] + s.close() + return ip + except Exception: + return "127.0.0.1" + + # ============================================================================ # LIFESPAN MANAGEMENT # ============================================================================ @@ -25,18 +58,24 @@ from database import VitalLinkDatabase async def lifespan(app: FastAPI): # Startup global db + + # GET THE IP + host_ip = get_host_ip() + print("=" * 80) - print("VitalLink Backend API Started") + print(f"VitalLink Backend API Started on {host_ip}") print("=" * 80) # Initialize database db = VitalLinkDatabase("vitallink.db") await db.initialize() - print("API Documentation: http://localhost:8000/docs") - print("WebSocket Endpoint: ws://localhost:8000/ws") - print("Database: vitallink.db") + # Print useful clickable links for the developer + print(f"API Documentation: http://{host_ip}:8000/docs") + print(f"Frontend Dashboard: http://{host_ip}:5173") + print(f"WebSocket Endpoint: ws://{host_ip}:8000/ws") print("=" * 80) + yield # Shutdown if db: diff --git a/vitallink/docker-compose.yml b/vitallink/docker-compose.yml index 46b74ef..3ba0bc9 100644 --- a/vitallink/docker-compose.yml +++ b/vitallink/docker-compose.yml @@ -1,15 +1,20 @@ -version: '3.8' - services: vitallink: build: . - ports: - - "8000:8000" - - "5173:5173" - - "5174:5174" volumes: - - ./wristband_config.yaml:/app/simulator/wristband_config.yaml + - ./wristband_config.yaml:/app/wristband_config.yaml - ./vitallink.db:/app/vitallink.db + - /var/run/dbus:/var/run/dbus # D-Bus for Bluetooth + - /run/dbus:/run/dbus environment: - HOST_IP=192.168.65.227 # Pi's IP restart: unless-stopped + + # BLUETOOTH ACCESS - ADD THESE: + privileged: true + network_mode: host + devices: + - /dev/bus/usb:/dev/bus/usb # USB Bluetooth adapter + cap_add: + - NET_ADMIN + - SYS_ADMIN diff --git a/vitallink/docker-start.sh b/vitallink/docker-start.sh index d024588..803bc80 100755 --- a/vitallink/docker-start.sh +++ b/vitallink/docker-start.sh @@ -1,15 +1,24 @@ #!/bin/bash -# Backend -python backend/server.py & +# --- ADD THIS LINE --- +# Add backend and simulator to Python path so imports work +export PYTHONPATH=$PYTHONPATH:/app/backend:/app/simulator -# Wristband system +# 1. Start Backend +echo "Starting Backend..." +uvicorn backend.server:app --host 0.0.0.0 --port 8000 & + +# 2. Wristband system +echo "Starting Simulator..." python simulator/main_runner.py & -# Dashboard -cd frontend/dashboard && python -m http.server 5173 -d dist & +# 3. Dashboard +echo "Starting Dashboard on 5173..." +cd frontend/dashboard && python -m http.server 5173 --bind 0.0.0.0 -d dist & -# Kiosk -cd frontend/kiosk && python -m http.server 5174 -d dist & +# 4. Kiosk +echo "Starting Kiosk on 5174..." +cd /app/frontend/kiosk && python -m http.server 5174 --bind 0.0.0.0 -d dist & +# Keep container running wait diff --git a/vitallink/nuke-docker.sh b/vitallink/nuke-docker.sh new file mode 100755 index 0000000..b6e18ff --- /dev/null +++ b/vitallink/nuke-docker.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +echo "๐Ÿ”„ INITIATING REBUILD (PRESERVING DATABASE)..." + +# 1. Stop containers +# Removed '--volumes' flag so named volumes aren't wiped inadvertently +echo "๐Ÿ›‘ Stopping containers..." +docker compose down --remove-orphans + +# 2. DATABASE PRESERVATION +# This section is now disabled to keep your data safe. +# if [ -f "vitallink.db" ]; then +# echo "๐Ÿ—‘๏ธ Deleting database file (vitallink.db)..." +# rm vitallink.db +# fi +echo "๐Ÿ’พ Database file (vitallink.db) preserved." + +# Optional: Still good to check for that directory error +if [ -d "wristband_config.yaml" ]; then + echo "๐Ÿ—‘๏ธ Removing broken config directory..." + rm -rf wristband_config.yaml +fi + +# 3. Prune Docker System +# Removes stopped containers and unused networks to save space +echo "๐Ÿงน Pruning Docker system..." +docker system prune -f + +# 4. Rebuild everything from scratch +# This ensures code changes (Python/React) are applied +echo "๐Ÿ—๏ธ Rebuilding images (No Cache)..." +docker compose build --no-cache + +# 5. Start it up +echo "๐Ÿš€ Launching VitalLink..." +docker compose up -d + +echo "โœ… DONE! System rebuilt, Database preserved. Access at:" +# Print the IP for convenience +hostname -I | awk '{print "http://" $1 ":5173"}' diff --git a/vitallink/vitallink.db b/vitallink/vitallink.db index 3c475b2..e149dad 100644 Binary files a/vitallink/vitallink.db and b/vitallink/vitallink.db differ