From 18fc4cb0bd78ac957425cc90888aaddd1a78a54e Mon Sep 17 00:00:00 2001 From: Raika Furude Date: Sat, 18 Oct 2025 17:36:36 -0400 Subject: [PATCH] fixed import error in band management --- vitallink/link-start.sh | 117 +++++++ vitallink/logs/all_pids.txt | 4 + vitallink/logs/backend.log | 298 +++++++++++++++++- vitallink/logs/backend.pid | 2 +- vitallink/logs/dashboard.log | 9 + vitallink/logs/dashboard.pid | 1 + vitallink/logs/kiosk.log | 10 + vitallink/logs/kiosk.pid | 1 + vitallink/logs/wristbands.log | 25 ++ vitallink/logs/wristbands.pid | 1 + .../__pycache__/config_system.cpython-39.pyc | Bin 0 -> 7543 bytes .../wristband_manager.cpython-39.pyc | Bin 0 -> 14632 bytes vitallink/simulator/config_system.py | 4 +- vitallink/simulator/main_runner.py | 175 ++++++---- vitallink/simulator/wristband_manager.py | 2 +- vitallink/start.sh | 47 --- vitallink/stop.sh | 18 -- vitallink/stop_everything.sh | 36 +++ vitallink/test.sh | 13 - vitallink/wristband_config.yaml | 40 +++ 20 files changed, 647 insertions(+), 156 deletions(-) create mode 100755 vitallink/link-start.sh create mode 100644 vitallink/logs/all_pids.txt create mode 100644 vitallink/logs/dashboard.log create mode 100644 vitallink/logs/dashboard.pid create mode 100644 vitallink/logs/kiosk.log create mode 100644 vitallink/logs/kiosk.pid create mode 100644 vitallink/logs/wristbands.log create mode 100644 vitallink/logs/wristbands.pid create mode 100644 vitallink/simulator/__pycache__/config_system.cpython-39.pyc create mode 100644 vitallink/simulator/__pycache__/wristband_manager.cpython-39.pyc delete mode 100755 vitallink/start.sh delete mode 100755 vitallink/stop.sh create mode 100755 vitallink/stop_everything.sh delete mode 100755 vitallink/test.sh create mode 100644 vitallink/wristband_config.yaml diff --git a/vitallink/link-start.sh b/vitallink/link-start.sh new file mode 100755 index 0000000..eeaeedb --- /dev/null +++ b/vitallink/link-start.sh @@ -0,0 +1,117 @@ +#!/bin/bash + +PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$PROJECT_ROOT" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo -e "${BLUE}" +cat <<"EOF" +╔══════════════════════════════════════════════════════════════════════════╗ +║ ║ +║ ██╗ ██╗██╗████████╗ █████╗ ██╗ ██╗ ██╗███╗ ██╗██╗ ██╗ ║ +║ ██║ ██║██║╚══██╔══╝██╔══██╗██║ ██║ ██║████╗ ██║██║ ██╔╝ ║ +║ ██║ ██║██║ ██║ ███████║██║ ██║ ██║██╔██╗ ██║█████╔╝ ║ +║ ╚██╗ ██╔╝██║ ██║ ██╔══██║██║ ██║ ██║██║╚██╗██║██╔═██╗ ║ +║ ╚████╔╝ ██║ ██║ ██║ ██║███████╗███████╗██║██║ ╚████║██║ ██╗ ║ +║ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ║ +║ ║ +║ Complete System Startup ║ +║ ║ +╚══════════════════════════════════════════════════════════════════════════╝ +EOF +echo -e "${NC}" + +echo -e "${YELLOW}Starting VitalLink Complete System...${NC}\n" + +# Create logs directory +mkdir -p logs + +# Activate Python virtual environment +echo -e "${BLUE}[1/5]${NC} Activating Python environment..." +source .venv/bin/activate + +# Start Backend +echo -e "${BLUE}[2/5]${NC} Starting Backend API..." +python backend/server.py >logs/backend.log 2>&1 & +BACKEND_PID=$! +echo $BACKEND_PID >logs/backend.pid +echo -e " ${GREEN}✓${NC} Backend started (PID: $BACKEND_PID)" +sleep 3 + +# Start Wristband System +echo -e "${BLUE}[3/5]${NC} Starting Wristband Management System..." +python simulator/main_runner.py >logs/wristbands.log 2>&1 & +WRISTBAND_PID=$! +echo $WRISTBAND_PID >logs/wristbands.pid +echo -e " ${GREEN}✓${NC} Wristband system started (PID: $WRISTBAND_PID)" +sleep 2 + +# Start Dashboard Frontend +echo -e "${BLUE}[4/5]${NC} Starting Staff Dashboard..." +cd frontend/dashboard +npm run dev >../../logs/dashboard.log 2>&1 & +DASHBOARD_PID=$! +echo $DASHBOARD_PID >../../logs/dashboard.pid +cd ../.. +echo -e " ${GREEN}✓${NC} Dashboard started (PID: $DASHBOARD_PID)" +sleep 2 + +# Start Kiosk Frontend +echo -e "${BLUE}[5/5]${NC} Starting Check-in Kiosk..." +cd frontend/kiosk +npm run dev >../../logs/kiosk.log 2>&1 & +KIOSK_PID=$! +echo $KIOSK_PID >../../logs/kiosk.pid +cd ../.. +echo -e " ${GREEN}✓${NC} Kiosk started (PID: $KIOSK_PID)" + +echo "" +echo -e "${GREEN}═══════════════════════════════════════════════════════════════════════${NC}" +echo -e "${GREEN} ✅ VitalLink System Running! ${NC}" +echo -e "${GREEN}═══════════════════════════════════════════════════════════════════════${NC}" +echo "" +echo -e "${YELLOW}📊 Access Points:${NC}" +echo -e " ${BLUE}•${NC} Backend API: http://localhost:8000" +echo -e " ${BLUE}•${NC} API Documentation: http://localhost:8000/docs" +echo -e " ${BLUE}•${NC} Staff Dashboard: http://localhost:5173" +echo -e " ${BLUE}•${NC} Check-in Kiosk: http://localhost:5174" +echo "" +echo -e "${YELLOW}📝 View Logs:${NC}" +echo -e " ${BLUE}•${NC} Backend: tail -f logs/backend.log" +echo -e " ${BLUE}•${NC} Wristbands: tail -f logs/wristbands.log" +echo -e " ${BLUE}•${NC} Dashboard: tail -f logs/dashboard.log" +echo -e " ${BLUE}•${NC} Kiosk: tail -f logs/kiosk.log" +echo "" +echo -e "${YELLOW}🔧 System Features:${NC}" +echo -e " ${GREEN}✓${NC} Auto-assigns wristbands when patients check in" +echo -e " ${GREEN}✓${NC} Prefers real wristbands over simulated" +echo -e " ${GREEN}✓${NC} Creates emergency simulated bands if needed" +echo -e " ${GREEN}✓${NC} Real-time monitoring and updates" +echo "" +echo -e "${YELLOW}🛑 Stop System:${NC}" +echo -e " ${BLUE}•${NC} Run: ./stop_everything.sh" +echo -e " ${BLUE}•${NC} Or press Ctrl+C (will stop all services)" +echo "" +echo -e "${GREEN}═══════════════════════════════════════════════════════════════════════${NC}" +echo "" + +# Save all PIDs for easy cleanup +cat >logs/all_pids.txt < dashboard@0.0.0 dev +> vite + + + VITE v7.1.10 ready in 100 ms + + ➜ Local: http://localhost:5173/ + ➜ Network: use --host to expose diff --git a/vitallink/logs/dashboard.pid b/vitallink/logs/dashboard.pid new file mode 100644 index 0000000..5185dbd --- /dev/null +++ b/vitallink/logs/dashboard.pid @@ -0,0 +1 @@ +103478 diff --git a/vitallink/logs/kiosk.log b/vitallink/logs/kiosk.log new file mode 100644 index 0000000..89aaf3a --- /dev/null +++ b/vitallink/logs/kiosk.log @@ -0,0 +1,10 @@ + +> kiosk@0.0.0 dev +> vite + +Port 5173 is in use, trying another one... + + VITE v7.1.10 ready in 103 ms + + ➜ Local: http://localhost:5174/ + ➜ Network: use --host to expose diff --git a/vitallink/logs/kiosk.pid b/vitallink/logs/kiosk.pid new file mode 100644 index 0000000..09ae417 --- /dev/null +++ b/vitallink/logs/kiosk.pid @@ -0,0 +1 @@ +103512 diff --git a/vitallink/logs/wristbands.log b/vitallink/logs/wristbands.log new file mode 100644 index 0000000..1aff406 --- /dev/null +++ b/vitallink/logs/wristbands.log @@ -0,0 +1,25 @@ +⚠️ Bleak not installed. Real wristbands disabled. Install with: pip install bleak +Creating default config at wristband_config.yaml +✓ Loaded configuration from wristband_config.yaml + +================================================================================ +VitalLink System Initialization +================================================================================ + +✓ Backend is running at http://localhost:8000 +Traceback (most recent call last): + File "/home/mai/documents/school/capstone/vitallink-BS/vitallink/simulator/main_runner.py", line 282, in + asyncio.run(system.run()) + File "/home/mai/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/asyncio/runners.py", line 44, in run + return loop.run_until_complete(main) + File "/home/mai/.local/share/uv/python/cpython-3.9.20-linux-x86_64-gnu/lib/python3.9/asyncio/base_events.py", line 647, in run_until_complete + return future.result() + File "/home/mai/documents/school/capstone/vitallink-BS/vitallink/simulator/main_runner.py", line 153, in run + await self.initialize() + File "/home/mai/documents/school/capstone/vitallink-BS/vitallink/simulator/main_runner.py", line 52, in initialize + self.manager.add_simulated_band( + File "/home/mai/documents/school/capstone/vitallink-BS/vitallink/simulator/wristband_manager.py", line 324, in add_simulated_band + band = SimulatedWristband(band_id, profile) + File "/home/mai/documents/school/capstone/vitallink-BS/vitallink/simulator/wristband_manager.py", line 243, in __init__ + from simulator.wristband_simulator import PATIENT_PROFILES, WristbandSimulator +ModuleNotFoundError: No module named 'simulator' diff --git a/vitallink/logs/wristbands.pid b/vitallink/logs/wristbands.pid new file mode 100644 index 0000000..a9f66c2 --- /dev/null +++ b/vitallink/logs/wristbands.pid @@ -0,0 +1 @@ +103468 diff --git a/vitallink/simulator/__pycache__/config_system.cpython-39.pyc b/vitallink/simulator/__pycache__/config_system.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5090c61b22edbce3269ac0db57c89892e0d74f2a GIT binary patch literal 7543 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 GHU1aZk=6nL literal 0 HcmV?d00001 diff --git a/vitallink/simulator/__pycache__/wristband_manager.cpython-39.pyc b/vitallink/simulator/__pycache__/wristband_manager.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fc8e6f720688ce86acd495cb86366ed3ae6807d GIT binary patch literal 14632 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 literal 0 HcmV?d00001 diff --git a/vitallink/simulator/config_system.py b/vitallink/simulator/config_system.py index 845a0d5..6597eb4 100644 --- a/vitallink/simulator/config_system.py +++ b/vitallink/simulator/config_system.py @@ -167,7 +167,7 @@ def cli_inventory(): print("=" * 80) print("\nSimulated Wristbands:") - simulated = config.get_simulated_bands() + simulated = config.get_simulated_bands() or [] # Add "or []" if simulated: for band in simulated: print(f" 🟢 {band['band_id']:20} | Profile: {band['profile']}") @@ -175,7 +175,7 @@ def cli_inventory(): print(" (none configured)") print("\nReal Wristbands (Hardware):") - real = config.get_real_bands() + real = config.get_real_bands() or [] # Add "or []" if real: for band in real: print(f" 🔵 {band['band_id']:20} | BLE: {band['ble_address']}") diff --git a/vitallink/simulator/main_runner.py b/vitallink/simulator/main_runner.py index df109dd..e0486eb 100644 --- a/vitallink/simulator/main_runner.py +++ b/vitallink/simulator/main_runner.py @@ -1,12 +1,14 @@ """ VitalLink Main System Runner Runs the complete system with real and/or simulated wristbands +Automatically assigns bands when patients check in via kiosk """ import asyncio import aiohttp from wristband_manager import WristbandManager from config_system import WristbandConfig +import sys # ============================================================================ # MAIN SYSTEM @@ -21,6 +23,7 @@ class VitalLinkSystem: self.config = WristbandConfig() self.backend_url = self.config.get("backend_url", "http://localhost:8000") self.running = False + self.monitoring_task = None async def initialize(self): """Initialize the system""" @@ -29,7 +32,9 @@ class VitalLinkSystem: print("=" * 80 + "\n") # Check backend availability - await self.check_backend() + backend_ok = await self.check_backend() + if not backend_ok: + print("\n⚠️ Warning: Backend not running. System will wait for backend...") # Scan for real wristbands if configured if self.config.get("auto_scan_ble", False): @@ -37,13 +42,13 @@ class VitalLinkSystem: await self.manager.scan_for_real_bands(timeout) # Load configured real wristbands - for band_config in self.config.get_real_bands(): + for band_config in self.config.get_real_bands() or []: self.manager.add_real_band( band_config["band_id"], band_config["ble_address"] ) # Load configured simulated wristbands - for band_config in self.config.get_simulated_bands(): + for band_config in self.config.get_simulated_bands() or []: self.manager.add_simulated_band( band_config["band_id"], band_config.get("profile", "stable") ) @@ -55,89 +60,112 @@ class VitalLinkSystem: """Check if backend is running""" try: async with aiohttp.ClientSession() as session: - async with session.get(f"{self.backend_url}/") as resp: + async with session.get( + f"{self.backend_url}/", timeout=aiohttp.ClientTimeout(total=3) + ) as resp: if resp.status == 200: print(f"✓ Backend is running at {self.backend_url}") return True except Exception as e: print(f"❌ Backend not reachable at {self.backend_url}") - print(f" Error: {e}") - print("\n⚠️ Start backend with: python backend/server.py") return False - async def auto_checkin_and_assign(self): - """Automatically check in patients and assign available bands""" + return False - # Mock patients for demo - demo_patients = [ - { - "firstName": "John", - "lastName": "Smith", - "dob": "1985-03-15", - "symptoms": ["Chest Pain"], - "severity": "mild", - }, - { - "firstName": "Sarah", - "lastName": "Johnson", - "dob": "1990-07-22", - "symptoms": ["Fever", "Difficulty Breathing"], - "severity": "moderate", - }, - { - "firstName": "Michael", - "lastName": "Chen", - "dob": "1978-11-05", - "symptoms": ["Severe Headache"], - "severity": "severe", - }, - ] - - print("\nAuto check-in patients...") + async def monitor_new_patients(self): + """Monitor backend for new patient check-ins and auto-assign bands""" + print("\n🔍 Monitoring for new patient check-ins...") + known_patients = set() prefer_real = self.config.get("prefer_real_bands", False) - for patient_data in demo_patients: + while self.running: try: - # Check in patient via API async with aiohttp.ClientSession() as session: - async with session.post( - f"{self.backend_url}/api/checkin", json=patient_data - ) as resp: + async with session.get(f"{self.backend_url}/api/queue") as resp: if resp.status == 200: - data = await resp.json() - patient_id = data["patient_id"] - assigned_band_id = data["band_id"] + queue = await resp.json() - print( - f"✓ {patient_data['firstName']} {patient_data['lastName']} → {patient_id}" - ) + for patient in queue: + patient_id = patient["patient_id"] - # Find and assign a physical/simulated band - band = self.manager.assign_band( - patient_id, prefer_real=prefer_real - ) + # New patient detected + if patient_id not in known_patients: + known_patients.add(patient_id) - if band: - # Start monitoring - await self.manager.start_monitoring(band.band_id) + # Check if already has a band assigned and monitoring + has_active_band = any( + b.patient_id == patient_id + and b.band_id in self.manager.active_monitoring + for b in self.manager.inventory.values() + ) + + if not has_active_band: + print( + f"\n🆕 New patient detected: {patient_id} ({patient['name']})" + ) + + # Try to assign a band + band = self.manager.assign_band( + patient_id, prefer_real=prefer_real + ) + + if band: + print( + f" ✓ Assigned {band.band_id} ({band.type.value})" + ) + + # Start monitoring + await self.manager.start_monitoring( + band.band_id + ) + else: + # No bands available - create a new simulated one on the fly + print( + f" ⚠️ No bands available, creating emergency simulated band..." + ) + + emergency_band_id = f"VitalLink-EMRG{len(self.manager.inventory):02d}" + band = self.manager.add_simulated_band( + emergency_band_id, "stable" + ) + band.assign_to_patient(patient_id) + + print( + f" ✓ Created and assigned {emergency_band_id}" + ) + + await self.manager.start_monitoring( + band.band_id + ) except Exception as e: - print(f"❌ Failed to check in {patient_data['firstName']}: {e}") + # Silently continue if backend temporarily unavailable + pass - print() + # Check every 2 seconds + await asyncio.sleep(2) async def run(self): """Run the main system""" self.running = True await self.initialize() - await self.auto_checkin_and_assign() - print("=" * 80) + print("\n" + "=" * 80) print("VitalLink System Running") print("=" * 80) - print("\nMonitoring patients... Press Ctrl+C to stop\n") + print("\n✓ Monitoring for new patients from kiosk check-ins") + print( + "✓ Auto-assigning wristbands (prefer real: {})".format( + self.config.get("prefer_real_bands", False) + ) + ) + print("\nPress Ctrl+C to stop\n") + print("=" * 80 + "\n") + + # Start monitoring for new patients + self.monitoring_task = asyncio.create_task(self.monitor_new_patients()) try: # Keep running until interrupted @@ -146,20 +174,29 @@ class VitalLinkSystem: # Periodic status update status = self.manager.get_status() + available = status["status_breakdown"].get("available", 0) + print( - f"[{asyncio.get_event_loop().time():.0f}s] Active: {status['active_monitoring']} | " - f"Available: {status['status_breakdown']['available']}" + f"[Status] Active: {status['active_monitoring']} monitoring | " + f"Available: {available} bands | " + f"Real: {status['real_bands']} | " + f"Sim: {status['simulated_bands']}" ) except KeyboardInterrupt: - print("\n\nShutting down...") + print("\n\n⚠️ Shutting down...") await self.shutdown() async def shutdown(self): """Clean shutdown""" self.running = False + # Cancel monitoring task + if self.monitoring_task: + self.monitoring_task.cancel() + # Stop all monitoring + print("Stopping all wristband monitoring...") for band_id in list(self.manager.active_monitoring.keys()): await self.manager.stop_monitoring(band_id) @@ -185,7 +222,7 @@ async def interactive_mode(): print("2. Scan for real wristbands") print("3. Assign band to patient") print("4. Release band") - print("5. Start auto-demo") + print("5. Start auto-monitoring mode") print("6. Exit") choice = input("\nSelect option: ") @@ -236,9 +273,13 @@ if __name__ == "__main__": args = parser.parse_args() - if args.interactive: - asyncio.run(interactive_mode()) - else: - # Normal automatic mode - system = VitalLinkSystem() - asyncio.run(system.run()) + try: + if args.interactive: + asyncio.run(interactive_mode()) + else: + # Normal automatic mode + system = VitalLinkSystem() + asyncio.run(system.run()) + except KeyboardInterrupt: + print("\n\nExiting...") + sys.exit(0) diff --git a/vitallink/simulator/wristband_manager.py b/vitallink/simulator/wristband_manager.py index 07d9384..b969f1d 100644 --- a/vitallink/simulator/wristband_manager.py +++ b/vitallink/simulator/wristband_manager.py @@ -240,7 +240,7 @@ class SimulatedWristband(BaseWristband): self.running = False # Import simulator profiles - from simulator.wristband_simulator import PATIENT_PROFILES, WristbandSimulator + from wristband_simulator import PATIENT_PROFILES, WristbandSimulator self.simulator = WristbandSimulator( band_id, PATIENT_PROFILES.get(profile, PATIENT_PROFILES["stable"]), None diff --git a/vitallink/start.sh b/vitallink/start.sh deleted file mode 100755 index 109b646..0000000 --- a/vitallink/start.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -cd "$PROJECT_ROOT" - -# Activate venv (bash way) -source venv/bin/activate 2>/dev/null || source .venv/bin/activate 2>/dev/null - -echo "╔═══════════════════════════════════════════════════════════════════════╗" -echo "║ Starting VitalLink System ║" -echo "╚═══════════════════════════════════════════════════════════════════════╝" -echo "" - -mkdir -p logs - -echo "Starting backend server..." -python backend/server.py > logs/backend.log 2>&1 & -echo $! > logs/backend.pid -echo "✓ Backend started (PID: $(cat logs/backend.pid))" - -sleep 3 - -echo "Starting wristband simulator..." -python simulator/wristband_simulator.py > logs/simulator.log 2>&1 & -echo $! > logs/simulator.pid -echo "✓ Simulator started (PID: $(cat logs/simulator.pid))" - -echo "" -echo "═══════════════════════════════════════════════════════════════════════" -echo "✅ VitalLink System Running!" -echo "═══════════════════════════════════════════════════════════════════════" -echo "" -echo "📊 Access Points:" -echo " • API Docs: http://localhost:8000/docs" -echo " • API Stats: http://localhost:8000/api/stats" -echo " • WebSocket: ws://localhost:8000/ws" -echo " • Staff Dashboard: file://$PROJECT_ROOT/frontend/dashboard/index.html" -echo " • Check-in Kiosk: file://$PROJECT_ROOT/frontend/kiosk/index.html" -echo "" -echo "📝 View Logs:" -echo " • Backend: tail -f logs/backend.log" -echo " • Simulator: tail -f logs/simulator.log" -echo "" -echo "🛑 Stop System:" -echo " • Run: ./stop.sh" -echo "" -echo "═══════════════════════════════════════════════════════════════════════" diff --git a/vitallink/stop.sh b/vitallink/stop.sh deleted file mode 100755 index a828f11..0000000 --- a/vitallink/stop.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -cd "$PROJECT_ROOT" - -echo "Stopping VitalLink system..." - -if [ -f logs/backend.pid ]; then - kill $(cat logs/backend.pid) 2>/dev/null && echo "✓ Backend stopped" || echo "Backend not running" - rm -f logs/backend.pid -fi - -if [ -f logs/simulator.pid ]; then - kill $(cat logs/simulator.pid) 2>/dev/null && echo "✓ Simulator stopped" || echo "Simulator not running" - rm -f logs/simulator.pid -fi - -echo "✓ VitalLink system stopped" diff --git a/vitallink/stop_everything.sh b/vitallink/stop_everything.sh new file mode 100755 index 0000000..a554c6d --- /dev/null +++ b/vitallink/stop_everything.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$PROJECT_ROOT" + +echo "Stopping VitalLink Complete System..." +echo "" + +# Function to stop a service +stop_service() { + local name=$1 + local pidfile="logs/${name}.pid" + + if [ -f "$pidfile" ]; then + PID=$(cat "$pidfile") + if kill -0 $PID 2>/dev/null; then + kill $PID 2>/dev/null + echo "✓ Stopped $name (PID: $PID)" + else + echo " $name already stopped" + fi + rm -f "$pidfile" + fi +} + +# Stop all services +stop_service "backend" +stop_service "wristbands" +stop_service "dashboard" +stop_service "kiosk" + +# Cleanup +rm -f logs/all_pids.txt + +echo "" +echo "✓ VitalLink system stopped" diff --git a/vitallink/test.sh b/vitallink/test.sh deleted file mode 100755 index 21acccc..0000000 --- a/vitallink/test.sh +++ /dev/null @@ -1,13 +0,0 @@ -cat >test.sh <<'TESTEOF' -#!/bin/bash - -PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -cd "$PROJECT_ROOT" -source venv/bin/activate 2>/dev/null || source .venv/bin/activate 2>/dev/null - -echo "Running VitalLink Test Suite..." -echo "" -python tests/test_suite.py -TESTEOF - -chmod +x test.sh diff --git a/vitallink/wristband_config.yaml b/vitallink/wristband_config.yaml new file mode 100644 index 0000000..12332bc --- /dev/null +++ b/vitallink/wristband_config.yaml @@ -0,0 +1,40 @@ + +# VitalLink Wristband Configuration +# Edit this file to manage your wristband inventory + +# Backend API URL +backend_url: "http://localhost:8000" + +# Auto-scan for real wristbands on startup +auto_scan_ble: false +scan_timeout: 10.0 + +# Simulated Wristbands +# Add as many as you need for testing +simulated_bands: + - band_id: "VitalLink-SIM1" + profile: "stable" + + - band_id: "VitalLink-SIM2" + profile: "mild_anxiety" + + - band_id: "VitalLink-SIM3" + profile: "deteriorating" + +# Real Wristbands (Hardware) +# Add BLE addresses of your physical wristbands +# You can find these by running: python -m wristband_manager --scan +real_bands: + # Example (uncomment and edit when you have real hardware): + # - band_id: "VitalLink-A3B2" + # ble_address: "D7:91:3F:9A:12:34" + # + # - band_id: "VitalLink-7B42" + # ble_address: "E1:84:7B:42:56:78" + +# Default preference when assigning bands +prefer_real_bands: false # Set to true to use real bands first + +# Patient profiles for simulated bands +# Options: stable, mild_anxiety, deteriorating, critical, sepsis +default_profile: "stable"