Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

368 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HMS-CPAP

License: MIT GHCR Build Buy Me A Coffee

Lightweight C++ microservice for CPAP data collection with built-in web dashboard, PDF reports, and Home Assistant integration.

⚠️ Not a medical device

HMS-CPAP is a hobbyist data viewer. It is not a medical device, it is not cleared or approved by any regulator, and it cannot diagnose anything or tell you whether your therapy is working. It is not a monitoring or alarm system.

Never change your therapy settings based on this software. Talk to the clinician who manages your therapy. The numbers here can be wrong: the parsers read undocumented, reverse-engineered formats, and data collection can fail silently.

Read DISCLAIMER.md before using this. By using it you accept the Terms of Use.

This project is independent and is not affiliated with or endorsed by ResMed, Philips, Löwenstein, SleepHQ, or any other company named here. See NOTICE.

Automatically extracts sleep therapy data from ResMed and Lowenstein Prisma CPAP machines, parses EDF/WMEDF files with its own signal-analysis engine, and publishes 47+ metrics to Home Assistant via MQTT discovery. Includes a full Angular web UI with detailed waveform charting, PDF report generation, O2Ring pulse oximetry, automatic SleepHQ export, LLM-powered session summaries, and ML intelligence. Supports two data sources: ezShare WiFi SD with bridge, or local filesystem.

Screenshots

Dashboard -- Key metrics, AI session summary, therapy insights, STR daily indices, sleep events, pressure gauges, respiratory metrics, ML intelligence, and 30-day trend charts.

Dashboard

Sessions -- Nightly session list with O2Ring SpO2/HR, event breakdown, and live session indicator.

Sessions

Events -- Searchable table of every respiratory event across all nights. Filter by date range, event type, and minimum duration; every row links to its night.

Events

Session Detail -- Per-session metrics with O2Ring SpO2/HR overlay, 13 zoomable signal charts, event markers, and doughnut event distribution.

Session Detail

PDF Reports -- Generate multi-night therapy reports with date range picker. Download as PDF for sharing with your doctor.

Reports

Settings -- Configure data source, O2Ring oximetry, SleepHQ sync, database, MQTT, LLM summaries, ML training, and device identity. Hot-reload without restart.

Settings

Upload -- Bring data in by hand from any browser -- no shared network or WiFi SD required. Drop a CPAP .zip (ResMed or Lowenstein) and it merges into the archive and reparses; drop a Wellue O2 Ring .csv export and it parses server-side into an oximetry session. The O2 Ring path is a simple, OSCAR-free way to actually view your pulse-oximetry data.

Upload

Supported Devices

Manufacturer Models Live Sessions Data Import
ResMed AirSense 10, AirSense 11 Yes -- EDF files grow during therapy, real-time charts with 65s refresh Yes
Lowenstein Prisma Line (20A, 20C, 25S, 25ST), Prisma Smart (Max, Plus, Soft) No -- files written post-session Yes

All data sources (ezShare WiFi SD, local filesystem) work with both manufacturers -- the WiFi SD adapter sits in the machine's SD card slot regardless of brand.

ResMed EDF files grow incrementally during therapy, enabling live session monitoring with pulsing LIVE badge and auto-refreshing charts.

Lowenstein Prisma files are written atomically after each mask-on/mask-off cycle. Prisma Line machines write therapy.pdat (ZIP archive) to SD card. Prisma Smart machines write raw directory trees. Both formats are auto-detected. Full session parsing includes WMEDF signals, XML events, AHI/event metrics, and breathing summaries.

Features

  • HA-Style Web Dashboard - 10 section components with pressure gauges, AI summary, therapy insights, ML predictions
  • 2 Data Sources - ezShare WiFi SD + bridge, or local files
  • 47+ Metrics - AHI, leak rate, pressure, usage hours, events, daily summary, LLM AI summary
  • Home Assistant Auto-Discovery - Instant MQTT integration with 47 sensor entities
  • PDF Reports - Generate multi-night therapy reports for sharing with your doctor
  • Therapy Insights Engine - Automated analysis of AHI trends, leak correlation, compliance, best/worst nights
  • Pulse Oximetry - Wellue O2Ring SpO2/HR with ODI calculation, session overlay, and fallback in session cards
  • Manual Upload Page - Drag-and-drop a CPAP .zip or a Wellue O2 Ring .csv from any browser, no shared network needed. CPAP zips merge into the archive and reparse; O2 Ring CSVs (both Wellue export dialects, auto-detected sample interval) become oximetry sessions -- an OSCAR-free way to view your O2 ring data. See docs/UPLOAD.md
  • Equipment & Supply Reminders - Track machine and accessories per profile, with wear computed from your in-use dates. Publishes days-left and wear sensors to Home Assistant plus a due/overdue event so an automation fires once per crossing. Optional CpapDash cloud sync. See Equipment & Supplies
  • SleepHQ Auto-Export - Automatically forward each completed night's raw data to SleepHQ via their public API, toggleable on session complete and on local import, plus a manual per-night "Upload to SleepHQ" button
  • Multi-Database - PostgreSQL, MySQL/MariaDB, or SQLite (auto-created on first run)
  • Signal Charts - Per-minute resolution with event markers and oximetry overlay
  • Events Explorer - A searchable table of every respiratory event across all nights: filter by date range, event type, and minimum duration; every row links to its night. Reads the event store directly, so it never depends on the machine's daily summary being present
  • Live Sessions - Pulsing LIVE badge, 65s auto-refresh, growing charts during therapy
  • ML Intelligence - AHI prediction, compliance forecasting, mask fit risk, anomaly detection
  • LLM Session Summary - AI-generated therapy analysis via Ollama (daily, weekly, monthly)
  • Windows + Linux - Native builds for both platforms, Docker image for CI

Table of Contents

Quick Start

Download it, run it, and answer four screens in a browser. No config file, no terminal, no YAML.

Windows

Download CpapDashDesktop-Setup.exe from Releases and run it. It installs to your user profile, so it never asks for administrator rights. When it finishes, CpapDash Desktop appears in the notification area and your browser opens on the setup wizard.

The tray icon gives you Open Dashboard, Sync Now, and a Start at Login checkbox. It keeps the service running and restarts it with you.

macOS and Linux

Download hms-cpap-macos-arm64.zip (or build from source on Linux), unzip, and run the binary:

./hms_cpap

Your browser opens on http://localhost:8893/setup. If you are on a headless box or in a script, pass --no-browser and open that URL yourself.

What the wizard asks

  1. Where the data lives. The built in option is a single file in your data folder and needs nothing installed. If you already run PostgreSQL or MySQL, choose it and CpapDash will test the connection, tell you whether that database already holds sessions, and offer to create it for you.
  2. Where the data comes from. Scan the network for a CpapDash Mule and Miner, point at a folder of card files, or enter an ezShare address.
  3. Anything else, all optional and all off by default: Home Assistant over MQTT, plain language night summaries from a local LLM, machine learning insights, and mirroring your equipment and cleaning lists to a CpapDash account.
  4. Whether it starts by itself, at login or at boot.

Press Finish and it writes the config, restarts itself, and lands you on the dashboard.

Checking a configuration without starting

./hms_cpap --preflight

Validates the data folder, the web port, the database credentials and the source, then tells you what is wrong and what to change. Startup runs the same checks and refuses to boot rather than half starting, so a busy port or a wrong password is named once instead of turning into a restart loop.

Build from source

git clone https://github.com/hms-homelab/hms-cpap.git
cd hms-cpap
mkdir build && cd build
cmake .. && make -j$(nproc)
./hms_cpap

The wizard works the same way from a source build. Everything below this point is for people who would rather set things by hand, which is still fully supported: the wizard only writes the same config.json you can edit yourself.

Data Sources

One wireless hardware path plus a local filesystem option. Both work with ResMed and Lowenstein machines -- the WiFi SD adapter sits in any standard SD card slot:

ezShare WiFi SD (Recommended)

How it works: The ezShare creates its own WiFi AP, which means it can't talk to your home network directly. You'll need a bridge to bring it onto your network. A convenient dual-WiFi bridge is provided by hms-mm -- one radio connects to the ezShare, the other to your home WiFi, and it serves the files over HTTP. HMS-CPAP polls the bridge every 65s.

Hardware (optional): ezShare WiFi SD adapter + a bridge device running hms-mm firmware.

Local Filesystem

How it works: Reads EDF files directly from a local directory (USB drive, NAS share, or mounted storage).

Use case: Offline analysis, importing historical data, or running without WiFi SD hardware.

Setup:

  1. Copy the whole ResMed SD card to a local path (or mount the card directly). Copy the card ROOT, not just DATALOG: STR.edf sits beside DATALOG, and without it you lose the machine's own nightly summaries.

    # Example: mount SD card
    sudo mount /dev/sdb1 /mnt/cpap-sd
    
    # Or copy to NAS/local disk. Note the trailing /. copies the card CONTENTS
    cp -r /mnt/cpap-sd/. /mnt/archive/cpap/

    The result must look like this:

    /mnt/archive/cpap/          <-- this is what you configure
    ├── STR.edf                 <-- nightly summaries
    ├── Identification.tgt
    └── DATALOG/
        ├── 20260206/
        └── 20260207/
    
  2. Configure hms-cpap to use local mode. local_dir is the card ROOT, the folder holding both STR.edf and DATALOG. Never DATALOG itself.

    CPAP_SOURCE=local
    CPAP_LOCAL_DIR=/mnt/archive/cpap

    Or via ~/.hms-cpap/config.json:

    {
      "source": "local",
      "local_dir": "/mnt/archive/cpap"
    }

    If you point it at DATALOG by mistake, hms-cpap refuses to import and shows a red banner naming the folder to use instead. It keeps serving nights you have already imported, so nothing is lost, but nothing new is added until the path is corrected.

  3. Start hms-cpap. It will poll the directory each burst interval for new sessions.

  4. Import existing history: Open Settings in the web UI, expand "Import History", and click Import History. The start/end dates auto-populate from your DATALOG folder. This parses all EDF files and saves them to the database. See also the CLI Reference for command-line alternatives.

Expected directory structure:

DATALOG/
  20250815/
    23243570851_BRP.edf    # Breathing pattern
    23243570851_PLD.edf    # Pressure/leak data
    23243570851_EVE.edf    # Events (apneas, hypopneas)
    23243570851_SAD.edf    # SpO2/heart rate (if oximeter)
    23243570851_CSL.edf    # Clinical summary
  20250816/
    ...
  STR.edf                  # Daily therapy summaries

Lowenstein Prisma

Both data source paths above (ezShare, local) work with Lowenstein machines. Set CPAP_SOURCE=lowenstein and point CPAP_LOCAL_DIR at the SD card contents or a copy. HMS-CPAP auto-detects both Prisma formats:

Prisma Smart writes a raw directory tree:

therapy/
  events/
    20260514/
      event_000370.xml      # Respiratory events (apneas, hypopneas)
    20260515/
      event_000380.xml
  signals/
    20260514/
      signal_000370.wmedf   # Therapy signals (pressure, flow, SpO2)
    20260515/
      signal_000380.wmedf

Prisma SMART max (newer firmware, e.g. 3.17) writes a combined tree, with events and signals together under a per-night session folder and 3-digit sequence numbers:

0040181394/                # device serial
  20260607/
    0000/                  # session index
      event_000.xml
      signal_000.wmedf
      trendCurves.tc
  20260620/
    0001/
      event_003.xml
      signal_003.wmedf

Point local_dir at either the SD root (containing the serial folder) or the serial folder itself; HMS-CPAP detects this layout automatically.

Prisma Line writes ZIP archives:

therapy.pdat              # ZIP containing the directory tree above
config.pcfg               # ZIP containing device.xml and configuration

Configuration example:

{
  "source": "lowenstein",
  "local_dir": "/mnt/archive/prisma",
  "device_name": "Lowenstein Prisma 20A"
}

Configuration

The setup wizard writes everything below for you, so this section is for people editing by hand or automating an install.

