Metadata-Version: 2.4
Name: cyme_win
Version: 1.5.1
Summary: Windows USB 热拔插监控库
Author-email: zhaof <297549653@qq.com>
Project-URL: Homepage, https://github.com/tuna-f1sh/cyme
Keywords: usb,windows,monitor,hotplug,cyme
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# cyme_win

Windows USB hotplug monitor based on [cyme](https://github.com/tuna-f1sh/cyme), simple and easy to use.

## Installation

```bash
pip install cyme_win
```

## Quick Start

```python
import cyme_win

# Download cyme.exe (first time only)
cyme_win.download_cyme()

# Simple callback - one line to monitor USB hotplug
cyme_win.watch(lambda d: print(f"{d['event']}: {d['name']} ({d['vid_pid']})"))

import time
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    pass
```

## Device Info

The callback receives a dict with these fields:

| Field | Description | Example |
|-------|-------------|---------|
| `event` | Event type | `"connect"` / `"disconnect"` |
| `name` | Device name | `"SanDisk USB Flash Drive"` |
| `vendor_id` | Vendor ID | `"0781"` |
| `product_id` | Product ID | `"5567"` |
| `vid_pid` | Combined format | `"0781:5567"` |
| `location` | Linux-style location | `"0-15"` |
| `manufacturer` | Manufacturer name | `"SanDisk"` |
| `serial` | Device serial number | `"4C5300012345"` |
| `speed` | Transfer speed | `"480.0 Mb/s"` |
| `device_class` | USB device class | `"mass-storage"` |
| `bus` | Bus number | `0` |
| `port` | Port number | `15` |

## Examples

### Example 1: Distinguish connect/disconnect events

```python
import cyme_win

def on_device(d):
    symbol = "+" if d["event"] == "connect" else "-"
    print(f"[{symbol}] {d['name']}")
    print(f"    VID/PID: {d['vid_pid']}")
    print(f"    Location: {d['location']}")

cyme_win.watch(on_device)

import time
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    print("Stopped")
```

### Example 2: Monitor specific devices

```python
import cyme_win

def on_storage(d):
    # Only monitor mass storage devices
    if d.get("device_class") == "mass-storage":
        print(f"USB Drive {d['event']}: {d['name']}")
        print(f"  Serial: {d['serial']}")
        print(f"  Speed: {d['speed']}")

cyme_win.watch(on_storage)
```

### Example 3: Using class API (multiple callbacks)

```python
import cyme_win

def log_device(d):
    with open("usb_log.txt", "a") as f:
        f.write(f"{d['event']} | {d['name']} | {d['vid_pid']}\n")

def notify(d):
    print(f"Notify: {d['event']} - {d['name']}")

# Create monitor, add multiple callbacks
monitor = cyme_win.USBMonitor()
monitor.add_callback(log_device)
monitor.add_callback(notify)
monitor.start()

import time
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    monitor.stop()
```

### Example 4: Using context manager

```python
import cyme_win

with cyme_win.USBMonitor().add_callback(lambda d: print(d)):
    print("Monitoring... Press Ctrl+C to exit")
    import time
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        pass
```

### Example 5: Get full device info

```python
import cyme_win

def show_details(d):
    print(f"\n{'='*50}")
    print(f"Event: {d['event']}")
    print(f"Name: {d['name']}")
    print(f"VID:PID: {d['vid_pid']}")
    print(f"Manufacturer: {d['manufacturer']}")
    print(f"Serial: {d['serial']}")
    print(f"Speed: {d['speed']}")
    print(f"Location: {d['location']} (bus {d['bus']}, port {d['port']})")
    print(f"Class: {d['device_class']}")
    print(f"{'='*50}\n")

cyme_win.watch(show_details)

import time
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    pass
```

## API Reference

### `download_cyme(target_dir=None)`

Download cyme.exe to specified directory (default: current working directory).

```python
cyme_win.download_cyme()  # Current directory
cyme_win.download_cyme("E:/my_project")  # Specified directory
```

### `watch(callback, cyme_path=None)`

Global singleton mode, simplest way to use.

```python
# Auto-find cyme.exe
cyme_win.watch(lambda d: print(d))

# Specify cyme.exe path
cyme_win.watch(lambda d: print(d), cyme_path="E:/tools/cyme.exe")
```

### `stop()`

Stop global monitoring.

```python
cyme_win.stop()
```

### `USBMonitor` class

| Method | Description |
|--------|-------------|
| `__init__(cyme_path=None)` | Create monitor, optionally specify cyme.exe path |
| `add_callback(fn)` | Add event callback, returns self for chaining |
| `start()` | Start monitoring |
| `stop()` | Stop monitoring |

```python
# Auto-find cyme.exe
monitor = cyme_win.USBMonitor()

# Specify cyme.exe path
monitor = cyme_win.USBMonitor(cyme_path="E:/tools/cyme.exe")
```

## Links

- cyme project: https://github.com/tuna-f1sh/cyme
- cyme releases: https://github.com/tuna-f1sh/cyme/releases

## License

MIT
