2

I want to turn on or off (not just toggle) Do Not Disturb within an Applescript-based app.

Apparently there used to be a method for doing this on older versions of the OS (I'm on Catalina). Now, the only solution I've found is a hack that uses a keyboard shortcut to toggle the condition of Do Not Disturb. This won't work for me because I don't know in advance the state of the setting before I run the app and I specifically want to turn it off when the app is run (later I'll turn it back on).

If there's no way to specifically turn Do Not Disturb on or off, then I suppose what I need to know is how to ascertain the current state of the setting and only execute the keyboard shortcut if it is not in the desired state.

4
  • The keyboard shortcut solution doesn't seem to work well anyway. At first when I ran the code in either Script Editor or as an app it was working... then it just stopped. Strange.
    – Hack-R
    Commented Apr 21, 2021 at 21:12
  • This works on Big Sur, doesn't work on Mojave. I don't have a Catalina machine to test, so I can't tell you if it works there, but it's what I would try first: raw.githubusercontent.com/vitorgalvao/tiny-scripts/master/… In Terminal, save it as 'calm-notifications.rb' make it executable (chmod 755 calm-notifications.rb) and then run ./calm-notifications.rb status and see what it says.
    – TJ Luoma
    Commented Apr 21, 2021 at 23:00
  • @TJLuoma Interesting. It says ./dnd.rb:32:in grab_dnd_xml': undefined method text' for nil:NilClass (NoMethodError)
    – Hack-R
    Commented Apr 21, 2021 at 23:13
  • 1
    That's the same error I get on Mojave. I think it must be Big Sur only.
    – TJ Luoma
    Commented Apr 21, 2021 at 23:39

3 Answers 3

1

The example AppleScript code, shown below, was tested under macOS Catalina with Language & Region settings in System Preferences set to English (US) — Primary and worked for me without issue1 to turn Do Not Disturb either on or off.

  • 1 Assumes necessary and appropriate setting in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.

The setDoNoDisturbTo() handler takes one parameter, "On" or "Off".

Example AppleScript code:

my setDoNoDisturbTo("Off")


on setDoNoDisturbTo(OnOff)
    set checkDNDstatusCMD to ¬
        {"defaults -currentHost read", space, ¬
            "~/Library/Preferences/ByHost/", ¬
            "com.apple.notificationcenterui", ¬
            space, "doNotDisturb"} as string
    set statusOfDND to ¬
        (do shell script checkDNDstatusCMD) ¬
            as number as boolean
    if statusOfDND is false and OnOff is "On" then
        set OnOff to true
    else if statusOfDND is true and OnOff is "Off" then
        set OnOff to false
    else
        return
    end if
    set changeDNDstatusCMD to ¬
        {"defaults -currentHost write", space, ¬
            "~/Library/Preferences/ByHost/", ¬
            "com.apple.notificationcenterui", ¬
            space, "doNotDisturb -boolean", space, OnOff, ¬
            space, "&& killall NotificationCenter"} as string
    do shell script changeDNDstatusCMD
end setDoNoDisturbTo

Note: The example AppleScript code is just that and sans any included error handling does not contain any additional error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.

2
  • this seems like not working on Monterey :( I mean I tested it based if Focus is changed to Do not disturb on control center but it wasn't Commented Apr 8, 2022 at 3:35
  • the "write" fails Commented Apr 9, 2022 at 7:12
1

This is not as elegant as I was hoping for but it seems to work.

After playing with the Record feature for a while, I seem to be able to turn DND on when it's off:

-- Click the “Notification Center” menu bar item.
delay 1.109957
set timeoutSeconds to 0.0
set uiScript to "click menu bar item \"Notification Center\" of menu bar 1 of application process \"SystemUIServer\""
my doWithTimeout(uiScript, timeoutSeconds)

-- Click the “<fill in title>” button.
delay 2.096055
set timeoutSeconds to 0.0
set uiScript to "click UI Element 3 of group \"Do Not Disturb\" of scroll area 1 of window \"Notification Center\" of application process \"Notification Center\""
my doWithTimeout(uiScript, timeoutSeconds)

on doWithTimeout(uiScript, timeoutSeconds)
    set endDate to (current date) + timeoutSeconds
    repeat
        try
            run script "tell application \"System Events\"
" & uiScript & "
end tell"
            exit repeat
        on error errorMessage
            if ((current date) > endDate) then
                error "Can not " & uiScript
            end if
        end try
    end repeat
end doWithTimeout

and vice versa:

-- Click the “Notification Center” menu bar item.
delay 2.508349
set timeoutSeconds to 2.0
set uiScript to "click menu bar item \"Notification Center, Do Not Disturb enabled\" of menu bar 1 of application process \"SystemUIServer\""
my doWithTimeout(uiScript, timeoutSeconds)

-- Click the “<fill in title>” button.
delay 1.176098
set timeoutSeconds to 2.0
set uiScript to "click UI Element 3 of group \"Do Not Disturb\" of scroll area 1 of window \"Notification Center\" of application process \"Notification Center\""
my doWithTimeout(uiScript, timeoutSeconds)

on doWithTimeout(uiScript, timeoutSeconds)
    set endDate to (current date) + timeoutSeconds
    repeat
        try
            run script "tell application \"System Events\"
" & uiScript & "
end tell"
            exit repeat
        on error errorMessage
            if ((current date) > endDate) then
                error "Can not " & uiScript
            end if
        end try
    end repeat
end doWithTimeout

It would be better if there were a solution that checked its state or explicitly specified the desired new state instead of just toggling. There is a small difference between the "on" and "off" scripts so it's not exactly toggling but it works by clicking the button.

0

In Monterey (macOS 12) you can use the Shortcuts app and the Set Focus action.

It has options to turn any of your configured focus modes Off or On until various end conditions, including until turned off.

That's not an AppleScript solution, though I'm hoping that someone will update or comment with a way to trigger Shortcuts from AppleScript or the Terminal.

1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .