Skip to content

discocracker02/cpap-mask-monitor

Repository files navigation

CPAP Mask Monitor

A lightweight background service that detects when your CPAP mask is removed during sleep and alerts you immediately via Pushover. Runs on macOS, Windows, Linux, or a Raspberry Pi Zero 2W.


⚠️ Legal Disclaimer

This tool is not a medical device. It is not intended to diagnose, treat, cure, or monitor any medical condition.

Use of this software is entirely at your own risk. The authors and contributors accept no liability whatsoever for any harm, injury, loss of sleep quality, missed alerts, false alerts, or any other outcome β€” direct or indirect β€” arising from the use or misuse of this software.

  • Do not rely on this tool as your sole method of CPAP compliance monitoring
  • Always consult your physician or sleep specialist regarding your CPAP therapy
  • This tool is a personal convenience project shared freely with the community
  • By using this software, you agree that you are solely responsible for any consequences

The Problem

Severe obstructive sleep apnea (OSA) requires consistent CPAP therapy throughout the night. However, many users β€” especially those with high pressure requirements β€” tend to unconsciously remove their mask during REM or deep sleep when discomfort peaks. When this happens, therapy stops completely, OSA events return, and sleep quality suffers β€” often without the user even remembering it happened.

ResMed's MyAir app shows a morning summary, but by then the damage is done. There was no way to get a real-time alert the moment the mask came off.

This project solves that.


How It Works

A smart plug with energy monitoring sits between your CPAP machine and the wall socket. The monitor polls the plug every 2 minutes (configurable) and reads the current power consumption in watts:

  • Mask on, therapy running: varies by machine and pressure setting
  • Mask off, machine idle/stopped: low standby wattage

When the monitor detects a sustained low watt reading across multiple consecutive readings, it starts a timer. If the mask stays off long enough, it fires a Pushover push notification to your phone β€” with priority 2 (emergency), which bypasses Silent mode and Do Not Disturb.

CPAP Machine β†’ Smart Plug β†’ Local WiFi β†’ Monitor (Mac/PC/Pi) β†’ Pushover β†’ Phone/Watch

Requirements

Hardware

  • CPAP machine β€” tested with ResMed AirSense 10 and AirSense 11. Should work with any CPAP/APAP/BiPAP machine.
  • Smart plug with energy monitoring β€” see Supported Devices
  • A device to run the monitor β€” Mac, Windows PC, Linux machine, or Raspberry Pi Zero 2W (or any Pi)

Software

  • Python 3.10 or later (3.11+ recommended)
  • Pushover account β€” one-time $5 purchase per platform (iOS or Android). Free 30-day trial available.
  • Smart plug account (Tapo, Kasa, or Tuya)

Network

  • Monitor device and smart plug must be on the same local WiFi network
  • Internet connection required for Pushover alerts

Cost

Item Cost
This software Free
Tapo P110 smart plug ~β‚Ή1,500–2,000 / ~$18–25
Pushover app (iOS or Android) $5 one-time
Raspberry Pi Zero 2W (optional) ~β‚Ή1,500 / ~$15

Installation

Option A β€” Mac / Linux / Raspberry Pi (recommended)

git clone https://github.com/discocracker02/cpap-mask-monitor.git
cd cpap-mask-monitor
bash install.sh

The installer will:

  1. Check Python version
  2. Install required libraries
  3. Create config.json from the example and open it for you to fill in
  4. Register a background service that starts automatically on boot
  5. Start the monitor

Option B β€” Windows

git clone https://github.com/discocracker02/cpap-mask-monitor.git
cd cpap-mask-monitor
pip install tapo requests
copy config.example.json config.json

Edit config.json with your credentials, then run:

python cpap_monitor.py

To run automatically on startup, add a shortcut to cpap_monitor.py in your Windows Startup folder (Win + R β†’ shell:startup).

Option C β€” Manual setup (all platforms)

1. Clone the repo:

git clone https://github.com/discocracker02/cpap-mask-monitor.git
cd cpap-mask-monitor

2. Install dependencies:

pip3 install tapo requests

3. Create config:

cp config.example.json config.json   # Mac/Linux
copy config.example.json config.json  # Windows

Edit config.json with your credentials (see Configuration).

4. Test it works:

python3 cpap_monitor.py

You should see power readings appearing every 2 minutes.


πŸ“ Raspberry Pi Zero 2W Setup (Recommended for 24/7 use)

Running the monitor on a Pi Zero 2W is the best long-term setup. It runs silently 24/7, uses almost no power (~0.5W), and doesn't tie up your laptop or Mac. Any Raspberry Pi model will work.

What you need

  • Raspberry Pi Zero 2W (or any Pi model)
  • MicroSD card (16GB or larger)
  • Micro USB power adapter (Pi Zero 2W) or USB-C (Pi 4/5)
  • Micro USB OTG adapter (for Pi Zero 2W, to connect peripherals)
  • A computer to set it up from

Step 1 β€” Flash the OS

  1. Download and install Raspberry Pi Imager
  2. Insert your microSD card
  3. Open Raspberry Pi Imager
  4. Choose Raspberry Pi Zero 2W as the device
  5. Choose Raspberry Pi OS Lite (64-bit) β€” no desktop needed
  6. Click the settings gear icon and configure:
    • Set hostname: snoozesense (or any name you like)
    • Enable SSH
    • Set username: pi (or your preferred name)
    • Set password
    • Configure WiFi with your network name and password
  7. Flash the card and insert it into the Pi

Step 2 β€” First boot and SSH

Power on the Pi. Wait 2 minutes, then SSH in from your computer:

ssh pi@snoozesense.local

If that doesn't work, find the Pi's IP in your router's connected devices list and use:

ssh pi@192.168.x.x

Step 3 β€” Reserve a static IP (recommended)

Open your router admin page and find the DHCP reservation section. Reserve a fixed IP for your Pi using its MAC address. This ensures the Pi always gets the same IP address so nothing breaks after a reboot.

Step 4 β€” Install Python and dependencies

sudo apt update && sudo apt upgrade -y
sudo apt install -y python3-pip python3-venv git

Create a virtual environment:

cd ~
python3 -m venv cpap-env
source cpap-env/bin/activate

Clone the repo and install:

git clone https://github.com/discocracker02/cpap-mask-monitor.git
cd cpap-mask-monitor
pip install tapo requests

Step 5 β€” Configure

cp config.example.json config.json
nano config.json

Fill in your Tapo credentials, plug IP, and Pushover keys. See Configuration for all options.

Save with Ctrl+X β†’ Y β†’ Enter.

Step 6 β€” Test it manually

python3 cpap_monitor.py

You should see power readings every 2 minutes. Press Ctrl+C to stop.

Step 7 β€” Set up as a systemd service (auto-start on boot)

Create the service file:

sudo nano /etc/systemd/system/cpap-monitor.service

Paste this (replace pi with your username if different):

[Unit]
Description=CPAP Mask Monitor
After=network.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/cpap-mask-monitor
ExecStart=/home/pi/cpap-env/bin/python3 /home/pi/cpap-mask-monitor/cpap_monitor.py
Restart=always
RestartSec=30

[Install]
WantedBy=multi-user.target

Save with Ctrl+X β†’ Y β†’ Enter.

Enable and start:

sudo systemctl enable cpap-monitor
sudo systemctl start cpap-monitor
sudo systemctl status cpap-monitor

You should see Active: active (running). The monitor will now start automatically every time the Pi boots.

Step 8 β€” Verify it's working

Check the log:

cat ~/cpap-mask-monitor/cpap_monitor.log

You should see timestamped power readings. You're done β€” the Pi will run silently overnight, every night.

Useful Pi commands

# Check service status
sudo systemctl status cpap-monitor

# View live log
tail -f ~/cpap-mask-monitor/cpap_monitor.log

# Restart service
sudo systemctl restart cpap-monitor

# Safely shut down Pi before unplugging
sudo shutdown now

Configuration

Copy config.example.json to config.json and fill in your details:

{
  "plug_type": "tapo",
  "tapo": {
    "email": "your_tapo_account_email@example.com",
    "password": "your_tapo_account_password",
    "ip": "192.168.x.x"
  },
  "pushover": {
    "user_key": "your_pushover_user_key",
    "app_token": "your_pushover_app_token"
  },
  "monitor": {
    "poll_seconds": 120,
    "idle_minutes": 15,
    "watt_threshold": 3,
    "confirm_count": 5,
    "sleep_start_hour": 22,
    "sleep_end_hour": 9,
    "timezone_offset_hours": 5.5
  }
}

Config reference

Key Recommended Description
tapo.email β€” Your TP-Link/Tapo account email
tapo.password β€” Your TP-Link/Tapo account password
tapo.ip β€” Local IP of your Tapo plug
pushover.user_key β€” Your Pushover user key
pushover.app_token β€” Your Pushover app token
poll_seconds 120 How often to poll the plug (seconds)
idle_minutes 15 How long mask must be off before alert fires
watt_threshold 3 Watts below which mask is considered off
confirm_count 5 Consecutive low readings before timer starts
sleep_start_hour 22 Hour monitoring starts (24h format)
sleep_end_hour 9 Hour monitoring stops (24h format)
timezone_offset_hours 5.5 Your UTC offset (India = 5.5, US EST = -5)

Calibrating watt_threshold for your machine

Important: The recommended values above (watt_threshold: 3, confirm_count: 5) are based on testing with a ResMed AirSense 11 AutoSet. Your machine may draw different power levels depending on the model, pressure settings, and humidifier use. Always calibrate for your own machine.

How to calibrate:

  1. Run python3 cpap_monitor.py and watch the log
  2. Note the watts while wearing the mask with therapy running β€” this is your active range
  3. Note the watts when the machine is on standby (mask off, machine idle) β€” this is your idle value
  4. Set watt_threshold to a value between idle and the lowest active reading
  5. Set confirm_count higher if you get false alerts β€” this requires more consecutive low readings before confirming mask-off

Example β€” ResMed AirSense 11 AutoSet:

  • Active therapy: 3–7W (varies with pressure)
  • Standby / idle: 2W
  • Recommended threshold: 3W
  • Recommended confirm_count: 5 (10 minutes of polling before confirming)

Example β€” ResMed AirSense 10 AutoSet:

  • Active therapy: 6–15W
  • Standby / idle: 2–3W
  • Recommended threshold: 5W
  • Recommended confirm_count: 2–3

Tip: Use your smart plug's own app (Tapo app, Kasa app etc.) to watch live power readings for 10–15 minutes while using your CPAP. This gives you a clear picture of your machine's power profile before setting any thresholds.

Finding your Tapo plug IP

Open the Tapo app β†’ tap your plug β†’ tap the settings icon β†’ Device Info β†’ IP Address.

Tip: Reserve a static IP for your plug in your router's DHCP settings so the IP never changes.


Pushover Setup

Pushover is the notification service that sends alerts to your phone and Apple Watch or Wear OS watch. It costs $5 once and works on both iOS and Android.

Step 1 β€” Create your account

  1. Go to pushover.net and create a free account
  2. On your dashboard, note your User Key β€” you'll need this for config.json
  3. Click Create an Application/API Token
  4. Give it a name (e.g. "CPAP Monitor") and click Create
  5. Note the API Token β€” you'll need this too

Step 2 β€” Install on iPhone + Apple Watch

  1. Download Pushover from the App Store
  2. Log in with your pushover.net account
  3. Open Settings inside the Pushover app
  4. Tap Notification Settings
  5. Enable Critical Alerts β€” this is essential. It bypasses Silent mode and all Focus modes including Sleep Focus
  6. If you have an Apple Watch, the Pushover app installs automatically on the watch via the Watch app
  7. On your Apple Watch, open the Watch app on iPhone β†’ scroll to Pushover β†’ enable Show App on Apple Watch
  8. Critical alerts will now appear on both your iPhone and Apple Watch even when your phone is silenced

Step 3 β€” Install on Android + Wear OS

  1. Download Pushover from the Google Play Store
  2. Log in with your pushover.net account
  3. Open the app β†’ Settings β†’ Notification Channels
  4. Enable the Emergency channel β€” this allows alerts to bypass Do Not Disturb
  5. If you have a Wear OS watch (Galaxy Watch, Pixel Watch etc.), notifications mirror automatically from your phone
  6. To ensure watch alerts work: on your phone go to Settings β†’ Notifications β†’ find Pushover β†’ enable "Allow notification mirroring" or similar (varies by Android version)

Step 4 β€” Test your setup

Run this command from your terminal (replace with your actual keys):

curl -s \
  --form-string "token=YOUR_APP_TOKEN" \
  --form-string "user=YOUR_USER_KEY" \
  --form-string "title=CPAP Monitor Test" \
  --form-string "message=Test alert β€” your setup is working!" \
  --form-string "priority=2" \
  --form-string "retry=60" \
  --form-string "expire=300" \
  https://api.pushover.net/1/messages.json

You should receive a loud alert on your phone and watch within a few seconds.


Supported Devices

Tested

Device Status
TP-Link Tapo P110 βœ… Tested
ResMed AirSense 10 AutoSet βœ… Tested
ResMed AirSense 11 AutoSet βœ… Tested

Should work (untested)

Device Notes
Tapo P110M Same chip, energy monitoring
Tapo P115 Energy monitoring variant
Tapo P105 No energy monitoring β€” will not work
Tapo P100 No energy monitoring β€” will not work
Kasa KP115 Energy monitoring β€” should work
Kasa EP25 Energy monitoring β€” should work
Tuya-compatible plugs Requires local key setup via tinytuya
Any CPAP/APAP/BiPAP machine Watt threshold calibration required

Important: Only smart plugs with energy monitoring (live power reading in watts) are compatible. Always check your plug's spec sheet before buying.


Known Issues & Troubleshooting

False alerts (mask is on but alert fires)

Your watt_threshold may be too high or confirm_count too low. This is the most common issue with AutoSet machines that dynamically adjust pressure β€” power draw fluctuates even with the mask on.

Fix:

  1. Watch the log for a full night and note minimum watts during therapy
  2. Lower watt_threshold to just above standby level
  3. Raise confirm_count to 4 or 5 to require more consecutive low readings
  4. Raise idle_minutes to 15 to require longer sustained low power before alerting

Alert fired but not received on phone

  • Make sure Pushover Critical Alerts is enabled (see Pushover Setup above)
  • Verify your User Key and App Token in config.json
  • Check internet connection on the monitor device

Tapo plug shows "Hash mismatch" error

This is a known issue with newer Tapo firmware. Fixes to try:

  1. Power cycle the plug
  2. Restart the monitor service
  3. Factory reset the plug and re-add to Tapo app

No data / plug unreachable

  • Verify the IP in config.json matches your plug's current IP
  • Make sure monitor device and plug are on the same WiFi network
  • Reserve a static IP for the plug in your router

Pi not accessible after reboot

  • Check if IP changed β€” look in your router's connected devices list
  • Use ssh pi@snoozesense.local as a fallback (uses hostname instead of IP)
  • Reserve a static IP in your router to prevent this permanently

Limitations

Limitation Details
Same network required Monitor device and smart plug must be on the same local WiFi. Does not work while travelling unless you bring the plug and connect to a shared hotspot
Internet required for alerts Pushover needs internet. If internet is down, the monitor logs the event locally but cannot send push notifications
Smart plug required No smart plug = no monitoring. The plug is the only required hardware addition
2-minute detection delay At default settings: up to 10 minutes to confirm mask off + 15 minute idle timer = up to 25 minutes before first alert. Reduce poll_seconds to detect faster at the cost of more network traffic

Roadmap

  • macOS support
  • Linux / Raspberry Pi support (systemd service)
  • Windows auto-start service
  • Additional smart plugs β€” Sonoff S31, additional Kasa models
  • Additional alert providers β€” Telegram bot, ntfy.sh, Home Assistant webhook
  • Web dashboard β€” nightly summary, mask-off history, trend graphs
  • Multi-machine support β€” for households with multiple CPAP users
  • Auto-calibration β€” automatically determine watt threshold from first-night data

Community contributions welcome. If you've tested with a device not listed above, please open an issue or PR.


Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you'd like to change.


License

MIT β€” free to use, modify, and distribute. See LICENSE for details.


Supported Smart Plugs

See README_PLUGS.md for the full list of supported plugs including Tapo, Kasa, Wipro, and Havells.

About

😴 Real-time CPAP mask-off alerts for macOS. Monitors your machine's power via a Tapo smart plug and fires an instant push notification when the mask comes off during sleep.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors