Skip to content

TITManagement/USB-Util

Repository files navigation

USB-util

Python License

AiLab Project Documentation

概要

USB-utilは、接続済みのUSBデバイス/BLEデバイスをスキャンし、詳細情報をGUIで閲覧できるクロスプラットフォーム対応のPythonツールです。macOS/LinuxではPyUSB+libusb、WindowsではWMI経由でCOMポート情報も取得し、usb.idsによるベンダー/製品名補完やスナップショット永続化、責務分離設計を特徴とします。

主な機能

  • macOS/Linux: PyUSBによるUSBデバイススキャン・メタデータ取得
  • Windows: WMI経由でCOMポート突合・USB情報取得
  • usb.idsによるベンダー/プロダクト名自動解決
  • 取得スナップショットのusb_devices.json保存
  • CustomTkinterベースのGUIでのデバイス切替・JSONプレビュー
  • エラーメッセージの明示表示
  • COMポート情報の自動逆引き(core/com_ports.py利用)
  • Windows: ハブ/ポート連鎖・USBコントローラ名自動解析
  • Serial/Port Path/BUS/Addressを組み合わせた識別タグ生成

技術仕様・動作環境

  • Python: 3.9以降
  • macOS/Linux: libusb 1.0(PyUSBバックエンド)
  • Windows: WMIサービス有効な環境(WinUSB/Zadig等不要)
  • ネイティブライブラリのビルド/読み込みに必要な環境

インストール

【重要】pip index一元管理について

依存解決の再現性向上のため、pip の index 設定は
$AILAB_ROOT/lab_automation_module/config/pip/pip.conf.local を正本とします。

ローカル環境では AILAB_ROOT を各マシンで設定してから PIP_CONFIG_FILE を指定してください。

export AILAB_ROOT=/path/to/AiLab
export PIP_CONFIG_FILE="$AILAB_ROOT/lab_automation_module/config/pip/pip.conf.local"

CI では PIP_CONFIG_FILE 固定ではなく、環境変数で index を注入してください。

export PIP_INDEX_URL="http://<internal-pypi>/simple"
export PIP_EXTRA_INDEX_URL="https://pypi.org/simple"
export PIP_TRUSTED_HOST="<internal-pypi-host>"

OS別セットアップ

macOS

  • Homebrewで brew install libusb

使い方

python main.py

USB/BLE情報モデル

USB: VID/PID、Manufacturer/Product、Serial、Bus/Address、Port Path、Descriptor情報
BLE: BLE Address、デバイス名、RSSI、Service UUIDs

構成

USB-util/
├── src/
├── docs/
├── scripts/
├── pyproject.toml
├── LICENSE
└── README.md

コントリビューション

バグ報告・機能要望・プルリクエストを歓迎します。

ライセンス

MIT License — 詳細は LICENSE をご覧ください。

Ubuntu 24.04

  • sudo apt update && sudo apt install libusb-1.0-0

Windows

  • Python仮想環境有効化: venv\Scripts\activate(PowerShell/コマンドプロンプト)
  • 追加パッケージ: pip install customtkinter wmi
  • シリアル通信やCOMポート列挙を行う場合は pip install pyserial

注意: Windowsは管理者権限で実行することを推奨します。

Python依存パッケージ

customtkinter
pyusb      # macOS/LinuxでのUSBスキャン用
wmi        # WindowsでのUSB情報取得用
pyserial   # COMポート列挙/シリアル通信を行う場合

補足: macOSでHomebrewを利用している場合は brew install libusb、Linuxでは各ディストリビューションのパッケージマネージャーから libusb-1.0 をインストールしてください。WindowsではWMIサービスが有効であれば追加のドライバ導入は不要です。

セットアップ

【重要】pip index一元管理について

依存解決の再現性向上のため、pip の index 設定は
$AILAB_ROOT/lab_automation_module/config/pip/pip.conf.local を正本とします。

ローカル環境では AILAB_ROOT を各マシンで設定してから PIP_CONFIG_FILE を指定してください。

export AILAB_ROOT=/path/to/AiLab
export PIP_CONFIG_FILE="$AILAB_ROOT/lab_automation_module/config/pip/pip.conf.local"

CI では PIP_CONFIG_FILE 固定ではなく、環境変数で index を注入してください。

export PIP_INDEX_URL="http://<internal-pypi>/simple"
export PIP_EXTRA_INDEX_URL="https://pypi.org/simple"
export PIP_TRUSTED_HOST="<internal-pypi-host>"
  1. 仮想環境を作成して有効化します。
    python -m venv .venv_USB-Util
    source .venv_USB-Util/bin/activate  # Windowsは .venv_USB-Util\Scripts\activate
  2. プロジェクト依存をインストールします。
    python -m pip install -e .
    python -m pip check
  3. python -m pip -V を実行し、.venv_USB-Util 配下の pip が使われていることを確認します。
  4. usb.ids をプロジェクトルートに配置するか、環境変数 USB_IDS_PATH で外部のusb.idsファイルを指定します。
    代表的な設置場所(Linux, macOS)は /usr/share/hwdata/usb.ids 等です。

依存更新ルール(再発防止)
ak_communication / aist_guiparts を更新した場合は、対象パッケージの version を上げた上で lab_automation_libs/internal-PyPI/dist/ の wheel を更新してください。同一バージョンの差し替えはキャッシュ衝突の原因になります。

使い方

  1. Python環境をアクティブにした状態で usb_util_gui.py を実行します。
    python usb_util_gui.py
  2. 初回起動時にUSBデバイスをスキャンし、結果を usb_devices.json に保存します。
  3. GUI上部のコンボボックスからデバイス(VID:PID形式)を切り替えると、左側に主要情報、右側に詳細JSONが表示されます(ViewModelが選択状態と表示内容を管理します)。

USB IDsの検索パス

アプリケーションは以下の優先順位で usb.ids を探索します。

  1. 環境変数 USB_IDS_PATH
  2. プロジェクトルートの usb.ids
  3. 現在の作業ディレクトリの usb.ids
  4. OS毎の代表パス(例: /usr/share/hwdata/usb.ids/opt/homebrew/share/hwdata/usb.ids など)

COMポート自動割当・逆引き機能

USB-Serialデバイスは、PCから抜き差しするたびにCOMポート番号(例: COM5, /dev/ttyUSB0 など)が変わることがありますが、 VID(ベンダーID)、PID(プロダクトID)、Serial(シリアル番号)はデバイス固有で基本的に不変です。

本ツールでは、

  • get_com_port_for_device(vid, pid, serial=None) というAPIで、
  • 指定したUSBデバイス(VID/PID/Serial)に一致する現在割り当てられているCOMポート番号を自動で取得できます。

これにより、

  • 物理的な抜き差しやPC再起動後でも、同じデバイスを正しく自動制御できる
  • LiquidDispenser("COM5") のようなAPIの引数を自動で割り当て可能
  • GUI上でもCOMポート情報が自動表示される

使い方例

com_port = get_com_port_for_device(vid, pid, serial)
if com_port:
    sender = LiquidDispenser(com_port)

外部モジュールからの利用例

プロジェクトとは別のスクリプトから直接COMポートを解決したい場合は、usb_util_gui.py が提供するヘルパー関数をインポートして使用できます。

# other_module.py からの利用サンプル
from usb_util_gui import get_com_port_for_device

vid = "0x1234"
pid = "0x5678"
serial = "ABCDEF123"

port = get_com_port_for_device(vid, pid, serial, refresh=True)
if port:
    print(f"USBデバイスのCOMポートは {port} です")
else:
    print("一致するCOMポートが見つかりませんでした")

refresh=True を指定すると呼び出し前にUSBデバイスの再スキャンを行います(既存スナップショットがある場合は省略可能)。戻り値は serial.Serial(port=...) に渡せる文字列です。

メリット

  • デバイス固有情報(vid, pid, serial)からCOMポートを逆引きできる
  • USBデバイスの抜き差しや環境変化にも柔軟に対応
  • GUIでもCOMポート情報を確認可能
  • Windowsでは、WMI経由でHub/Port番号とUSBコントローラ名を同時取得
  • Serialが取得できないケースでも、Port PathやBUS/Addressを組み合わせた識別タグで同一機種を区別可能

実装上は core/com_ports.pyComPortManager を介してアクセスします。GUIでは ViewModel からこのクラスを利用し、同期的にCOMポート情報を解決しています。

コマンドラインからCOMポートを取得する方法

USBデバイスのVID/PID/Serialから、現在割り当てられているCOMポート番号をコマンドラインで取得できます。

使い方

usb_util_gui.py を以下のように実行します:

python usb_util_gui.py <vid> <pid> [serial]
  • <vid>: ベンダーID(例: 0x1234)
  • <pid>: プロダクトID(例: 0x5678)
  • [serial]: シリアル番号(省略可能)
  • --refresh フラグを併用するとコマンド呼び出しの直前に再スキャンを実施します。

実行例

python usb_util_gui.py 0x1234 0x5678 ABCDEF123

→ 該当するCOMポート名(例: COM5, /dev/tty.usbserial-xxxx)が標準出力に表示されます。 VID/PIDに対するベンダー名・製品名(usb.ids由来)と、実機から取得した生のManufacturer/Product文字列も併記されるため、入力値の検証が容易です。識別タグ・ポートパス・バス/アドレスも併せて出力されるため、同一機種が複数ある場合でも個体を特定できます。

シリアル番号は省略可能です。

GUIを起動したい場合は引数なしで python usb_util_gui.py を実行してください。

代表的な実行例(usb_devices.json に基づく実サンプル)

python usb_util_gui.py 0x25a4 0x9311
python usb_util_gui.py 0x25a4 0x9311 --send "STATUS" --append-newline --read-until OK --baudrate 115200
python usb_util_gui.py 0x03e7 0x2485 03e72485 --refresh
python usb_util_gui.py --self-test

自己診断コマンド

環境セットアップが正しく行われているか確認したいときは、以下のコマンドで自己診断を実行できます。

python usb_util_gui.py --self-test
  • 現在保存されているUSBスナップショット(最大5件)と、pyserialが検出したCOMポートを一覧表示します。
  • Windowsの場合はWMI経由の取得結果、macOS/Linuxの場合はPyUSB経由の結果が確認できます。
  • 失敗時には不足しているライブラリや権限に関するヒントが表示されます。

アーキテクチャ

core/
 ├─ com_ports.py        # USB-Serialポート検出ヘルパー
 ├─ models.py           # UsbDeviceSnapshotデータクラス
 ├─ scanner.py          # OS毎にPyUSB/WMIを使い分けてUSBデバイスをスキャン
 ├─ repository.py       # JSONファイル永続化
 ├─ service.py          # UsbSnapshotService(スキャンと永続化の調停)
 └─ topology_wmi.py     # Windows用Hub/Port/Controller解析
ui/
 └─ view_model.py       # UsbDevicesViewModel(GUIの状態管理)
usb_util_gui.py         # TkベースのView(UsbDevicesApp)とアプリ起動エントリ
  • サービス層 (core/service.py)
    UsbSnapshotServiceUsbScannerUsbSnapshotRepository を協調させ、スキャン結果をJSONへ保存します。またUSB接続状態確認の窓口もここに集約しています。

  • スキャナ (core/scanner.py)
    macOS/LinuxではPyUSB、WindowsではWMIを利用してUSBデバイスを列挙・詳細取得します。CLI/GUIの双方から共通利用できるよう、依存は最小限に抑えています。

  • トポロジ解析 (core/topology_wmi.py)
    Windows環境ではWMIを用いてPnPデバイスを解析し、Hub/Port連鎖とUSBホストコントローラ名を抽出します。サービス層から呼び出され、スナップショットへ追加情報として格納されます。

  • ViewModel (ui/view_model.py)
    UsbDevicesViewModel がスナップショットの並び替え、選択状態、派生情報(COMポート・表示用テキスト)を管理し、View から呼び出し可能なメソッドを提供します。

  • View (usb_util_gui.py)
    UsbDevicesApp はCustomTkinterでUI要素を構築し、ViewModelが提供する値に従って描画・再描画します。イベントハンドラはViewModelへの委譲を行うだけに簡素化されています。

この構成により、ビジネスロジック(スキャン/永続化/状態管理)と表示ロジックを明確に分離し、テストや機能拡張を容易にしています。

トラブルシューティング

  • PyUSBが見つからない: macOS/Linuxでは pip install pyusb を実行してください。WindowsではPyUSB依存なしで動作します。
  • libusb backend が見つからない: macOS/Linux向けにlibusb 1.0を導入します。Windowsでは不要です。
  • WMIでエラーが発生する: PowerShellで Get-Service Winmgmt が実行できるか、管理者権限でアプリを起動しているか確認してください。
  • USBデバイスが表示されない: 実行ユーザーにUSBデバイスへアクセスできる権限があるか確認してください。Linuxではplugdevグループへの所属やudevルールの調整が必要な場合があります。
  • GUIフォントが崩れる: Meiryoが存在しない環境では、CustomTkinterが代替フォントを使用します。必要に応じてコード中のフォント設定を変更してください。

開発メモ

  • 収集したUSBスナップショットは usb_devices.json に配列形式で保存されます。内容を直接編集するとGUIにも反映されます。
  • スキャン・永続化ロジックは core/ 配下、GUIはViewModel+Viewに二分されています。エントリポイントは usb_util_gui.pymain() です。
  • ViewModelはテストしやすいようにPure Pythonで実装されています。UIの結合テストを行う場合もViewModelをモック化することで効率的に検証できます。

ライセンス

MIT License

作者

  • TITManagement 2025

対象者

  • 運用担当者: 日常運用・手順実行を行う担当者
  • 開発者: 機能追加・保守を行う担当者
  • 検証担当者: 実機/テスト環境で動作確認を行う担当者

依存関係

  • Python: pyproject.tomlrequires-python に従う
  • 主要ライブラリ: pyproject.tomldependencies を参照
  • pip index設定: $AILAB_ROOT/lab_automation_module/config/pip/pip.conf.local を正本とする

最短セットアップ

bash / zsh で以下を実行。

export AILAB_ROOT=/path/to/AiLab
export PIP_CONFIG_FILE="$AILAB_ROOT/lab_automation_module/config/pip/pip.conf.local"
python -m venv .venv_USB-Util
source .venv_USB-Util/bin/activate
python -m pip install -e .

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages