vitallink-BS/vitallink/simulator/config_system.py

257 lines
7.5 KiB
Python

"""
VitalLink Configuration System
Easy configuration for managing wristband inventory
"""
import yaml
import json
from pathlib import Path
# ============================================================================
# CONFIGURATION FILE EXAMPLE
# ============================================================================
EXAMPLE_CONFIG = """
# 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"
"""
class WristbandConfig:
"""Configuration manager for wristbands"""
def __init__(self, config_path: str = "wristband_config.yaml"):
self.config_path = Path(config_path)
self.config = {}
if not self.config_path.exists():
self.create_default_config()
self.load()
def create_default_config(self):
"""Create default configuration file"""
print(f"Creating default config at {self.config_path}")
with open(self.config_path, "w") as f:
f.write(EXAMPLE_CONFIG)
def load(self):
"""Load configuration from file"""
try:
with open(self.config_path, "r") as f:
self.config = yaml.safe_load(f) or {}
print(f"✓ Loaded configuration from {self.config_path}")
except Exception as e:
print(f"⚠️ Could not load config: {e}")
print("Using default configuration")
self.config = {}
def get(self, key: str, default=None):
"""Get configuration value"""
return self.config.get(key, default)
def get_simulated_bands(self):
"""Get list of simulated bands from config"""
return self.config.get("simulated_bands", [])
def get_real_bands(self):
"""Get list of real bands from config"""
return self.config.get("real_bands", [])
def add_discovered_band(self, band_id: str, ble_address: str):
"""Add a discovered real band to config"""
if "real_bands" not in self.config:
self.config["real_bands"] = []
# Check if already exists
for band in self.config["real_bands"]:
if band.get("ble_address") == ble_address:
return
self.config["real_bands"].append(
{"band_id": band_id, "ble_address": ble_address}
)
self.save()
print(f"✓ Added {band_id} to configuration")
def save(self):
"""Save configuration to file"""
try:
with open(self.config_path, "w") as f:
yaml.safe_dump(
self.config, f, default_flow_style=False, sort_keys=False
)
print(f"✓ Saved configuration to {self.config_path}")
except Exception as e:
print(f"❌ Failed to save config: {e}")
# ============================================================================
# COMMAND LINE INTERFACE
# ============================================================================
async def cli_scan():
"""CLI: Scan for real wristbands"""
from wristband_manager import WristbandManager
print("Scanning for VitalLink wristbands...")
manager = WristbandManager()
config = WristbandConfig()
found = await manager.scan_for_real_bands(timeout=15.0)
if found:
print(f"\nFound {len(found)} wristband(s):")
for band_id in found:
band = manager.inventory[band_id]
if hasattr(band, "ble_address"):
print(f" {band_id}: {band.ble_address}")
# Ask to add to config
response = input(f"Add {band_id} to config? (y/n): ")
if response.lower() == "y":
config.add_discovered_band(band_id, band.ble_address)
else:
print("No wristbands found")
print("\nTroubleshooting:")
print(" 1. Make sure wristbands are powered on")
print(" 2. Remove wristbands from chargers")
print(" 3. Ensure Bluetooth is enabled on this computer")
def cli_inventory():
"""CLI: Show current inventory"""
config = WristbandConfig()
print("\n" + "=" * 80)
print("CONFIGURED WRISTBAND INVENTORY")
print("=" * 80)
print("\nSimulated Wristbands:")
simulated = config.get_simulated_bands()
if simulated:
for band in simulated:
print(f" 🟢 {band['band_id']:20} | Profile: {band['profile']}")
else:
print(" (none configured)")
print("\nReal Wristbands (Hardware):")
real = config.get_real_bands()
if real:
for band in real:
print(f" 🔵 {band['band_id']:20} | BLE: {band['ble_address']}")
else:
print(" (none configured)")
print("\n" + "=" * 80)
print(f"Total: {len(simulated) + len(real)} wristbands")
print("=" * 80 + "\n")
def cli_add_simulated():
"""CLI: Add a simulated wristband"""
config = WristbandConfig()
print("\nAdd Simulated Wristband")
print("-" * 40)
band_id = input("Band ID (e.g., VitalLink-SIM4): ")
print("\nAvailable profiles:")
print(" 1. stable - Normal vitals")
print(" 2. mild_anxiety - Elevated HR")
print(" 3. deteriorating - Gradually worsening")
print(" 4. critical - Severe vitals")
print(" 5. sepsis - Rapid deterioration")
profile_choice = input("\nSelect profile (1-5): ")
profiles = ["stable", "mild_anxiety", "deteriorating", "critical", "sepsis"]
profile = (
profiles[int(profile_choice) - 1]
if profile_choice.isdigit() and 1 <= int(profile_choice) <= 5
else "stable"
)
if "simulated_bands" not in config.config:
config.config["simulated_bands"] = []
config.config["simulated_bands"].append({"band_id": band_id, "profile": profile})
config.save()
print(f"\n✓ Added {band_id} ({profile})")
if __name__ == "__main__":
import argparse
import sys
# Check if yaml is installed
try:
import yaml
except ImportError:
print("❌ PyYAML not installed. Install with: pip install pyyaml")
sys.exit(1)
parser = argparse.ArgumentParser(
description="VitalLink Wristband Configuration Tool"
)
parser.add_argument("--scan", action="store_true", help="Scan for real wristbands")
parser.add_argument(
"--inventory", action="store_true", help="Show configured inventory"
)
parser.add_argument(
"--add-simulated", action="store_true", help="Add a simulated wristband"
)
args = parser.parse_args()
if args.scan:
import asyncio
asyncio.run(cli_scan())
elif args.inventory:
cli_inventory()
elif args.add_simulated:
cli_add_simulated()
else:
parser.print_help()