Turn Do Not Disturb on or off in an Applescript app (macOS Catalina)
Solution 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.
Solution 2:
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.