PHP, Mumbles (Growl), and DBus: Sweeet

So, after reading Mark Shuttlework’s blog on ideas for notifications in Ubuntu (basically mimicking Growl notifications for the Mac), I decided I wanted that kind of functionality, but… you know, NOW!

There are a multitude of options available but currently I’m liking Mumbles. Unlike, say, Specto, which does the monitoring itself, Mumbles provides a DBus interface, a command-line app named mumbles-send, and (I’m not sure if it’s implemented in the current stable download) libnotify support. Woutc, from the Specto project, commented below explaining that Specto is not intended to be a Mumbles competitor, but a package to easily monitor system internals (I quote “…the purposes from mumbles and specto are different…specto is monitoring what happens outside your desktop, mumbles monitors what happens on your desktop (or in your network)…”) Apparently he has plans to build a Mumbles plugin so that one can optionally have Specto send its messages to Mumbles for display.

I decided the best easiest route is to access the internal DBus API, however the forums and other resources on the Mumbles site… well… just plain suck. And by suck I mean tell you that something exists and… thaaats about it.

D-Feet browsing Mumble's Growl interface

D-Feet browsing Mumble's Growl interface

Well in my Google quest I discovered the existence of D-Feet, a DBus debugging tool (on Ars of all places). Thanks to a quick sudo apt-get install d-feet I found the existence of a public interface in info.growl.Growl that allows for a Notify(title, message) signal to be passed.

Well, with a place to access all I needed was DBus integration with PHP (because I want to start sending debug notification via Growl/Mumbles like this idea on the Zend Framework incubator).

Luckily, GREE Labs provides a DBus C extension for PHP that was easily downloaded and installed. Once installed I read the documentation to get an idea on how to use the API (which is a 1:1 mapping to the DBus API).

After a bit of hacking I finally came up with an alpha product:

<?php
function null_callback()
{
        var_dump(func_get_args());
}

$dbus = dbus_bus_get(DBUS_BUS_SESSION);

$m = new DBusMessage(DBUS_MESSAGE_TYPE_SIGNAL);

$m->setPath('/info/growl/Growl');
$m->setInterface('info.growl.Growl');
$m->setMember('Notify');
$m->appendArgs('Hello World!');
$m->appendArgs('Lorem Ipsum Dolor Sit Amet. (' . time() . ')');

$r= $dbus->send($m);

After running the script in the console, did I see success?

Mumbles and PHP Test: Success!

Mumbles and PHP Test: Success!

Damn right I did!

Though with a caveat:

Warning: dbusconnection::sendwithreplyandblock(): dbus_connection_send_with_reply_and_block() failed (Traceback (most recent call last):
File "/var/lib/python-support/python2.5/dbus/service.py", line 643, in _message_cb
(candidate_method, parent_method) = _method_lookup(self, method_name, interface_name)
File "/var/lib/python-support/python2.5/dbus/service.py", line 244, in _method_lookup
raise UnknownMethodException('%s is not a valid method of interface %s' % (method_name, dbus_interface))
UnknownMethodException: org.freedesktop.DBus.Error.UnknownMethod: Unknown method: Notify is not a valid method of interface info.growl.Growl
) in /home/daniel/test.php on line 21

Call Stack:
0.0002 64496 1. {main}() /home/daniel/test.php:0
0.0024 66372 2. dbusconnection->sendwithreplyandblock() /home/daniel/test.php:21

Apparently Mumbles seems to be throwing an Exception that it’s failing to to find the Notify signal (though everything works correctly). I guess I could ignore this, use the error suppressor (@), or even yell at GREE Labs to have the objects throw exceptions so I can catch them… I guess I’ll hack on it some more and report back. I should probably spend more time learning the DBus specs since this is my first project playing with DBus…

Update: Though it’s not listed on the API page for PHP DBus’s API, there is a method send() that takes only a single argument (the message object).

Edit:

I saw a question on Reddit asking what is the use of this technique if it’s limited to the desktop it was called on and PHP is primarily a server side language. Why not do this in Python or Perl?

Well, Mumbles was written in Python so there’s no point in me doing this in Python: it’s already been done.

However, the primary use case of a technique like this is having a web app post notifications and errors for the developer. When I work on a site I have a local copy running on my desktop and/or laptop, so when it posts Growl/Mumbles notifications, I get them on my desktop. It’s great for situations where, say, I have a page in my PHP app that never displays its contents because it processes data then redirects to another page. If a warning or other non-fatal error that I should really fix occurs, then I would normally have to dig through the system wide PHP error log (if you even have error logging enabled). However, if I wrote a custom error handler that posts errors to Growl/Mumbles as they happen, when I visit a transitory page like I described I get little Growl/Mumbles notifications showing that I screwed up!

Comments

  1. Adam Kinder says:

    Very nice, good work. I wonder if this could be engineered on the C side to work with Window’s task bar notifications

  2. Well, Windows doesn’t use DBus natively and their tooltip notifications are a bit different. But if you were to write a system tray application that pops up Growl notifications and listens to DBus, this code would work transparently on Linux or Windows :P

  3. Woutc says:

    Hello,

    I am the specto developer and I just want to say that the purposes from mumbles and specto are different…specto is monitoring what happens outside your desktop, mumbles monitors what happens on your desktop (or in your network).

    For the moment I am converting specto so it sends dbus signals and a specto plugin for mumbles is already finished.

    This means that mumbles will also be able to notify you from specto updates so we will have the ultimate notification system! (all mumbles plugins but also gmail, imap, pop3, rss, websites, processes, ports, greader, facebook,….).

    About your error:
    you use $dbus->sendWithReplyAndBlock($m, 10);
    but you should use a method that does not expect a reply because mumbles does not send a reply.

  4. Thanks Woutc! I’ll look more at the PHP DBus API but I didn’t remember seeing anything that didn’t expect a reply. I may just be blind.

    And thanks for the correction, I’ll update the post.

  5. newsen says:

    Hi,
    Thanks for the tutorial.I tried the same thing but in my error log i am getting “Failed to auto launch D-Bus session :x11 initialisation failed.What could be the reason.

  6. I was wondering, since I found some tutorials online where you could hook up into a different session by finding the session id via SSH and then send commands into that session, would this work in a pure PHP version too?
    The thing is that I try to remote control Rhythmbox and similar programs via a Web interface and obviously the Webserver runs as www-data and rhythmbox runs as my user.

  7. tester says:

    my problems is when I execute the script.

    when I try to run it in shell (php Daniel-Dbus.php) it return either the error message:

    PHP Fatal error: Call to undefined function dbus_bus_get() in /var/www/Daniel-Dbus.php on line 7

    and when I try to run it via a web browser it return either the error message:

    Warning: dbus_bus_get(): failed to create dbus connection object [//bin/dbus-launch terminated abnormally with the following error: Autolaunch error: X11 initialization failed. ] in /var/www/Daniel-Dbus.php on line 7 Fatal error: Call to a member function send() on a non-object in /var/www/Daniel-Dbus.php on line 17

  1. [...] Read the original: Tower Of Power – PHP, Mumbles (Growl), and DBus: Sweeet [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>