Skip to main content

USB Inspector

Coverage

Overview

A simple package that leverages pyusb and allows you to lookup USB vendor and device IDs and get back a human readable vendor and device name. It includes ability to manually update the USB DB without installing a new version of usb-inspector.

Installation

uv add usb-inspector
# via pip
python3 -m pip install usb-inspector

IMPORTANT: On Windows ensure you have libusb-1.0.dll (64bit) in C:\Windows\System32 or you will get a NoBackendError. You can get it from here.

Example Usage

Command Line:

usb-inspector lookup --vendor-id 1A40
usb-inspector lookup --vendor-id 1A40 --device-id 0801

# To manually update the USB DB
usb-inspector delete-data
usb-inspector update-db
import asyncio

from usb_inspector import create_usb_monitoring_service

async def main():
    service = create_usb_monitoring_service(poll_interval=1.0)
    monitor_task = asyncio.create_task(service.run())
    await asyncio.sleep(10)
    await service.stop()
    await monitor_task

asyncio.run(main())

Device identity

USB Inspector uses a device's vendor/product IDs and USB serial number as its preferred identity. When a backend cannot read a serial number temporarily, it uses the USB bus and port path to retain the identity already associated with that physical connection. USB addresses are not treated as stable because they can change when a device re-enumerates.

If a device has no readable serial number and is moved to a different USB port, it is necessarily reported as a new device.

Each scan returns one snapshot per full_system_uid, even if enumeration returns the same device multiple times. A camera with a readable serial keeps the same identity when its bus, address, or port changes.

When displaying monitored devices, update rows by full_system_uid rather than appending a row for every connection event. A reconnect produces another connected event for the same camera. The registry retains disconnected devices, so count currently plugged-in cameras using get_connected_devices_by_type, not the number of connection events or all devices ever seen:

cameras = service.get_connected_devices_by_type("2bc5_066b")
connected_count = len(cameras)

The type key uses an underscore; each camera's full_system_uid uses colons, for example 2bc5:066b:CL8E36300FC. If only four specific cameras should be included, filter cameras against their expected serial numbers. Vendor/product IDs alone select every camera of that model.

Issues

If you experience any issues, please create an issue on Bitbucket.

Development

To get a list of all commands with descriptions simply run just.

just env
just pip-install-editable

Testing

just pytest
just coverage
just open-coverage

History

All notable changes to this project will be documented in this file. This project adheres to Semantic Versioning.

1.1.1 (2026-10-05)

  • FIXED package validation now requires Twine 7.0.0 or newer to support metadata version 2.5.
  • FIXED repeated USB enumeration results no longer produce duplicate device snapshots or connection callbacks for the same full system UID.
  • ADDED regression coverage for four cameras with unique serials, repeated enumeration, USB location changes, and reconnects.
  • ADDED guidance for updating monitor rows by full system UID and counting currently connected cameras by device type.

1.1.0 (2026-08-11)

  • FIXED transient USB serial-number read failures no longer create duplicate device records or spurious disconnect/connect events.
  • CHANGED device monitoring now reads each serial number once per snapshot and uses the USB bus/port path to preserve an established device identity when the serial is temporarily unavailable.
  • ADDED detection of a different serial number at the same USB port as a device replacement.

1.0.0 (2026-05-22)

Breaking changes

  • REMOVED USBDeviceMonitor from the public API. Use create_usb_monitoring_service() instead, which returns a USBMonitoringService instance with the same behavior.
  • REMOVED standalone free functions lookup_usb_details, delete_usb_db, delete_data_file, and update_usb_db from usb_inspector.usb.infrastructure.repository. Use SQLiteUSBDetailsRepository and USBDatabaseMaintenanceRepository directly.
  • CHANGED public API of usb_inspector package now exports USBMonitoringService, USBDetailsLookupPort, and create_usb_monitoring_service. Importing USBDeviceMonitor from the top-level package will raise ImportError. USBEnumeratorPort remains importable from usb_inspector.usb.application.ports.

