Far too often, I sit down in front of the computer to get some work done, only to look up and realize that eight hours have elapsed, I haven’t eaten, and my prescription has increased by 2 diopters. Break timers are handy, but many cost money and/or are too bulky and annoying for my preferences (they’ll pop up a big overlay on your screen saying HEEEEYYY RYAN TAKE A BREAK, which kills my concentration if I am thinking about a hard problem). My experience with most break timers is that I disable them within a few hours of using them. All I want is a subtle reminder, and I figure it shouldn’t be too hard to script that myself.

Mac OS has had built-in notifications since Mountain Lion; these are nifty, unobtrusive bubbles that pop up in the upper right of the screen. These would be perfect for what I want to do, and I figured Apple must have some way to trigger notifications through some simple script. Indeed, there is an AppleScript API:

display notification "Notification Content" with title "Notification Title"

We can call this through bash:

osascript -e 'display notification "Take a break, please!" with title "Break reminder"'

And, if we want a reminder every 10 minutes, we can pop that into a simple loop:

while true
do
    osascript -e 'display notification "Take a break, please!" with title "Break reminder"'
    sleep 600
done

Break notification bubble

Voila! We have a very simple, customizable break timer in just 5 lines. Now, this does work, but one problem is that even if the display is off/locked, it will continue to remind us to take breaks, leaving us with hundreds of notifications when we return to the computer. We can fix this fairly easily.

The I/O Registry maintains information about the hardware on a Mac system. We can query it to get information about the state of the system’s power management:

$ ioreg -n IODisplayWrangler | grep -i IOPowerManagement
      | |   "IOPowerManagement" = {"CapabilityFlags"=32832,"MaxPowerState"=4,"ActivityTickles"=63761,"DevicePowerState"=4,"IdleTimerPeriod"=584000,"TimeSinceLastTickle"=25,"IdleTimerElapsedTime"=280243,"CurrentPowerState"=4}

We are particularly interested in the CurrentPowerState key, whose value we can extract with a simple regex:

$ ioreg -n IODisplayWrangler | grep -i IOPowerManagement  | sed 's/.*"CurrentPowerState"=\([0-9]\).*/\1/'
4

I wasn’t able to find any documentation on CurrentPowerState values, but it appears that the key has a value of 4 when the screen is on and a value of 1 when the screen is off (but the machine is on). You should double check that CurrentPowerState is 4 when your screen is on, just in case this varies between versions of OS X or varies based on system preferences.

Now, we can modify our script so that it only triggers a notification if the screen is on:

while true
do
    POWER_STATE=$(ioreg -n IODisplayWrangler | grep -i IOPowerManagement | sed 's/.*"CurrentPowerState"=\([0-9]\).*/\1/')
    if [ $POWER_STATE -eq 4 ]
    then
        osascript -e 'display notification "Take a break, please!" with title "Break reminder"'
    fi
    sleep 600
done

And there we have it. It isn’t perfect, but it’s simple, customizable, and gets the job done.