كيف يمكنني الاستماع إلى أحداث "تم إدخال جهاز USB" في Linux، في Python؟
سؤال
أرغب في كتابة برنامج نصي 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!)، والذي أعتقد أنه سيكون مفيدًا:
- البرنامج التعليمي dbus-بايثون (الذي يتحدث عن كيفية استخدام بايثون للوصول إلى D-Bus)
- مواصفات هال 0.5.10 (الذي يتحدث عن كيفية قيام HAL بنشر الأحداث إلى D-Bus)
على وجه الخصوص، اقرأ عن org.freedesktop.Hal.Manager
واجهة، ولها DeviceAdded
و DeviceRemoved
الأحداث.:-)
أتمنى أن يساعدك هذا!
وهنا هو الحل في 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
.