pythonlinuxdebiandbusmtp

Listening to dbus signals to mount mtp device on debian linux


I am trying to write a python script that will detect when an mtp device (in this case an Android phone) has been mounted to a raspberry pi 3 (running raspbian jessie). I want to automatically transfer files to the phone when it is plugged in.

I started out with the script given as the second answer to this question

I changed a few things to get it to run on my raspberry pi. The current script is below. I can see UnitNew and UnitRemoved signals when I plug/unplug my phone. When it gets to the path_to_device function, I get this error:

DBusException: org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.systemd1.Manager was not provided by any .service files

I read in a similar question that this is a permissions issue, so I tried running the script as sudo ./usb_SYSTEM.py but I still get the same error.

I have also tried using a SessionBus instead of a SystemBus. The signals are different, the bus name is then org.gtk.vfs.MountTracker. I still get the same error, this time it says org.gtk.vfs.MountTracker is not an available service. When I try to run the SessionBus version with sudo, I don't see the signals at all.

Am I using the right input to the get_object() function? And the right bus type? There is no destination bus since the signal is broadcast, I'm not sure if that is part of the problem. I have a very limited understanding of linux and signals/buses.

Script:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-

import dbus
import dbus.service
if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
    import dbus.glib

from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib
import sys
import os


class DeviceManager:
    def __init__(self):
        self.bus = dbus.SystemBus()
        self.bus.add_signal_receiver(self.device_added,
                        'UnitNew',
                        'org.freedesktop.systemd1.Manager',
                        None,
                        '/org/freedesktop/systemd1',
                        path_keyword='path')

        self.bus.add_signal_receiver(self.device_removed,
                        'UnitRemoved',
                        'org.freedesktop.systemd1.Manager',
                        None,
                        '/org/freedesktop/systemd1',
                        path_keyword='path')

        self.bus.add_signal_receiver(self.print_event, None, None, None, None,
                                     sender_keyword='sender', message_keyword='message')

    def path_to_device(self, path):
        return self.bus.get_object('org.freedesktop.systemd1.Manager', path)

    def device_added(self, *args, **kwds):
        path = kwds['path']
        print 'Added', path
        properties = self.path_to_device(path).GetAllProperties()
        print properties.get('info.category')
        if properties.get('info.category') == u'volume':
            label, dev = properties.get('volume.label'), properties.get('block.device')
            print 'Mounting %s on /mnt/%s' %(dev, label)
            ## os.system('mount %s /mnt/%s' %(dev, label))

    def device_removed(self, *args, **kwds):
        path = kwds['path']
        print 'Removed', path

    def print_event(*args, **sender):
        print "got signal from:"
        print sender

if __name__ == '__main__':
    DBusGMainLoop(set_as_default=True)

    m = DeviceManager()

    mainloop = GLib.MainLoop()
    try:
        mainloop.run()
    except KeyboardInterrupt:
        mainloop.quit()
        print 'Exiting...'
        sys.exit(0)

Solution

  • I'm not familiar enough with the systemd D-Bus APIs to be able to tell if the general approach is correct but this should help with the specific problem:

    self.bus.get_object('org.freedesktop.systemd1.Manager', path)
    

    The first argument to bus.get_object() is service name (typically a well-known name found in the services documentation). I'm pretty sure 'org.freedesktop.systemd1' is the service name you should be using. The one you are currently using ('org.freedesktop.systemd1.Manager') is one of the interfaces implemented by one of the objects exposed by that service.

    The fact that interfaces and service names often look alike is in my opinion a design mistake in D-Bus... If the d-feet D-Bus debugger is available on raspbian (or you have another linux box to test on), I suggest using it to see all the D-Bus services and their exposed objects and interfaces: it makes it much easier to understand how they relate to each other.