Other changes

  • CHANGED package no longer initialises the USB database on import. Initialisation is now lazy: the database is created on the first call to SQLiteUSBDetailsRepository.lookup() if it does not already exist.
  • CHANGED usb_inspector.usb package no longer re-exports USBMonitoringService; import from usb_inspector or usb_inspector.usb.application.service directly.
  • CHANGED usb_inspector.usb.infrastructure package now exports only create_usb_monitoring_service; concrete repository classes remain importable from their module.

0.3.1 (2026-04-21)

  • CHANGED updated build backend and release tooling configuration.
  • CHANGED refreshed Justfile workflows for environment, testing, and release checks.
  • CHANGED updated packaging/verification helper scripts and dependency lock maintenance.
  • CHANGED updated pre-commit toolchain versions.

0.3.0 (2026-03-13)

  • CHANGED refactored package internals to a layered DDD structure under usb_inspector.usb (domain/application/infrastructure/interface).
  • CHANGED internal legacy modules db.py, update.py, and cli.py were removed; CLI entry point now resolves to usb_inspector.usb.interface.router:cli.
  • CHANGED usb_inspector.monitor remains available as a compatibility shim for USBDeviceMonitor.
  • FIXED circular import issues in package initialization/import flow.
  • ADDED layered test coverage for application and infrastructure modules plus import regression coverage.

0.2.2 (2025-12-04)

  • ADDED tox and more test coverage

0.2.1 (2025-11-21)

  • ADDED port to the device info
  • CHANGED cleaned up logging on connect/disconnect descriptions

0.2.0 (2025-11-21)

  • FIXED Connecting/Disconnecting the same physical device to the same port now correctly identifies the device as the same device on Windows/Linux.

0.1.9 (2025-11-21)

  • FIXED Cached sql db lookup so it occurs only once.

0.1.8 (2025-11-20)

  • FIXED turned default packaged logging to ERROR. Was INFO...Sorry!

0.1.7 (2025-11-13)

  • FIXED is_connected bug introduced in last patch.
  • ADDED improved tracking of devices allowing multiple of the same vendor/device ID to be connected.

0.1.6 (2025-11-13)

  • FIXED last_seen timestamp for each device, only updates when connected/disonnected.

0.1.5 (2025-11-05)

  • Locked pandas to version 2.3.3 for Raspberry Pi compatability (it pulls the pre-built wheel from piwheels.org)

0.1.4 (2025-11-05)

  • Added last_seen timestamp for each device.

0.1.4 (2025-10-31)

  • update-db cli command only adds new Vendors and Devices to the existing DB rather than requiring deletion and recreation of the DB.
  • Track which devices are connected/disconnected.

0.1.2 (2025-10-30)

  • Fix lookup error

0.1.1 (2025-10-30)

  • Added start as an alias for monitor.

0.1.0 (2025-10-30)

  • First release

Metadata

Release files for usb-inspector 1.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for usb-inspector 1.1.1
File Size Uploaded
usb_inspector-1.1.1.tar.gz 348.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for usb-inspector 1.1.1
File Interpreter ABI Platform
usb_inspector-1.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 622.6 kB

Release files / usb_inspector-1.1.1.tar.gz

Download URL usb_inspector-1.1.1.tar.gz
Size 348.1 kB
Tags Source
SHA-256 checksum
How to use checksums
2784c6cc14031d93727394ccc8119ab7206665ef82001f0cc881b3c0a79b9a30
BLAKE2b-256 checksum
How to use checksums
4e2ed6c188718f915e4d0e03a7b765e41c7f8037da2a35d07f40f89661b70475
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.1

Release files / usb_inspector-1.1.1-py3-none-any.whl

Download URL usb_inspector-1.1.1-py3-none-any.whl
Size 274.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
765559e5e50041fa985ea5972cefe855e6a16f9c1f3321b7e4170d392374ddd0
BLAKE2b-256 checksum
How to use checksums
38fcc116bd1bd788fdd3736dd08857757d63cb1ef8d4271faf741b26425ba646
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.1

Release history Release notifications | RSS feed

This release

1.1.1 This release

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page