web-dev-qa-db-fra.com

Comment puis-je écouter les événements «USB Device Insert» à Linux, en Python?

J'aimerais écrire un Python Script pour Amarok sous Linux pour copier automatiquement le podcast Stackoverflow à mon lecteur. Lorsque je branche le lecteur, il s'agirait du lecteur, copiez-vous des podcasts en attente, et éjecter le joueur. Comment puis-je écouter l'événement "branché"? J'ai parcouru à travers la halte mais je n'ai pas trouvé de bon exemple.

35
joeforker

Mise à jour : Comme indiqué dans les commentaires, HAL n'est pas pris en charge dans les distributions récentes, la norme est maintenant udev, voici un petit exemple qui utilise une boucle de glib et udev , je garde la version Hal pour des raisons historiques.

Ceci est fondamentalement le exemple dans la documentation de Pyudev , adapté au fonctionnement des anciennes versions, et avec la boucle de glib, remarquez que le filtre doit être personnalisé pour votre besoin spécifique:

import glib

from pyudev import Context, Monitor

try:
    from pyudev.glib import MonitorObserver

    def device_event(observer, device):
        print 'event {0} on device {1}'.format(device.action, device)
except:
    from pyudev.glib import GUDevMonitorObserver as MonitorObserver

    def device_event(observer, action, device):
        print 'event {0} on device {1}'.format(action, device)

context = Context()
monitor = Monitor.from_netlink(context)

monitor.filter_by(subsystem='usb')
observer = MonitorObserver(monitor)

observer.connect('device-event', device_event)
monitor.start()

glib.MainLoop().run()

Version ancienne avec HAL et D-BUS :

Vous pouvez utiliser des liaisons D-BUS et écouter DeviceAdded et DeviceRemoved signaux. Vous devrez vérifier les capacités du périphérique ajouté afin de sélectionner uniquement les périphériques de stockage.

Voici un petit exemple, vous pouvez supprimer les commentaires et l'essayer.

import dbus
import gobject

class DeviceAddedListener:
    def __init__(self):

Vous devez vous connecter au gestionnaire HAL à l'aide du bus système.

        self.bus = dbus.SystemBus()
        self.hal_manager_obj = self.bus.get_object(
                                              "org.freedesktop.Hal", 
                                              "/org/freedesktop/Hal/Manager")
        self.hal_manager = dbus.Interface(self.hal_manager_obj,
                                          "org.freedesktop.Hal.Manager")

Et vous devez connecter un auditeur aux signaux qui vous intéressent, dans ce cas DeviceAdded.

        self.hal_manager.connect_to_signal("DeviceAdded", self._filter)

J'utilise un filtre en fonction des capacités. Il acceptera tout volume et appellera do_something Avec si, vous pouvez lire la documentation HAL pour trouver les requêtes les plus appropriées pour vos besoins, ou plus d'informations sur les propriétés des périphériques HAL.

    def _filter(self, udi):
        device_obj = self.bus.get_object ("org.freedesktop.Hal", udi)
        device = dbus.Interface(device_obj, "org.freedesktop.Hal.Device")

        if device.QueryCapability("volume"):
            return self.do_something(device)

Exemple de fonction indique certaines informations sur le volume:

     def do_something(self, volume):
        device_file = volume.GetProperty("block.device")
        label = volume.GetProperty("volume.label")
        fstype = volume.GetProperty("volume.fstype")
        mounted = volume.GetProperty("volume.is_mounted")
        mount_point = volume.GetProperty("volume.mount_point")
        try:
            size = volume.GetProperty("volume.size")
        except:
            size = 0

        print "New storage device detectec:"
        print "  device_file: %s" % device_file
        print "  label: %s" % label
        print "  fstype: %s" % fstype
        if mounted:
            print "  mount_point: %s" % mount_point
        else:
            print "  not mounted"
        print "  size: %s (%.2fGB)" % (size, float(size) / 1024**3)

if __name__ == '__main__':
    from dbus.mainloop.glib import DBusGMainLoop
    DBusGMainLoop(set_as_default=True)
    loop = gobject.MainLoop()
    DeviceAddedListener()
    loop.run()
55
Jaime Soriano

Je n'ai pas essayé d'écrire un tel programme moi-même, cependant je viens de regarder les deux liens suivants (merci Google!), Que je pense sera utile:

En particulier, lisez sur le org.freedesktop.Hal.Manager Interface et ses DeviceAdded et DeviceRemoved événements. :-)

J'espère que cela t'aides!

7
Chris Jester-Young

Voici une solution en 5 lignes.

import pyudev

context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by(subsystem='usb')

for device in iter(monitor.poll, None):
    if device.action == 'add':
        print('{} connected'.format(device))
        # do something very interesting here.

Enregistrez-le dans un fichier dire usb_monitor.py, Cours python monitor.py. Branchez n'importe quel USB et il imprimera les détails du périphérique

→ python usb_monitor.py 
Device('/sys/devices/pci0000:00/0000:00:14.0/usb1/1-6/1-6:1.0') connected
Device('/sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0') connected

Testé sur Python 3.5 avec pyudev==0.21.0.

5
ChillarAnand

Je pense que D-Bus fonctionnerait comme Chris mentionné, mais si vous utilisez KDE4, vous pouvez utiliser le cadre solide de la manière similaire à l'applet KDE4 "NOUVEAU Notifiant de périphérique".

La source C++ pour cette applet est ici , qui montre comment utiliser Solid pour détecter de nouveaux périphériques. Utilisez PYKDE4 pour Python liaison à ces bibliothèques, comme indiqué ici .

4
Matt J