Package: usb-monitor
USBMonitorUSBMonitoris a versatilecross-platformlibrary that simplifiesUSB device monitoringfor bothWindowsandLinuxsystems. It enables developers to effortlessly track deviceconnections,disconnections, and access to all connected deviceattributes.WithUSBMonitor, developers can stay up-to-date with any changes in the connected USB devices, allowing them totrigger specific actionswhenever a USB device is connected or disconnected. By ensuringconsistent functionality across various operating systems,USBMonitorremoves the need to address platform-specific quirks, inconsistencies, or incompatibilities, resulting in a smooth and efficient USB device management experience. The uniformity in functionality significantly enhancescode compatibility, minimizing the risk ofcode issuesorunexpected breakswhen moving between platforms.At its core,USBMonitorutilizespyudev(for Linux environments) andWMI(for Windows environments), handling all the low-level intricacies and translating OS-specific information to ensure consistency across both systems.InstallationTo installUSBMonitor, simply run:pipinstallusb-monitorUsageUsingUSBMonitoris both simple and straight-forward. In most cases, you'll just want to start themonitoringDaemon, defining theon_connectandon_disconnectcallback functions to manage events when a USB device connects or disconnects. Here's a basic example:fromusbmonitorimportUSBMonitorfromusbmonitor.attributesimportID_MODEL,ID_MODEL_ID,ID_VENDOR_IDdevice_info_str=lambdadevice_info:f"{device_info[ID_MODEL]}({device_info[ID_MODEL_ID]}-{device_info[ID_VENDOR_ID]})"# Define the `on_connect` and `on_disconnect` callbackson_connect=lambdadevice_id,device_info:print(f"Connected:{device_info_str(device_info=device_info)}")on_disconnect=lambdadevice_id,device_info:print(f"Disconnected:{device_info_str(device_info=device_info)}")# Create the USBMonitor instancemonitor=USBMonitor()# Start the daemonmonitor.start_monitoring(on_connect=on_connect,on_disconnect=on_disconnect)# ... Rest of your code ...# If you don't need it anymore stop the daemonmonitor.stop_monitoring()OutputLinuxWindowsSometimes, when initializing your software, you may seek to confirm which USB devices are indeed connected.fromusbmonitorimportUSBMonitorfromusbmonitor.attributesimportID_MODEL,ID_MODEL_ID,ID_VENDOR_ID# Create the USBMonitor instancemonitor=USBMonitor()# Get the current devicesdevices_dict=monitor.get_available_devices()# Print themfordevice_id,device_infoindevices_dict.items():print(f"{device_id}--{device_info[ID_MODEL]}({device_info[ID_MODEL_ID]}-{device_info[ID_VENDOR_ID]})")Output/dev/bus/usb/001/001--xHCI_Host_Controller(0002-1d6b)/dev/bus/usb/001/002--USB2.0_Hub(3431-2109)/dev/bus/usb/001/003--USB_Optical_Mouse(c077-046d)/dev/bus/usb/001/004--USB_Compliant_Keypad(9881-05a4)/dev/bus/usb/002/001--xHCI_Host_Controller(0003-1d6b)API ReferenceUSBMonitor(filter_devices = None)Initialize the USBMonitor instance. It will allow to inspect and monitor connected devicesfilter_devices:tuple[dict[str, str]] | None. A tuple of dictionaries containing the device attributes to filter. If passed, it will only return and monitor devices that match any of the specified filters. For example, if you want to only retrieve and track devices with 'ID_VENDOR_FROM_DATABASE' = 'Realtek' or the device with 'ID_VENDOR_ID' = '1234' and 'ID_MODEL_ID' = '1A2B' you should instantiate with:USBMonitor(filter_devices=({'ID_VENDOR_FROM_DATABASE': 'Realtek'}, {'ID_VENDOR_ID': '1234', 'ID_MODEL_ID': '1A2B'})). Default value is None.USBMonitor.start_monitoring(on_connect = None, on_disconnect = None, check_every_seconds = 0.5)Starts a daemon that continuously monitors the connected USB devices in order to detect new connections or disconnections. When a device is disconnected, theon_disconnectcallback function is invoked with the Device ID as the first argument and thedictionary of device informationas the second argument. Similarly, when a new device is connected, theon_connectcallback function is called with the same arguments. This allows developers to promptly respond to any changes in the connected USB devices and perform necessary actions.on_connect:callable | None. The function to call every time a device isadded. It is expected to have the following formaton_connect(device_id: str, device_info: dict[str, dict[str, str|tuple[str, ...]]])on_disconnect:callable | None. The function to call every time a device isremoved. It is expected to have the following formaton_disconnect(device_id: str, device_info: dict[str, dict[str, str|tuple[str, ...]]])check_every_seconds:int | float. Seconds to wait between each check for changes in the USB devices. Default value is 0.5 seconds.USBMonitor.stop_monitoring(warn_if_was_stopped=True)Stops the monitoring of USB devices. This function willstopthe daemon launched byUSBMonitor.start_monitoringwarn_if_was_stopped:bool. If set toTrue, this function will issue a warning if the monitoring of USB devices was already stopped (the daemon was not running).USBMonitor.get_available_devices()Returns a dictionary of the currently available devices, where the key is theDevice IDand the value is adictionary containing the device's information. All the keys of this dictionary can be found atattributes.DEVICE_ATTRIBUTES. They always correspond with the default Linux device properties (independently of the OS where the library is running).Returns:dict[str, dict[str, str|tuple[str, ...]]]: A dictionary containing the currently available devices. All values are strings except forID_USB_INTERFACES, which is atupleofstringUSBMonitor.changes_from_last_check(update_last_check_devices = True)Returns a tuple of two dictionaries, one containing the devices that have beenremovedsince the last check, and another one containing the devices that have beenadded. Both dictionaries will have theDevice IDas key and all the device information as value. Remember that all thekeys of this dictionarycan be found at can be found atattributes.DEVICE_ATTRIBUTES.update_last_check_devices:bool. IfTrueit will update the internalUSBMonitor.last_check_devicesattribute. So the next time you'll call this method, it will check for differences against the devices found in that current call. IfFalseit won't update theUSBMonitor.last_check_devicesattribute.Returns:tuple[dict[str, dict[str, str|tuple[str, ...]]], dict[str, dict[str, str|tuple[str, ...]]]]: Atuplecontaining twodictionaries. The firstdictionarycontains the information of the devices that wereremovedsince the last check and the second dictionary contains the information of the newaddeddevices. All values arestringsexcept forID_USB_INTERFACES, which is atupleofstring.USBMonitor.check_changes(on_connect = None, on_disconnect = None, update_last_check_devices = True)Checks for any new connections or disconnections of USB devices since the last check. If a device has been removed, theon_disconnectfunction will be called with theDevice IDas the first argument and thedictionary with the device's informationas the second argument. The same will occur with theon_connectfunction if any new device have been added. Internally this function will just runUSBMonitor.changes_from_last_checkand will execute the callbacks for each returned deviceon_connect:callable | None. The function to call when a device is added. It is expected to have the following formaton_connect(device_id: str, device_info: dict[str, dict[str, str|tuple[str, ...]]])on_disconnect:callable | None. The function to call when a device is removed. It is expected to have the following formaton_disconnect(device_id: str, device_info: dict[str, dict[str, str|tuple[str, ...]]])update_last_check_devices:bool. IfTrueit will update the internalUSBMonitor.last_check_devicesattribute. So the next time you'll call this method, it will check for differences against the devices found in that current call. IfFalseit won't update theUSBMonitor.last_check_devicesattribute.Device PropertiesThedevice_inforeturned by most functions will contain the following information:KeyValue DescriptionExample'ID_MODEL_ID'The product ID of the USB device.'0892''ID_MODEL'The name of the USB device model.'HD_Pro_Webcam_C920''ID_MODEL_FROM_DATABASE'Device model name, retrieved from the device database.'OrbiCam''ID_VENDOR'The name of the USB device vendor'046d''ID_VENDOR_ID'The vendor ID of the USB device.'046d''ID_VENDOR_FROM_DATABASE'USB device vendor's name, from the device database.'Logitech, Inc.''ID_USB_INTERFACES'Atuplerepresenting the USB device's interfaces.('0e0100', '0e0200', '010100', '010200')'DEVNAME'The device name or path'/dev/bus/usb/001/003''DEVTYPE'Should always be'usb_device'.'usb_device'Note that, depending on the device and the OS, some of this information may be incomplete or certain attributes may overlap with others.RoadmapAccepting MacOS (As soon as I will have access to a MacOS system to test it out)