245 lines
7.8 KiB
Python
245 lines
7.8 KiB
Python
"""
|
|
VitalLink Main System Runner
|
|
Runs the complete system with real and/or simulated wristbands
|
|
"""
|
|
|
|
import asyncio
|
|
import aiohttp
|
|
from wristband_manager import WristbandManager
|
|
from config_system import WristbandConfig
|
|
|
|
# ============================================================================
|
|
# MAIN SYSTEM
|
|
# ============================================================================
|
|
|
|
|
|
class VitalLinkSystem:
|
|
"""Main system orchestrator"""
|
|
|
|
def __init__(self):
|
|
self.manager = WristbandManager()
|
|
self.config = WristbandConfig()
|
|
self.backend_url = self.config.get("backend_url", "http://localhost:8000")
|
|
self.running = False
|
|
|
|
async def initialize(self):
|
|
"""Initialize the system"""
|
|
print("\n" + "=" * 80)
|
|
print("VitalLink System Initialization")
|
|
print("=" * 80 + "\n")
|
|
|
|
# Check backend availability
|
|
await self.check_backend()
|
|
|
|
# Scan for real wristbands if configured
|
|
if self.config.get("auto_scan_ble", False):
|
|
timeout = self.config.get("scan_timeout", 10.0)
|
|
await self.manager.scan_for_real_bands(timeout)
|
|
|
|
# Load configured real wristbands
|
|
for band_config in self.config.get_real_bands():
|
|
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():
|
|
self.manager.add_simulated_band(
|
|
band_config["band_id"], band_config.get("profile", "stable")
|
|
)
|
|
|
|
# Show inventory
|
|
self.manager.print_inventory()
|
|
|
|
async def check_backend(self):
|
|
"""Check if backend is running"""
|
|
try:
|
|
async with aiohttp.ClientSession() as session:
|
|
async with session.get(f"{self.backend_url}/") 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"""
|
|
|
|
# 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...")
|
|
|
|
prefer_real = self.config.get("prefer_real_bands", False)
|
|
|
|
for patient_data in demo_patients:
|
|
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:
|
|
if resp.status == 200:
|
|
data = await resp.json()
|
|
patient_id = data["patient_id"]
|
|
assigned_band_id = data["band_id"]
|
|
|
|
print(
|
|
f"✓ {patient_data['firstName']} {patient_data['lastName']} → {patient_id}"
|
|
)
|
|
|
|
# Find and assign a physical/simulated band
|
|
band = self.manager.assign_band(
|
|
patient_id, prefer_real=prefer_real
|
|
)
|
|
|
|
if band:
|
|
# Start monitoring
|
|
await self.manager.start_monitoring(band.band_id)
|
|
|
|
except Exception as e:
|
|
print(f"❌ Failed to check in {patient_data['firstName']}: {e}")
|
|
|
|
print()
|
|
|
|
async def run(self):
|
|
"""Run the main system"""
|
|
self.running = True
|
|
|
|
await self.initialize()
|
|
await self.auto_checkin_and_assign()
|
|
|
|
print("=" * 80)
|
|
print("VitalLink System Running")
|
|
print("=" * 80)
|
|
print("\nMonitoring patients... Press Ctrl+C to stop\n")
|
|
|
|
try:
|
|
# Keep running until interrupted
|
|
while self.running:
|
|
await asyncio.sleep(10)
|
|
|
|
# Periodic status update
|
|
status = self.manager.get_status()
|
|
print(
|
|
f"[{asyncio.get_event_loop().time():.0f}s] Active: {status['active_monitoring']} | "
|
|
f"Available: {status['status_breakdown']['available']}"
|
|
)
|
|
|
|
except KeyboardInterrupt:
|
|
print("\n\nShutting down...")
|
|
await self.shutdown()
|
|
|
|
async def shutdown(self):
|
|
"""Clean shutdown"""
|
|
self.running = False
|
|
|
|
# Stop all monitoring
|
|
for band_id in list(self.manager.active_monitoring.keys()):
|
|
await self.manager.stop_monitoring(band_id)
|
|
|
|
print("\n✓ VitalLink system stopped")
|
|
self.manager.print_inventory()
|
|
|
|
|
|
# ============================================================================
|
|
# CLI MODES
|
|
# ============================================================================
|
|
|
|
|
|
async def interactive_mode():
|
|
"""Interactive mode with menu"""
|
|
system = VitalLinkSystem()
|
|
await system.initialize()
|
|
|
|
while True:
|
|
print("\n" + "=" * 80)
|
|
print("VITALLINK INTERACTIVE MODE")
|
|
print("=" * 80)
|
|
print("\n1. Show inventory")
|
|
print("2. Scan for real wristbands")
|
|
print("3. Assign band to patient")
|
|
print("4. Release band")
|
|
print("5. Start auto-demo")
|
|
print("6. Exit")
|
|
|
|
choice = input("\nSelect option: ")
|
|
|
|
if choice == "1":
|
|
system.manager.print_inventory()
|
|
|
|
elif choice == "2":
|
|
await system.manager.scan_for_real_bands(timeout=10.0)
|
|
|
|
elif choice == "3":
|
|
patient_id = input("Patient ID: ")
|
|
prefer_real = input("Prefer real band? (y/n): ").lower() == "y"
|
|
band = system.manager.assign_band(patient_id, prefer_real=prefer_real)
|
|
if band:
|
|
await system.manager.start_monitoring(band.band_id)
|
|
|
|
elif choice == "4":
|
|
band_id = input("Band ID to release: ")
|
|
await system.manager.release_band(band_id)
|
|
|
|
elif choice == "5":
|
|
await system.run()
|
|
break
|
|
|
|
elif choice == "6":
|
|
print("Goodbye!")
|
|
break
|
|
|
|
|
|
# ============================================================================
|
|
# MAIN ENTRY POINT
|
|
# ============================================================================
|
|
|
|
if __name__ == "__main__":
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(description="VitalLink System")
|
|
parser.add_argument(
|
|
"--interactive", "-i", action="store_true", help="Run in interactive mode"
|
|
)
|
|
parser.add_argument(
|
|
"--config",
|
|
"-c",
|
|
default="wristband_config.yaml",
|
|
help="Configuration file path",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.interactive:
|
|
asyncio.run(interactive_mode())
|
|
else:
|
|
# Normal automatic mode
|
|
system = VitalLinkSystem()
|
|
asyncio.run(system.run())
|