featured image

Sleep Lab Monitoring System: Real-Time CPAP Data Analytics for Critical Care

A full-stack medical monitoring system that enables real-time collection, analysis, and visualization of CPAP data for sleep apnea patients in clinical sleep labs.

Published

Wed Jun 11 2025

Technologies Used

Docker Python Streamlit Flask Pytest SQLite
View on GitHub

Live Demo

Loading demo...

What the Traditional Sleep Lab Workflow Gets Wrong

The standard approach to overnight sleep monitoring has a frustrating inefficiency built into it: technicians have to physically walk to a patient’s room to collect data. There’s no real-time view of apnea events as they happen. If a patient needs their CPAP pressure adjusted, someone has to go in the room to do it. For labs running multiple simultaneous studies, this gets unwieldy fast.

This system replaces that workflow with a full-stack monitoring platform. A desktop client on the patient side handles CPAP data uploads and signal processing. A REST API backend manages data and patient records. And a bidirectional communication layer lets monitoring stations remotely adjust CPAP pressure settings — so a technician can respond to an event without ever leaving their desk.

The Signal Processing Pipeline

The most technically interesting piece of the system is how raw CPAP data becomes clinical information. Raw ADC sensor values come off the device as integers. The pipeline converts those to Pascals using calibrated sensor coefficients, then applies venturi tube fluid dynamics to derive volumetric airflow. From there, peak detection algorithms identify individual breaths and measure breathing rate.

That last step is harder than it sounds. Human breathing produces asymmetric waveforms — inhalation peaks and exhalation troughs don’t look the same — with significant inter-breath variability. A naive threshold approach fires false positives on coughing, shifting, or equipment artifacts. The solution uses SciPy’s find_peaks with tuned prominence and distance parameters, detecting positive and negative peaks separately, then validating that each inhalation peak has a corresponding exhalation within a physiologically reasonable time window. Only complete respiratory cycles count.

Apnea detection layers on top of this. The system computes time deltas between consecutive validated breaths and flags any gap exceeding 10 seconds as an apnea event. Precise timestamp management matters here — any rounding error in the index chain produces false apnea counts, which in a clinical context could trigger unnecessary interventions.

Handling Patient Turnovers

The state management for longitudinal patient tracking turned out to be one of the more nuanced engineering problems in the project. The system needs to handle three distinct scenarios: new patient creation, appending data to an existing patient record, and room turnover when a new patient is assigned to an existing room number.

That last case is where things get tricky. When the Medical Record Number changes for an existing room, the system has to atomically delete the previous patient’s record and create a new one in a single database transaction. Early implementations allowed partial updates where a new patient could inherit remnants of the previous patient’s CPAP data if the transaction wasn’t properly scoped. Establishing the invariant — an MRN change must trigger full record deletion before creation — and encoding it as an atomic operation eliminated that entire class of data integrity bug.

Stack and the Reasoning Behind It

The system runs Flask as the REST API layer with SQLAlchemy and SQLite for data persistence, Tkinter for the patient-side desktop client, Streamlit for the monitoring dashboard, and Docker with GitHub Actions CI for infrastructure.

Flask over FastAPI made sense here because the request patterns are inherently synchronous — CPAP data arrives sporadically from patient clients, not in high-frequency bursts. Flask’s simplicity and mature SQLAlchemy integration reduced complexity without sacrificing anything the system actually needed.

SQLite over PostgreSQL was a similar call. The data access pattern is write-once, append-many, keyed by room number. SQLite’s file-based architecture eliminates network latency entirely, provides ACID transactions, and handles the write volume easily. A separate database server would add overhead with no real benefit.

The Tkinter desktop client was a deliberate choice over a web interface. Sleep labs run on secure, isolated networks. A web app introduces browser compatibility concerns, CORS policy management, and session handling that a native desktop app sidesteps entirely. For locked-down clinical workstations, Tkinter just works.

What I’d Do Differently

Apnea rate analysis and pressure adjustment occur at a scale of minutes, not seconds. I almost went down the path of implementing WebSocket-based real-time updates for CPAP pressure changes, but analyzing the actual clinical workflow made clear that 30-second polling intervals perfectly match how technicians actually operate. The system delivers what’s needed with a fraction of the complexity that WebSockets would have introduced. Understanding the domain first, then choosing the architecture — that turned out to be the most important thing.

Test-driven development wasn’t optional here. Comprehensive unit tests for the signal processing pipeline caught multiple off-by-one indexing errors that would have produced incorrect apnea counts in production. In a medical context, that kind of error isn’t just a bug — it’s a patient safety issue.

Where This Goes

The most obvious next step is the multi-patient monitoring dashboard. The backend already exposes a GET route for all active patient records, and the Streamlit container is already deployed alongside the API. Building live-updating visualizations with color-coded alerts for high apnea counts or overdue data uploads is primarily a frontend problem at this point — the infrastructure exists.

The longitudinal CPAP data stored as JSON arrays also positions the system well for time-series analysis. Even simple statistical approaches — flagging patients whose apnea rates increase linearly over the course of a night — would surface clinical intelligence that the current threshold-based alerts miss entirely.

Production deployment in a real sleep lab would also require formal HIPAA compliance work: encrypted database storage, audit logging for all patient data access, and role-based access control to separate technician and physician privilege levels. Flask-Login and SQLAlchemy’s event listeners would handle most of that; it’s a matter of building it out.

Try It Out

Check out the live demo or explore the source code on GitHub.

We respect your privacy.

← View All Projects

Related Tutorials

    Ask me anything!