كيف يمكنني الاستماع إلى أحداث "تم إدخال جهاز USB" في Linux، في Python؟

StackOverflow https://stackoverflow.com/questions/469243

  •  19-08-2019
  •  | 
  •  

سؤال

أرغب في كتابة برنامج نصي Python لـ Amarok في Linux لنسخ بودكاست Stackoverflow تلقائيًا إلى المشغل الخاص بي.عندما أقوم بتوصيل المشغل، فإنه يقوم بتثبيت محرك الأقراص، ونسخ أي ملفات بودكاست معلقة، وإخراج المشغل.كيف يمكنني الاستماع إلى الحدث "موصول"؟لقد بحثت في hald ولكن لم أتمكن من العثور على مثال جيد.

هل كانت مفيدة؟

المحلول

تحديث:كما ذكرنا في التعليقات، فإن Hal غير مدعوم في التوزيعات الأخيرة، والمعيار الآن هو udev، وإليك مثال صغير يستخدم حلقة glib و udev, ، أحتفظ بنسخة هال لأسباب تاريخية.

هذا هو في الأساس مثال في وثائق pyudev, ، تم تكييفه للعمل مع الإصدارات الأقدم، ومع حلقة glib، لاحظ أنه يجب تخصيص الفلتر ليناسب احتياجاتك المحددة:

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()

الإصدار القديم مع Hal و d-bus:

يمكنك استخدام روابط D-Bus والاستماع إليها DeviceAdded و DeviceRemoved إشارات.سيتعين عليك التحقق من إمكانيات الجهاز المضاف لتحديد أجهزة التخزين فقط.

إليك مثال صغير، يمكنك إزالة التعليقات وتجربته.

import dbus
import gobject

class DeviceAddedListener:
    def __init__(self):

تحتاج إلى الاتصال بـ Hal Manager باستخدام ناقل النظام.

        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")

وتحتاج إلى توصيل المستمع بالإشارات التي تهمك في هذه الحالة DeviceAdded.

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

أنا أستخدم مرشحًا يعتمد على القدرات.سوف يقبل أي volume وسوف ندعو do_something باستخدام if، يمكنك قراءة وثائق Hal للعثور على الاستعلامات الأكثر ملاءمة لاحتياجاتك، أو مزيد من المعلومات حول خصائص أجهزة 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)

مثال على الدالة التي تعرض بعض المعلومات حول وحدة التخزين:

     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()

نصائح أخرى

لم أحاول كتابة مثل هذا البرنامج بنفسي، ولكنني ألقيت نظرة على الرابطين التاليين (شكرًا لـ Google!)، والذي أعتقد أنه سيكون مفيدًا:

على وجه الخصوص، اقرأ عن org.freedesktop.Hal.Manager واجهة، ولها DeviceAdded و DeviceRemoved الأحداث.:-)

أتمنى أن يساعدك هذا!

أعتقد أن D-Bus سيعمل كما ذكر كريس، ولكن إذا كنت تستخدم KDE4، فقد تستخدم إطار العمل Solid بطريقة مشابهة لبرنامج KDE4 "New Device Notifier".

مصدر C++ لهذا التطبيق الصغير هو هنا, والذي يوضح كيفية استخدام Solid لاكتشاف الأجهزة الجديدة.استخدم PyKDE4 لربط Python بهذه المكتبات، كما هو موضح هنا.

وهنا هو الحل في 5 خطوط.

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.

وحفظ هذا إلى ملف يقول usb_monitor.py، python monitor.py تشغيل. لسد أي USB، وسوف طباعة تفاصيل الجهاز

→ 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

واختبارها على بيثون 3.5 مع pyudev==0.21.0.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top