-
Notifications
You must be signed in to change notification settings - Fork 1
feat: Multi-device discovery with USB hardware identification and serial device support #108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
X9X0
merged 19 commits into
main
from
claude/fix-multiple-device-discovery-01HqshYU6Sr9M8ce7nWv3Yvd
Dec 2, 2025
Merged
feat: Multi-device discovery with USB hardware identification and serial device support #108
X9X0
merged 19 commits into
main
from
claude/fix-multiple-device-discovery-01HqshYU6Sr9M8ce7nWv3Yvd
Dec 2, 2025
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
…fication
This commit addresses several critical issues with device discovery and
adds comprehensive improvements to make the process more robust and user-friendly.
## Key Features
### 1. USB Hardware ID Database
- Created comprehensive USB VID:PID to device model mapping database
- Supports automatic device identification for:
- B&K Precision power supplies (1685B, 9205B, 9206B, 9130B, 1902B)
- Rigol oscilloscopes (DS1000Z, MSO2072A, DS1102D)
- Rigol electronic loads (DL3021A)
- Keysight/Agilent equipment
- Common USB-to-Serial bridges (CP210x, FTDI)
- Provides fallback identification when *IDN? queries fail
### 2. Async Parallel Device Discovery
- Converted VISA scanner to fully async implementation
- Parallel device queries with semaphore-controlled concurrency (max 3 concurrent)
- Non-blocking *IDN? queries using asyncio executors
- Eliminates sequential bottlenecks that caused only first device to be detected
### 3. Real-time Progress Streaming
- WebSocket-based progress updates during discovery
- Detailed feedback at each stage:
- Resource enumeration
- Device querying (with current/total count)
- Device identification (manufacturer/model)
- Error reporting
- Prevents "python3: is not responding" errors in PyQt6 GUI
### 4. Enhanced User Experience
- Progress dialog in PyQt6 client shows live discovery status
- Percentage-based progress bar (0-100%)
- Clear status messages for each discovery phase
- Graceful error handling with user-friendly messages
## Technical Implementation
### USB Hardware Database
- New file: `server/discovery/usb_hardware_db.py`
- Parses USB VID:PID from VISA resource strings
- Returns device metadata (manufacturer, model, type, specs)
- Used as fallback when SCPI communication fails
### Async VISA Scanner
- `scan()` method is now fully async
- Uses `asyncio.gather()` for parallel processing
- Runs blocking PyVISA calls in thread executor
- Progress callbacks at each stage
- Controlled concurrency to avoid overwhelming devices
### Discovery Manager Integration
- Progress callback mechanism for real-time updates
- Forwards VISA scanner progress to WebSocket clients
- Maintains backward compatibility with existing API
### WebSocket Progress Streaming
- Discovery progress messages broadcast to all connected clients
- Message format: `{type: "discovery_progress", event_type: str, data: dict}`
- Client-side signal/slot architecture for thread-safe GUI updates
## Bug Fixes
- Fixed issue where only first device was detected due to sequential blocking
- Fixed "not responding" errors caused by synchronous VISA operations
- Fixed missing identification for USB devices when *IDN? times out
- Fixed lack of user feedback during long-running discovery operations
## Testing Notes
This fix specifically addresses the issue where:
- BK 1685 Power Supply (first device) was detected
- BK 9205B Power Supply (second device) was not detected
With these changes:
- Both devices should be discovered in parallel
- Even if *IDN? fails, USB VID:PID provides identification
- User sees real-time progress: "Querying device 1/2", "Querying device 2/2", etc.
- No GUI freezing or "not responding" errors
## Files Changed
- `server/discovery/usb_hardware_db.py`: New USB hardware database
- `server/discovery/visa_scanner.py`: Async parallel scanning
- `server/discovery/manager.py`: Progress callback integration
- `server/main.py`: WebSocket progress streaming setup
- `client/ui/equipment_panel.py`: Progress dialog and WebSocket handlers
Resolves multiple device discovery issues.
Fixed scoping error where datetime was being used in discovery_progress_callback but was only imported later in a conditional block. This was causing the error: "cannot access free variable 'datetime' where it is not associated with a value in enclosing scope" and preventing any device discovery from working. The datetime import is now at the top of the file with other standard imports.
Created comprehensive test script to verify basic VISA/SCPI communication with the BK Precision 9205B power supply. This helps isolate whether issues are with device communication, SCPI command compatibility, or driver implementation. Features: - Auto-discovery of VISA resources - USB VID:PID detection (2ec7:9200) - Tests standard SCPI commands (*IDN?, MEAS:VOLT?, MEAS:CURR?, etc.) - Safe write command testing (only when output is OFF) - Detailed error reporting and summary Usage: python3 test_bk9205b.py
Fixed device selection to properly parse USB resource strings and convert VID:PID from decimal to hex format. The script now: - Correctly identifies BK 9205B by matching decimal IDs (11975:37376) - Shows hex and decimal VID:PID for all USB devices - Skips serial devices (ASRL) to avoid connecting to wrong device - Provides better diagnostic output This fixes the issue where the script was connecting to ASRL/dev/ttyUSB0 instead of the actual USB device.
The BK 9205B doesn't support the device.clear() operation (causes VI_ERROR_NSUP_OPER). Removed clear() calls before queries. Also added BK-specific commands to test: - GETD (Get device data - used in original LabLink logs) - GETS (Get status) - GPAL (Get all parameters) - ISET?, VSET? (alternate query commands) This will help identify which command set the BK 9205B actually uses instead of assuming it implements full SCPI.
The BK 9205B is a newer model that uses standard SCPI commands via USB, unlike older BK models (1685B, 1902B) which use proprietary serial protocol. Changes: - BK9205B now inherits from BaseEquipment instead of BKPowerSupplyBase - Removed proprietary commands (GETD, GETS, GMAX, GOUT) - Implemented standard SCPI commands: * *IDN? for identification * VOLT/CURR for setting values * VOLT?/CURR? for querying setpoints * MEAS:VOLT?/MEAS:CURR? for actual measurements * OUTP ON/OFF for output control * SYST:ERR? for error checking - Configure USB connection with \n terminators (not \r for serial) - Remove device.clear() calls (not supported by BK 9205B) - 5 second timeout for USB communication This fixes the timeout errors where the driver was sending GETD commands that the BK 9205B doesn't understand.
Implemented automatic selection of equipment type and model when devices are clicked in the discovery dialog, based on USB VID:PID identification. Changes: - equipment_manager.discover_devices() now returns full DiscoveredDevice objects with manufacturer, model, device_type, and confidence score - API /discover endpoint now returns devices array with full info - ConnectDeviceDialog enhancements: * Display manufacturer, model, and device type for each resource * Highlight devices with high confidence (green=*IDN?, yellow=USB DB) * Auto-populate equipment type dropdown when device is selected * Auto-populate model dropdown when device is selected * Add tooltips showing identification method * Larger dialog size (700x450) to accommodate richer information - equipment_panel updated to use new devices format Benefits: - Prevents wrong model selection (e.g., 9206B vs 9205B confusion) - Improves user experience with visual confidence indicators - Reduces manual input by auto-filling known device information - Makes device identification status clear to users Fixes the issue where BK 9205B was being mis-identified as 9206B due to hardcoded default values in the dialog.
Fixed two issues preventing discovery from working: Server-side: - Added missing discovery_method field to fallback DiscoveredDevice objects in equipment_manager.py - This was causing 500 Internal Server Error when discovery_manager wasn't available and fallback VISA scan was used Client-side: - Fixed scoping error in equipment_panel.py exception handler - Lambda was trying to access 'e' from outer scope after it expired - Now captures error message in closure variable before lambda The server was returning 500 because DiscoveredDevice requires discovery_method as a non-optional field, but the fallback code wasn't providing it.
Fixed Pydantic validation error in /api/equipment/discover endpoint.
FastAPI was unable to serialize DiscoveredDevice objects directly in
the response model.
Changes:
- Removed response_model=DiscoverDevicesResponse from /discover endpoint
- Convert DiscoveredDevice objects to dicts using model_dump()
- Return plain dict response: {"devices": [dict, dict, ...]}
This fixes the 500 Internal Server Error with validation errors:
"Input should be a valid dictionary or instance of DiscoveredDevice"
The client already expects dict objects, so this change is compatible.
- Extract USB VID:PID from serial port devices via sysfs - Check USB hardware database for both USB and ASRL (serial) interfaces - Return serial devices even if they don't respond to *IDN? (proprietary protocols) - Added BK 1685B serial variant (VID:PID 2ec7:168b) - Improved Silicon Labs CP210x detection with B&K device hints - Mark unidentified serial devices as AVAILABLE with lower confidence This fixes discovery of BK 1685B power supply which uses Silicon Labs USB-to-UART bridge and doesn't respond to standard SCPI *IDN? queries.
- Log all VISA resources found with their full resource strings - Log which interface type each resource is being processed as - Log sysfs path attempts when looking up USB IDs for serial ports - Warn when resources are filtered out or serial port USB IDs can't be found - Log when resources are skipped due to disabled interface types This will help diagnose why BK 1685B is not being discovered.
The DiscoveredDevice model already has default_factory=datetime.now for discovered_at and last_seen fields. Explicitly passing datetime.now() in the constructor was causing scoping issues in async context. Let Pydantic handle timestamp generation via default_factory instead.
- Log when serial (ASRL) devices start processing - Log USB hardware DB lookup results for serial devices - Log when generic USB-to-Serial chip is found - Log final device status before returning (manufacturer, model, status, confidence) This will help diagnose why ASRL/dev/ttyUSB0 (BK 1685B) is being filtered out.
Show whether serial devices are being skipped due to config or actually being processed. Logs will show either: -⚠️ Skipping ASRL resource (DISABLED in config) - ✓ Processing ASRL (serial) device This will tell us definitively why the BK 1685B at ASRL/dev/ttyUSB0 is being filtered out of discovery results.
Serial scanning was disabled by default (scan_serial=False), causing devices like the BK 1685B that use USB-to-serial bridges to be skipped during auto- discovery at startup. Changed default to scan_serial=True so serial/ASRL devices are discovered automatically along with USB and TCP/IP devices. This fixes the issue where BK 1685B was showing in lsusb but not in LabLink device discovery.
- Disable background auto-discovery (enable_auto_discovery=False) to avoid interference with active measurements - Increase VISA scan interval from 30s to 300s (5 min) - Increase mDNS scan interval from 60s to 600s (10 min) - Discovery still runs once at startup and on manual user request - Reduces CPU/USB overhead and prevents device query conflicts
The discovery system needs access to sysfs to extract USB VID:PID from serial devices (ASRL resources like /dev/ttyUSB0). The code in usb_hardware_db.py reads from paths like: /sys/class/tty/ttyUSB0/device/../../idVendor /sys/class/tty/ttyUSB0/device/../../idProduct Without this mount, serial devices like the BK 1685B (which uses a Silicon Labs CP210x USB-to-serial bridge) cannot be automatically identified from their USB hardware IDs. Changes: - Add /sys:/sys:ro volume mount to lablink-server in docker-compose.yml - Mount as read-only for security This fix enables automatic identification of serial-based devices like the BK 1685B power supply.
CRITICAL BUG FIX: The discovery_scan_serial default was set to False in server/config/settings.py, overriding the True default we set in server/discovery/models.py. The Settings class values take precedence because main.py explicitly passes settings.discovery_scan_serial to DiscoveryConfig(), bypassing the model's default values. This was causing serial devices like BK 1685B to be filtered out even after we "fixed" the issue in models.py. Changes: - discovery_scan_serial: False → True - enable_auto_discovery: True → False (performance optimization) - mdns_scan_interval_sec: 60 → 600 (10 minutes) - visa_scan_interval_sec: 30 → 300 (5 minutes) All settings now match the values in discovery/models.py. This fix is required for BK 1685B and other USB-to-serial devices to appear in discovery results.
X9X0
added a commit
that referenced
this pull request
Dec 7, 2025
…ecture ## Summary Unified version management across all components (server, client, launcher, Docker) using a single VERSION file as the source of truth. Updated to v1.2.0 to accurately reflect work completed since v1.0.0 (30+ PRs merged). ## Version System Changes ### Unified to v1.2.0 - Analyzed git history from v1.0.0 through current main - Determined v1.2.0 accurately represents features and fixes delivered - All components now read from single VERSION file ### Components Updated - VERSION file: 0.28.0 → 1.2.0 - README badge: 1.0.1 → 1.2.0 - Server: Now reads VERSION (already implemented) - Client: Added dynamic VERSION reading at startup - Launcher: Added __version__ variable from VERSION - Docker images: Labels updated to 1.2.0 - Copyright: Updated to © 2025 (project start year) ## CHANGELOG Updates Added comprehensive release notes for missing versions: ### v1.2.0 (2025-12-06) - Server update system with stable/development modes (#114, #118, #119) - Smart branch filtering and UI consolidation (#120) - Enhanced dropdown visibility - Multiple bug fixes (#105, #106, #108, #121) ### v1.0.1 (2025-11-28) - Equipment control panel (#104) - GUI system launcher with diagnostics (#70-74) - Raspberry Pi image builder (#75-76) - Waveform analysis tools (#79) - Automated test sequence builder (#80) - Remote firmware update (#81) - Equipment diagnostics system (#84-87) - WebSocket integration completion (#77) ## Automation & Documentation ### Created scripts/bump_version.py Automated version bumping tool with: - Support for major/minor/patch increments - Automatic VERSION file updates - CHANGELOG.md section generation - Git commit and tag creation - Dry-run mode for testing Usage: python scripts/bump_version.py patch # 1.2.0 → 1.2.1 python scripts/bump_version.py minor # 1.2.0 → 1.3.0 python scripts/bump_version.py major # 1.2.0 → 2.0.0 ### Created docs/VERSIONING.md Complete versioning system documentation covering: - Single-source architecture - Semantic versioning guidelines - Automated bumping procedures - Manual update processes - Troubleshooting guide - Best practices ## Files Modified Core Version Files: - VERSION (0.28.0 → 1.2.0) - CHANGELOG.md (added v1.0.1 and v1.2.0 entries) - README.md (badge updated to 1.2.0) Component Updates: - client/main.py (dynamic VERSION reading) - lablink.py (added __version__ from VERSION) - docker/Dockerfile.server (label 1.2.0) - docker/Dockerfile.web (label 1.2.0) Copyright Updates (© 2025): - docs/USER_GUIDE.md - client/ui/main_window.py New Files: + scripts/bump_version.py (version management tool) + docs/VERSIONING.md (complete documentation) ## Benefits ✅ Single source of truth for version (VERSION file) ✅ Consistent versioning across all components ✅ Accurate version history in CHANGELOG ✅ Automated version bumping workflow ✅ Complete documentation for future updates ✅ Git-tagged releases (v1.2.0) ## Testing Verified: - VERSION file: 1.2.0 ✓ - Server reads VERSION correctly ✓ - Client would read VERSION at startup ✓ - Launcher reads VERSION correctly ✓ - bump_version.py dry-run works ✓ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Overview
Fixes multiple device discovery issues and adds automatic hardware identification based on USB VID:PID. Previously, only the first device was detected; now all connected devices (USB, serial, TCPIP) are discovered in parallel.
Key Features
1. Multiple Device Discovery ✅
2. USB Hardware Identification Database 🆔
3. Serial Device Support (ASRL) 📡
/sys/class/tty/via sysfs/sys:/sys:rofor USB ID extraction4. Auto-Selection in Connection Dialog 🎯
5. Performance Optimization ⚡
6. Protocol Fixes 🔧
Technical Changes
New Files
server/discovery/usb_hardware_db.py- USB VID:PID to device model mappingModified Files
server/discovery/visa_scanner.py- Async scanning, parallel processing, serial device supportserver/discovery/models.py- Updated defaults for serial scanning and intervalsserver/config/settings.py- Fixed defaults to enable serial device discoveryserver/equipment/bk_power_supply.py- BK 9205B now uses SCPI instead of proprietary protocolserver/main.py- Added progress callbacks for WebSocket streamingclient/ui/connect_dialog.py- Auto-selection based on USB hardware IDdocker-compose.yml- Mount/sysfor serial device USB ID extractionBug Fixes
discovery_methodfield in fallback devicesTesting
Tested with:
Breaking Changes
None. All changes are backward compatible.
Configuration Changes
Default values changed (can be overridden via environment variables or config file):
enable_auto_discovery:True→Falsemdns_scan_interval_sec:60→600visa_scan_interval_sec:30→300discovery_scan_serial:False→TrueDeployment Notes
After merging, rebuild Docker container to apply changes: