Project Overview
The Sleep Lab Monitoring System is a full-stack medical monitoring platform that enables real-time collection, analysis, and visualization of Continuous Positive Airway Pressure (CPAP) data for sleep apnea patients. The system provides clinicians with a desktop patient-side interface for uploading physiological data, a RESTful API backend for data management, and bidirectional communication capabilities that allow monitoring stations to remotely adjust CPAP settings—creating a closed-loop feedback system critical for overnight patient safety.
The Purpose: Why Sleep Labs Need This
Sleep apnea is a serious medical condition affecting millions of patients worldwide, and overnight monitoring in clinical sleep labs requires constant vigilance. The traditional workflow presents significant operational friction: technicians must physically visit patient rooms to collect data from CPAP machines, manually record measurements, and rely on delayed analysis that can miss critical apnea events in real-time.
This system addresses three core pain points in clinical sleep studies:
- Data Fragmentation: Physiological data from CPAP devices typically remains siloed until manually extracted post-study, preventing real-time intervention.
- Apnea Detection Latency: Without automated analysis of breathing patterns and apnea event counting, technicians may miss critical episodes requiring immediate pressure adjustments.
- Remote Adjustment Barriers: Changing CPAP pressure settings traditionally requires physical access to the device, introducing delays when multiple patients need simultaneous attention.
By digitizing the entire workflow and providing real-time analytics with bidirectional communication, this system transforms reactive sleep lab monitoring into a proactive, data-driven operation.
The Solution
The system delivers a complete patient monitoring workflow with four core capabilities:
-
Intelligent Signal Processing: Uploads raw CPAP pressure waveforms and automatically processes them through a physics-based signal analysis pipeline. The system converts analog-to-digital converter (ADC) values to Pascals, applies venturi tube fluid dynamics equations to calculate volumetric airflow, and uses peak detection algorithms to identify individual breaths and measure breathing rates with clinical accuracy.
-
Automated Apnea Detection: Analyzes breath timing patterns to automatically identify apnea events (breathing cessation exceeding 10 seconds). When apnea counts reach clinically significant thresholds, the interface highlights the alert in red, enabling immediate clinician response.
-
Longitudinal Patient Tracking: Maintains a comprehensive patient history indexed by room number with support for seamless patient turnover. The system intelligently handles room transitions—when a new patient is assigned to an existing room number, it archives the previous patient’s data and creates a fresh record, ensuring data integrity across multi-night studies.
-
Bidirectional Communication: Implements a polling-based update mechanism where patient-side clients query the server every 30 seconds for new CPAP pressure settings. Monitoring stations can remotely adjust pressures via GET requests, enabling centralized control over multiple simultaneous sleep studies without physical room visits.
Tech Stack & Architecture
The Stack
Backend & API Layer:
- Flask (RESTful API server with JSON serialization)
- SQLAlchemy ORM (database abstraction layer)
- SQLite (embedded relational database)
- Gunicorn (production-grade WSGI server)
Signal Processing & Analytics:
- NumPy (vectorized numerical computations)
- SciPy (peak finding algorithms and numerical integration via Simpson’s rule)
- Matplotlib (flow-rate waveform visualization)
Client Interface:
- Tkinter (native desktop GUI framework with custom styling)
- Pillow (image processing for base64 encoding)
- Streamlit (web-based monitoring dashboard)
Infrastructure & Deployment:
- Docker (containerization with multi-stage builds)
- GitHub Actions (automated pytest and pycodestyle CI)
Architectural Decision Matrix
Why Flask over FastAPI for the REST Layer? While FastAPI offers async capabilities and automatic OpenAPI documentation, Flask was the optimal choice for this use case. The application’s request patterns are inherently synchronous—data uploads from patient clients occur sporadically (once per CPAP file upload), not in high-frequency bursts. Flask’s simplicity and extensive SQLAlchemy integration reduced development complexity without sacrificing performance. For systems with less than 100 simultaneous clients, Flask’s WSGI model provides more than adequate throughput, and the mature ecosystem meant fewer integration gotchas during database session management.
Why SQLite over PostgreSQL? At first glance, a clinical system might demand a production database like PostgreSQL. However, analyzing the data access patterns revealed SQLite as the superior choice. The system uses room numbers as primary keys with a write-once, append-many pattern—patients rarely update existing records, they simply append new CPAP data arrays. SQLite’s file-based architecture eliminates network latency entirely, provides ACID transactions, and handles the moderate write volume (dozens of updates per hour) with ease. The entire database remains portable, which simplifies deployment to isolated VPS environments or local clinical networks where a dedicated database server adds unnecessary infrastructure overhead.
Why Tkinter over Web Interface for Patient Client? The desktop GUI decision was strategic. Sleep labs operate on secure, isolated networks where web browsers introduce security surface area concerns (CORS policies, session management, XSS vulnerabilities). Tkinter provides a native application experience with no external dependencies beyond Python itself, ensuring the client runs on locked-down clinical workstations without browser compatibility issues. The tradeoff is mobile accessibility, but in a clinical context where patients are stationary and technicians use dedicated monitoring terminals, a desktop application offers superior reliability and reduced attack vectors.
Technical Challenges
The most architecturally complex aspect of this system lies in the signal processing pipeline for apnea detection. The challenge stems from converting noisy, raw ADC sensor data into clinically meaningful breathing events—a multi-stage transformation that requires careful handling of edge cases.
The system first normalizes ADC integer values into Pascal pressure units using calibrated sensor coefficients, then applies venturi tube fluid dynamics to derive volumetric flow rates. The critical challenge emerges when identifying discrete breath events: human breathing produces asymmetric waveforms (inhalation peaks differ from exhalation troughs) with significant inter-breath variability. A naive threshold-based approach would trigger false positives from coughing, shifting, or equipment artifacts.
The solution implements a sophisticated peak-finding algorithm using SciPy’s find_peaks with tuned prominence and distance parameters. The system separately detects positive (inhalation) and negative (exhalation) peaks, then validates that each inhalation peak has a corresponding exhalation peak within a physiologically reasonable time window. This paired-validation approach ensures that detected breaths represent complete respiratory cycles rather than motion artifacts.
Apnea detection introduces another layer of complexity: the system must distinguish between normal inter-breath pauses and clinically significant cessation events. By calculating time deltas between consecutive validated breaths, the algorithm flags any gap exceeding 10 seconds as an apnea event. This temporal analysis requires precise timestamp management across the entire signal processing chain—any rounding errors or index mismatches would produce false apnea counts, potentially triggering unnecessary clinical interventions.
The final complexity involves handling state management for longitudinal patient tracking. The system must support three distinct data update scenarios: new patient creation, existing patient data appends, and same-room patient turnovers. The room turnover logic was particularly nuanced—when the Medical Record Number (MRN) changes for an existing room, the system must atomically delete the previous patient’s record and create a new one within a single database transaction. This prevents orphaned data and maintains referential integrity, but required careful design of the database session lifecycle to avoid race conditions during concurrent updates.
Lessons Learned
Domain-Driven Design Beats Premature Optimization The initial architecture almost went down the path of implementing WebSocket-based real-time updates for CPAP pressure changes. However, analyzing the actual clinical workflow revealed that pressure adjustments occur at most every few minutes, not every second. The 30-second polling interval perfectly matches the operational cadence of sleep lab technicians, proving that understanding user behavior and domain constraints is more valuable than chasing architectural trends. The system delivers the required functionality with 95% less complexity than a WebSocket implementation would have introduced.
State Consistency Requires Explicit Invariants The room turnover logic exposed a fundamental lesson about distributed state management. Early implementations allowed partial updates where a new patient could inherit remnants of the previous patient’s CPAP data arrays if the database transaction wasn’t properly scoped. Establishing explicit invariants—“an MRN change MUST trigger full record deletion before creation”—and encoding them as atomic database operations eliminated an entire class of data corruption bugs. In medical software, “eventually consistent” is often unacceptable; strong consistency guarantees are worth the performance cost.
Test-Driven Development Pays Dividends in Healthcare Software With pytest-driven development enforced via GitHub Actions CI, the system maintains high reliability despite frequent feature additions. Comprehensive unit tests for the signal processing pipeline caught multiple off-by-one indexing errors that would have manifested as incorrect apnea counts—errors that could have led to improper clinical decisions. In domains where software failures have patient safety implications, the discipline of writing tests before implementation isn’t just best practice—it’s a professional responsibility.
Future Directions
Based on the current architecture, several high-value enhancements present themselves:
Multi-Patient Real-Time Dashboard The system already includes a GET route for retrieving all patient records, but a dedicated Streamlit monitoring dashboard (already containerized alongside the Flask API) could provide a centralized view of all active sleep studies. Implementing live-updating visualizations with color-coded alerts for high apnea counts, breath rate anomalies, or overdue data uploads would transform the clinician experience from reactive polling to proactive monitoring. The backend infrastructure exists; it’s primarily a frontend visualization challenge.
Historical Trend Analysis & Predictive Alerts With longitudinal CPAP data stored as JSON arrays, the system is positioned to implement time-series analysis. Machine learning models trained on historical breath rate patterns could predict upcoming apnea events before they occur, allowing preemptive CPAP pressure adjustments. Even simple statistical approaches—like flagging patients whose apnea rates increase linearly over the course of a night—would provide actionable clinical intelligence currently missed by the reactive threshold-based alerts.
Security Hardening for HIPAA Compliance While the current system implements functional authentication boundaries (isolated networks, no internet exposure), production deployment in a real sleep lab would require formal HIPAA compliance. This includes implementing encrypted database storage (SQLite supports SQLCipher), audit logging for all patient data access, and role-based access control (RBAC) to distinguish between technician and physician privilege levels. The Flask-Login extension provides a straightforward path for session-based authentication, and SQLAlchemy’s event listeners could automatically log all database mutations to an immutable audit trail.
Try It Out
Check out the live demo or explore the source code on GitHub.