config.json in your data folder is the source of truth. It lives at ~/.hms-cpap/config.json (%USERPROFILE%\.hms-cpap\config.json on Windows), and the Settings page and the wizard both write to it. Environment variables still work as a fallback for anything the file does not set, which is what makes container and systemd deployments straightforward, but where both exist the file wins.

Run ./hms_cpap --preflight after editing to check the result before starting.

See .env.example for the complete list of variable names, and config.json.example for the file form.

Required Variables

# Data source
CPAP_SOURCE=ezshare          # ezshare or local
EZSHARE_BASE_URL=http://192.168.4.1  # ezShare bridge IP

# MQTT broker (required for Home Assistant)
MQTT_BROKER=localhost
MQTT_PORT=1883
MQTT_USER=mqtt_user
MQTT_PASSWORD=your_mqtt_password

Optional Variables

# Local directory (required when CPAP_SOURCE=local, config.json key: local_dir)
# The SD card ROOT: the folder holding BOTH STR.edf and DATALOG. Not DATALOG.
CPAP_LOCAL_DIR=/path/to/card-root

# Device identification
CPAP_DEVICE_ID=resmed_airsense10
CPAP_DEVICE_NAME="ResMed AirSense 10"

# Collection interval (seconds)
BURST_INTERVAL=65

# Database (defaults to SQLite if not set)
DB_TYPE=sqlite                # sqlite, postgresql, or mysql
DB_HOST=localhost
DB_NAME=cpap_data
DB_USER=cpap_user
DB_PASSWORD=your_db_password

# Web UI port
WEB_PORT=8893

CLI Reference

HMS-CPAP supports several command-line modes for batch operations. These run once and exit (no web server, no polling loop).

Reparse Sessions

Re-parse therapy sessions from a local DATALOG archive for a date range. Deletes existing DB records for those dates and re-imports from the EDF files.

# Reparse a date range
hms_cpap --reparse /path/to/DATALOG 2025-08-15 2025-09-15

# Reparse a single day
hms_cpap --reparse /path/to/DATALOG 2025-08-15

This is the CLI equivalent of the "Import History" button in the web UI Settings page.

Backfill STR Daily Summaries

Parse a ResMed STR.edf file and upsert all daily therapy summaries into the database. This populates the cpap_daily_summary table with AHI, usage hours, leak rates, and other per-day metrics.

hms_cpap --backfill /path/to/STR.edf

Custom Config Path

hms_cpap --config /etc/hms-cpap/config.json

Docker

docker compose up -d

Brings up CpapDash, PostgreSQL and a Mosquitto broker. Open http://localhost:8893/setup and answer the same wizard. The compose file waits for PostgreSQL to actually accept connections before starting CpapDash, so the first run does not race the database while it initialises.

Docker owns the lifecycle here, so the wizard does not offer to install a startup entry. restart: unless-stopped in the compose file plus Docker itself starting at boot is what makes it survive a reboot, and the wizard says so rather than showing you a checkbox that would write a systemd unit into a container that has no systemd.

Your data lives in the cpap_data volume and your config in cpap_config. Neither is touched by pulling a new image.

Deployment

Native Systemd (Recommended)

# Build frontend + backend, run tests, and deploy
./build_and_deploy.sh --deploy

# Or manually:
cd frontend && npm ci && npx ng build --configuration production && cd ..
mkdir build && cd build && cmake -DBUILD_WITH_WEB=ON .. && make -j$(nproc)
sudo cp hms_cpap /usr/local/bin/
sudo cp ../.env /etc/hms-cpap/.env  # Edit with your settings

# Service file: /etc/systemd/system/hms-cpap.service
[Unit]
Description=HMS-CPAP Data Collection Service
After=network.target postgresql.service emqx.service

[Service]
Type=simple
EnvironmentFile=/etc/hms-cpap/.env
ExecStart=/usr/local/bin/hms_cpap
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable hms-cpap
sudo systemctl start hms-cpap

Docker

docker run -d \
  --name hms-cpap \
  --env-file .env \
  -p 8893:8893 \
  -v cpap_config:/config \
  -v cpap_data:/data \
  ghcr.io/hms-homelab/hms-cpap:latest

/config holds config.json, which is where setup_complete and everything the setup wizard writes lives. Keep it on a volume: without one it sits in the container's writable layer, so docker compose down (or any image update) discards your configuration and the next start returns to the setup wizard.

Mounting your CPAP data read-only for CPAP_SOURCE=local? Point the mount at the SD card root -- the folder that contains both STR.edf and DATALOG/ -- not at DATALOG itself. STR.edf is what carries the machine's own nightly aggregates (mask on/off pairs, leak percentiles, therapy mode). Without it the dashboard is still populated, but from the sessions alone, so those fields stay empty.

Raspberry Pi

Two deployment scripts are provided for running hms-cpap on a Raspberry Pi. Both read PI_HOST and PI_PASSWORD from environment variables or your .env file -- no hardcoded IPs or passwords.

Setup: Add your Pi credentials to .env:

# In .env
PI_HOST=user@192.168.1.50
PI_PASSWORD=your_password

Or pass them inline:

PI_HOST=user@192.168.1.50 PI_PASSWORD=mypass ./deploy_to_pi.sh

If either variable is missing, the script exits with a clear error message telling you what to set.

Cross-compile deploy (build on your machine, deploy ARM binary to Pi):

./deploy_to_pi.sh

Builds the Angular frontend, cross-compiles the C++ backend for ARM, copies the binary and static files to the Pi, and restarts the service.

Native build deploy (push code to Pi, build on Pi):

./deploy_to_pi_native.sh

Pushes via git, builds natively on the Pi (slower but avoids cross-compilation issues), deploys, and restarts. Use this if cross-compiled binaries have issues on your Pi model.

Windows

Download the latest release from Releases. Unzip and run:

# Edit config.example.json with your settings
hms_cpap.exe
# Open http://localhost:8893

Equipment & Supplies

Track what you actually run and get told when a part is due, without a spreadsheet.

Profiles

A profile is one named setup: exactly one machine plus its accessories. Most people need a single profile. A second is useful when you genuinely run two rigs -- a home AirSense and a travel AirMini, say -- and want their wear tracked apart.

Each item records what it is (from a type catalog), optionally brand and model, the date you started using it, and how often it should be replaced. Leave the interval blank to inherit the type's default; set it to override.

Wear is computed, never stored

Nothing runs a nightly job to decrement a counter. Days-left and wear percent are derived from your in-use date and the interval every time they are read, so a value can never drift, go stale, or need repairing after downtime. Change the date and every number updates instantly.

An item is untracked if it has no in-use date, or no interval -- machines included. Untracked items are skipped rather than reported as 0% worn, because a sensor pinned at zero forever is worse than no sensor.

States: fresh, due_soon (inside 14 days), overdue.

In Home Assistant

Published on the normal collection cycle, under your existing CPAP device -- no extra scheduler, no new integration to install.

Retained sensors (state -- what IS true):

cpap/<device_id>/supplies/<profile>_<type>/days_left
cpap/<device_id>/supplies/<profile>_<type>/wear_percent
cpap/<device_id>/supplies/due                          # ON if anything is due

Events (what just CHANGED) -- not retained, one message per crossing:

cpap/<device_id>/supplies/event
{"entity":"home_mask","profile":"Home","type":"mask",
 "from":"fresh","state":"overdue","days_left":-3,"replace_by":"2026-07-16"}

Retained state cannot say "this just went overdue" -- the value looks identical on the cycle it crossed and every cycle after -- so an automation built on state alone either fires once and misses later items, or re-fires on every cycle. The event topic exists for exactly that, and it fires on the crossing back to fresh too so an automation can clear whatever it raised. Crossings are remembered across restarts, so a restart does not re-announce anything.

automation:
  - alias: CPAP supply due
    trigger:
      platform: mqtt
      topic: cpap/cpap_resmed_12345/supplies/event
    condition: "{{ trigger.payload_json.state in ['due_soon', 'overdue'] }}"
    action:
      service: notify.mobile_app_phone
      data:
        message: >-
          {{ trigger.payload_json.type }} is
          {{ trigger.payload_json.state | replace('_', ' ') }}

Optional cloud sync

Equipment can mirror to CpapDash so the same profiles appear in the app. Off by default, opt-in with a pasted token, and local stays the source of truth -- an unreachable cloud degrades to local-only with no data loss. Only equipment data syncs; therapy and session data never leave. See PRIVACY.md.

Home Assistant Integration

HMS-CPAP uses MQTT Discovery for automatic Home Assistant integration.

1. Configure MQTT in Home Assistant

configuration.yaml:

mqtt:
  broker: localhost
  username: mqtt_user
  password: your_mqtt_password
  discovery: true

2. Restart Home Assistant

Sensors auto-appear as a device with 47+ entities:

  • sensor.cpap_ahi - Apnea-Hypopnea Index
  • sensor.cpap_leak_rate - Leak rate (L/min)
  • sensor.cpap_pressure_current - Current pressure (cmH2O)
  • sensor.cpap_usage_hours - Total usage hours
  • binary_sensor.cpap_session_active - Live session indicator
  • ... and 42 more metrics

Architecture

┌─────────────────┐     ┌──────────────────┐
│  ResMed CPAP    │     │ Lowenstein Prisma │
│  AirSense 10/11 │     │ Line / Smart      │
└────────┬────────┘     └────────┬──────────┘
         │ SD Card Slot          │ SD Card Slot
         │                       │
         └───────────┬───────────┘
                     │
             ┌───────────┴───────────┐
             │                       │
             ▼                       ▼
       ┌──────────┐            ┌──────────┐
       │ ezShare  │            │  Local   │
       │ WiFi SD  │            │  FS/USB  │
       └────┬─────┘            └────┬─────┘
            │ WiFi AP               │
            ▼                       │
       ┌──────────┐                 │
       │ hms-mm   │                 │
       │ bridge   │                 │
       └────┬─────┘                 │
            │ HTTP                  │
            ▼                       ▼
┌──────────────────────────────────────────┐
│            HMS-CPAP Service              │
│  BurstCollector + PrismaIngestion        │
│  EDFParser + PrismaParser (WMEDF/XML)    │
│  Angular Web UI (port 8893)              │
│  PDF Reports + LLM Summary + ML Intel    │
└──────────┬──────────┬────────────────────┘
           │          │
    ┌──────┘          └──────┐
    ▼                        ▼
┌──────────┐       ┌──────────────┐
│ Database │       │ MQTT (EMQX)  │
│ PG/MySQL │       │ 47 sensors   │
│ /SQLite  │       └──────┬───────┘
└──────────┘              │
                          ▼
                  ┌───────────────┐
                  │Home Assistant │
                  └───────────────┘

ResMed EDF File Types

File Content During Therapy After Mask-Off
BRP.edf Flow/pressure (25 Hz) Grows every 60s Final flush
PLD.edf Pressure/leak (0.5 Hz) Grows every 60s Final flush
SAD.edf SpO2/HR (1 Hz) Grows every 60s Final flush
EVE.edf Apnea/hypopnea events Updated live Final flush
CSL.edf Clinical summary Created at start Final flush
STR.edf Daily therapy summary N/A Written ~50s after mask-off

Lowenstein Prisma File Types

File Content Notes
signal_NNNNNN.wmedf Therapy signals (pressure, flow, leak, SpO2, HR) 8-bit or 16-bit EDF variant, 1s resolution
event_NNNNNN.xml Respiratory events (apneas, hypopneas, RERA, snore) Flat XML with RespEvent and DeviceEvent elements
device.xml Device serial number, type, firmware version In config.pcfg ZIP or conf/ directory

Development

Build Requirements

  • C++17 compiler (GCC 9+, Clang 10+, MSVC 2022+)
  • CMake 3.16+
  • Node.js 22+ (for Angular frontend)

Build & Test

The recommended way to build is via the build script, which handles frontend + backend + tests in one step:

# Build everything (frontend + backend + run tests)
./build_and_deploy.sh

# Build and deploy to systemd service
./build_and_deploy.sh --deploy

# Backend only (skip Angular build)
./build_and_deploy.sh --skip-fe

Or manually:

# Build frontend
cd frontend && npm ci && npx ng build --configuration production && cd ..

# Build backend
mkdir build && cd build
cmake -DBUILD_TESTS=ON -DBUILD_WITH_WEB=ON ..
make -j$(nproc)

# Run tests
./tests/run_tests

# Run service
./hms_cpap

Database Setup

SQLite (default) -- auto-created, no setup needed.

PostgreSQL:

psql -U postgres -c "CREATE DATABASE cpap_monitoring;"
psql -U postgres -d cpap_monitoring -f scripts/schema.sql

MySQL:

mysql -u root -e "CREATE DATABASE cpap_monitoring;"
mysql -u root cpap_monitoring < scripts/schema_mysql.sql

Running Tests

cd build && ./tests/run_tests

425 tests across 34 test suites covering EDF/WMEDF parsing, session discovery, Prisma ingestion, ezShare firmware compatibility, MQTT publishing, database operations, ML training, and more.

FAQ

Why not use existing CPAP data solutions?

Most solutions require cloud services, proprietary apps, or manual SD card removal. HMS-CPAP provides:

  • 100% local, no cloud
  • Automatic collection via WiFi
  • Built-in web dashboard with full signal charting
  • Open-source parsing & analysis algorithms
  • Home Assistant integration
  • ML-ready database storage

Does this work with other CPAP brands?

Currently supports ResMed AirSense 10/11 (real-time + import) and Lowenstein Prisma (import). ResMed has full real-time live session support via WiFi SD adapters. Lowenstein Prisma supports SD card data import with full session parsing, event detection, and breathing signal analysis.

What about data privacy?

All data stays local:

  • No cloud services
  • No external API calls
  • Your network only

Can I use this alongside OSCAR?

Yes. HMS-CPAP reads the same SD-card files independently, so you can run both simultaneously and cross-validate metrics.

Contributing

Contributions welcome! Please:

  1. Fork repository
  2. Create feature branch (git checkout -b feature/amazing-feature)
  3. Add tests for new functionality
  4. Ensure tests pass (./tests/run_tests)
  5. Open Pull Request

Legal

Document What it covers
DISCLAIMER.md Not a medical device. Read this first.
LICENSE MIT License -- the binding grant
TERMS.md Terms of use, warranty, liability, contributions
PRIVACY.md What is stored, and every way data can leave your machine
NOTICE Trademarks, independence, clean-room statement, dependencies

License

MIT -- see LICENSE. Use it, modify it, sell it; keep the notice.

Independence

Not affiliated with, endorsed by, or supported by ResMed, Philips, Lowenstein Medical, SleepHQ, or any other company named in this repository. All trademarks belong to their owners and are used descriptively. See NOTICE.

The parsers were written independently from public format documentation and inspection of files from physically owned devices. No OSCAR source code was copied or derived from -- OSCAR is GPLv3 and was consulted only to understand device data formats. See NOTICE section 2.

Privacy at a glance

No telemetry, no analytics, no phone-home. Your data stays on your hardware. The only outbound integrations are SleepHQ export, CpapDash sync, and LLM summaries -- all off by default and each one you enable yourself. The service ships with no authentication; do not expose it to the internet. Details in PRIVACY.md.

Third-Party Components

Full list with licenses in NOTICE. Direct dependencies include Drogon, libcurl, OpenSSL, SQLite, libpqxx/libpq, Paho MQTT (EPL 2.0), JsonCpp, nlohmann/json, spdlog, miniz, Angular, and Chart.js.

Acknowledgments

  • The open-source CPAP community - public documentation of the EDF/WMEDF file formats
  • ResMed - CPAP hardware
  • Lowenstein Medical - Prisma CPAP hardware
  • Home Assistant - Smart home platform
  • CPAP community on Reddit

Made for better sleep and open health data

If this project helps you, consider starring the repository!


Support

If this project is useful to you, consider buying me a coffee!

Buy Me A Coffee

About

ResMed CPAP data collection service for Home Assistant. Collects therapy data via ez Share WiFi SD card with OSCAR-compatible metrics.

Topics

Resources

Contributing

Stars

70 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages