Spending all day at a screen is brutal on the eyes, the back, and the brain. So I decided to whip up a desktop toast that nudges me every hour to stand, stretch, sip water anything except keep slouch-coding. What started as seven lines of Python turned into a surprisingly fun mini-project that now lives in my toolbox.
- “I only intended to write one quick script… then I fell down the rabbit-hole.”
Below is the journey, the full code, and a handful of ideas you can riff on.
Define Code
from plyer import notification
if __name__ == "__main__":
while True:
notification.notify(
title="ALERT!!!",
message="Take a break! It has been an hour!",
)
time.sleep(3600)
Install the only dependency:
pip install plyer
and run:
python break.py
Your OS pops up a toast every 60 minutes. Job done kind of.
What each line is doing
# | Code | Why it matters |
---|---|---|
1 | import time | Gives me time.sleep() so the script can nap between alerts. |
2 | from plyer import notification | plyer wraps each platform’s native “toast” API—works on Windows, macOS, Linux. |
4 | if __name__ == "__main__": | Runs the loop only when I execute the file directly, not when I import it elsewhere. |
5 | while True: | Endless loop until I hit Ctrl +C. |
6-8 | notification.notify(...) | Fires the visual reminder. |
10 | time.sleep(3600) | Waits one hour (3 600 s) before the next pass. |
Great for a proof-of-concept; painful in real life. I wanted:
- Flexible intervals (
--interval 20m
,2h
,90s
…) - Custom titles/messages
- A finite number of pings (helpful in pomodoro workflows)
- Random healthy-habit tips if I’m lazy
- A gentle console beep (toast may be hidden)
- Tidy logging with timestamps
- Graceful shutdown no ugly tracebacks when I quit
Level-up: the extended script
Below is break_timer.py in full, then read on for usage examples.
#!/usr/bin/env python3
"""
break_timer.py – flexible desktop break-reminder
"""
import argparse
import datetime as dt
import random
import sys
import time
from plyer import notification
# ---------- tiny knowledge base ----------
_TIPS = [
"Stand up and stretch your legs 🦵",
"Look away from the screen for 20 seconds 👀",
"Roll your shoulders a few times 🙆♂️",
"Drink a glass of water 💧",
"Take three slow, deep breaths 😮💨",
]
def parse_interval(text: str) -> int:
"""Turn '45m', '2h', '30s' into seconds (int)."""
units = {'s': 1, 'm': 60, 'h': 3600}
if text[-1].isdigit(): # default to minutes
return int(text) * 60
value, unit = int(text[:-1]), text[-1].lower()
if unit not in units:
raise ValueError("Use s, m or h as units.")
return value * units[unit]
def beep() -> None:
"""Cross-platform console bell."""
print('\a', end='', flush=True)
# ---------- main ----------
def main():
p = argparse.ArgumentParser(description="Desktop break reminder")
p.add_argument('-i', '--interval', default='60m',
help='Time between reminders (e.g. 20m, 2h, 45s).')
p.add_argument('-c', '--count', type=int, default=0,
help='Number of reminders then exit (0 = unlimited).')
p.add_argument('-t', '--title', default='ALERT!!!',
help='Notification title text.')
p.add_argument('-m', '--message',
help='Notification body; omit → random tip.')
args = p.parse_args()
wait = parse_interval(args.interval)
remaining = args.count
print(f"[{dt.datetime.now():%H:%M:%S}] Timer started – every "
f"{wait//60 if wait>=60 else wait} "
f"{'min' if wait>=60 else 'sec'} "
f"({ '∞' if remaining==0 else remaining} alerts). Ctrl-C to quit.")
try:
while remaining != -1: # -1 means we hit the limit
body = args.message or random.choice(_TIPS)
notification.notify(title=args.title,
message=body,
app_name="Break Timer")
beep()
print(f"[{dt.datetime.now():%H:%M:%S}] Notified: {body}")
if remaining > 0:
remaining -= 1
if remaining == 0:
break
time.sleep(wait)
except KeyboardInterrupt:
print("\nStopped by user. Have a healthy day! 👋")
sys.exit(0)
if __name__ == "__main__":
main()
Running the upgraded version
install plyer # one-time
python break_timer.py -i 45m # ping every 45 min
python break_timer.py -i 20m -c 6 # six pings then exit
python break_timer.py -i 90s -t "Hydrate" \
-m "Sip some water 🚰" # custom text
Quick flag reference
Flag | Example | Purpose |
---|---|---|
-i , --interval | -i 90s | How often to remind (supports s/m/h suffix). |
-c , --count | -c 4 | Quit after N reminders. |
-t , --title | -t "Hydrate" | Notification headline. |
-m , --message | -m "Drink water" | Body text (skip for a random tip). |
Stretch goals I’m tinkering with
- System-tray icon with pause/resume for meetings.
- Work-hours window so it only nags 09:00-18:00.
- CSV/JSON logging to track how often I actually moved.
- Tkinter GUI so colleagues can set it up without CLI knowledge.
- GIF micro-exercises—imagine a shoulder-roll animation popping up.
- Voice alert via
pyttsx3
for the perpetually alt-tabbed.
Final thought
Writing this tiny utility reminded me why I love Python:
a couple of imports + the right library = instant quality-of-life boost.
Feel free to fork, tweak, and ship your own flavour. Just remember: the best code you’ll ever write might be the one that literally tells you to stop coding for a minute.