Skip to content

Instantly share code, notes, and snippets.

@mieky
Last active March 30, 2025 09:13
Show Gist options
  • Save mieky/d57f3dd99f137fb62cd68d91d6478359 to your computer and use it in GitHub Desktop.
Save mieky/d57f3dd99f137fb62cd68d91d6478359 to your computer and use it in GitHub Desktop.
Zero-dependency watcher for macOS session lock/unlock events
#!/bin/bash
#
# Watches for macOS session lock/unlock events and runs ~/.lock or ~/.unlock on change.
#
# Usage:
# - chmod u+x /path/to/lockwatch.bash
# - to test, run /path/to/lockwatch.bash
# - to launch in the background, set up a launchd agent with lockwatch.plist.
script_lock=~/.lock
script_unlock=~/.unlock
unlocked=-1
unlocked_last=-1
# detect if a copy of lockwatch is already running
if pgrep -f lockwatch.sh >/dev/null; then
echo "lockwatch is already running"
exit 1
fi
echo "lockwatch started"
while true; do
ioreg -n Root -d1 -a | grep -q CGSSessionScreenIsLocked
unlocked=$?
# Update status after a change
if [[ $unlocked -ne $unlocked_last && $unlocked_last -ne -1 ]]; then
# shellcheck disable=SC1090
if [[ $unlocked -eq 0 ]]; then
echo "$(date +'%c') - screen is locked"
# if the script specified by path script_lock exists, run it
[[ -f $script_lock ]] && source $script_lock
else
echo "$(date +'%c') - screen is unlocked"
[[ -f $script_unlock ]] && source $script_unlock
fi
fi
unlocked_last=$unlocked
sleep 1
done
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!--
- Save this file in ~/Library/LaunchAgents/lockwatch.plist
- Update the path to the script in the ProgramArguments array
- Start the script with: launchctl load ~/Library/LaunchAgents/lockwatch.plist
- To later stop it, use: launchctl unload ~/Library/LaunchAgents/lockwatch.plist
-->
<plist version="1.0">
<dict>
<key>Label</key>
<string>lockwatch</string>
<key>ProgramArguments</key>
<array>
<string>/Users/mike/bin/lockwatch.bash</string>
</array>
<key>RunAtLoad</key>
<true/>
<!--
OnDemand makes it easier to stop the script when needed, without it will always auto-restart.
-->
<key>OnDemand</key>
<true/>
</dict>
</plist>
@mieky
Copy link
Author

mieky commented Oct 6, 2024

Example ~/.lock:

#!/bin/bash
#
# Update an input boolean via Home Assistant API when the macOS screen is locked.

source ~/.envrc

curl --silent \
  -H "Authorization: Bearer $HA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"entity_id":"input_boolean.macbook_active"}' \
  $HA_API_URL/services/input_boolean/turn_off >/dev/null
  
echo $(date +%c) - lock >>~/.lockwatch.log

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment