How to write to Notification Center from a launchd command

launchd

I've got a plist set to run at a set interval, and have put it in /Library/LaunchDaemons like so:

/Library/LaunchDaemons $ ll macports_update_notifier.plist 
lrwxr-xr-x  1 root  wheel    55B  5 Sep 13:47 macports_update_notifier.plist@ -> /Users/seron/bin/macports/macports_update_notifier.plist

The problem is that it doesn't seem to execute.
Here's the plist:

<?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">
<plist version="1.0">
<dict>
    <key>EnvironmentVariables</key>
    <dict>
        <key>HOME</key>
        <string>/Users/seron</string>
    </dict>
    <key>Label</key>
    <string>macports_update_notifier</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/seron/bin/macports/macports_notificaton.sh</string>
    </array>
    <key>StartInterval</key>
    <integer>300</integer>
</dict>
</plist>

I loaded it with sudo launchctl load -w /Library/LaunchDaemons/macports_update_notifier.plist.

Here's what sudo launchctl list macports_update_notifier produces:

{
    "Label" = "macports_update_notifier";
    "LimitLoadToSessionType" = "System";
    "OnDemand" = true;
    "LastExitStatus" = 0;
    "TimeOut" = 30;
    "ProgramArguments" = (
        "/Users/seron/bin/macports/macports_notificaton.sh";
    );
};

The script executes in about a second and works fine when run on its own. It needs to run as root.

I'm using OS X 10.8.1. What could be the problem?

edit:

My script runs terminal-notifier which is command line tool to display notifications in Mountain Lion and this is where the daemon bails.

#!/bin/sh
/opt/local/bin/terminal-notifier -message 'output' -group 'debug'

I found that the daemon runs fine if it's not loaded with sudo. One difference is that launchctl load test.plist reports "LimitLoadToSessionType" = "Aqua" instead of "System". However if I set LimitLoadToSessionType to Aqua in the plist and load with sudo launchctl refuses to load it displaying nothing found to load. It needs to run as root however because it updates the macports database.

update

I think I've found the reason why a GUI can't be launched by a daemon; Mac Developer Library, Daemons and Agents. An agent can do that. In my case, it needs to communicate with the daemon in order to display information whenever the daemon has updated macports. Now the question is, How do I make the agent ask and the daemon answer?

Best Answer

You can send to Notification Centre using Applescript (osascript )in you shell script.

There is a very good thread here that explains the various ways of either running only Applescript as a shell script or being able to mix applescript in with bash, for example.

I created a shell script with:

#!/bin/bash
theDate=`date '+DATE: %m/%d/%y TIME:%H:%M:%S'`

osascript -e "display notification \"$theDate\" with title \"test 1\" subtitle \" sub 1\""

I then created a LaunchDaemon in the same way you have and loaded it without sudo.

<?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">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>notifTest</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/userName/Documents/notify.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StartInterval</key>
    <integer>90</integer>
</dict>
</plist>

Every 90 seconds I get a notification:

enter image description here

The notification icon you will notice is the Script Editors one. Which means the Notification is controlled by the Script Editors Notification settings in Notification Centre