0
# Device Discovery and Management
1
2
Device discovery and management provides functions to find, enumerate, and manage USB devices connected to the system. This includes listing all devices, finding specific devices by identifiers, and accessing device metadata.
3
4
## Capabilities
5
6
### Device Enumeration
7
8
Get a list of all USB devices currently attached to the system.
9
10
```typescript { .api }
11
/**
12
* Return a list of Device objects for the USB devices attached to the system
13
* @returns Array of Device objects representing connected USB devices
14
*/
15
function getDeviceList(): Device[];
16
```
17
18
**Usage Examples:**
19
20
```typescript
21
import { getDeviceList } from 'usb';
22
23
// Get all connected USB devices
24
const devices = getDeviceList();
25
console.log(`Found ${devices.length} USB devices`);
26
27
// Iterate through devices
28
devices.forEach((device, index) => {
29
console.log(`Device ${index}:`);
30
console.log(` Vendor ID: 0x${device.deviceDescriptor.idVendor.toString(16).padStart(4, '0')}`);
31
console.log(` Product ID: 0x${device.deviceDescriptor.idProduct.toString(16).padStart(4, '0')}`);
32
console.log(` Bus: ${device.busNumber}, Address: ${device.deviceAddress}`);
33
});
34
```
35
36
### Device Search by IDs
37
38
Find a specific device using vendor ID and product ID.
39
40
```typescript { .api }
41
/**
42
* Convenience method to get the first device with the specified VID and PID
43
* @param vid - USB vendor ID
44
* @param pid - USB product ID
45
* @returns Device object if found, undefined otherwise
46
*/
47
function findByIds(vid: number, pid: number): Device | undefined;
48
```
49
50
**Usage Examples:**
51
52
```typescript
53
import { findByIds } from 'usb';
54
55
// Find Arduino Uno (example IDs)
56
const arduino = findByIds(0x2341, 0x0043);
57
if (arduino) {
58
console.log('Arduino Uno found!');
59
console.log(`Bus: ${arduino.busNumber}, Address: ${arduino.deviceAddress}`);
60
} else {
61
console.log('Arduino Uno not connected');
62
}
63
64
// Find device by hex IDs
65
const customDevice = findByIds(0x1234, 0xABCD);
66
```
67
68
### Device Search by Serial Number
69
70
Find a device using its serial number string.
71
72
```typescript { .api }
73
/**
74
* Convenience method to get the device with the specified serial number
75
* @param serialNumber - Device serial number string
76
* @returns Promise resolving to Device if found, undefined otherwise
77
*/
78
function findBySerialNumber(serialNumber: string): Promise<Device | undefined>;
79
```
80
81
**Usage Examples:**
82
83
```typescript
84
import { findBySerialNumber } from 'usb';
85
86
// Find device by serial number
87
const device = await findBySerialNumber('ABC123DEF456');
88
if (device) {
89
console.log('Device found by serial number');
90
console.log(`Vendor: 0x${device.deviceDescriptor.idVendor.toString(16)}`);
91
} else {
92
console.log('Device with serial number not found');
93
}
94
95
// Handle with try-catch
96
try {
97
const myDevice = await findBySerialNumber('MY_DEVICE_SERIAL');
98
if (myDevice) {
99
// Use device
100
myDevice.open();
101
// ... perform operations
102
myDevice.close();
103
}
104
} catch (error) {
105
console.error('Error searching for device:', error);
106
}
107
```
108
109
### Device Object Properties
110
111
Each Device object contains metadata and properties for USB device access.
112
113
```typescript { .api }
114
/**
115
* USB Device class with properties and methods
116
*/
117
interface Device {
118
/** Integer USB bus number */
119
busNumber: number;
120
121
/** Integer USB device address */
122
deviceAddress: number;
123
124
/** Array containing USB device port numbers, or undefined if not supported */
125
portNumbers: number[];
126
127
/** Object with properties for the fields of the device descriptor */
128
deviceDescriptor: DeviceDescriptor;
129
130
/** List of Interface objects for the interfaces of the default configuration */
131
interfaces?: Interface[];
132
133
/** Timeout in milliseconds to use for control transfers */
134
timeout: number;
135
136
/** Object with properties for the fields of the active configuration descriptor */
137
readonly configDescriptor?: ConfigDescriptor;
138
139
/** Contains all config descriptors of the device */
140
readonly allConfigDescriptors: ConfigDescriptor[];
141
142
/** Contains the parent of the device, such as a hub. If no parent, this is null */
143
readonly parent: Device;
144
}
145
```
146
147
**Usage Examples:**
148
149
```typescript
150
import { getDeviceList } from 'usb';
151
152
const devices = getDeviceList();
153
const device = devices[0];
154
155
// Access device properties
156
console.log('Device Info:');
157
console.log(` Bus Number: ${device.busNumber}`);
158
console.log(` Device Address: ${device.deviceAddress}`);
159
console.log(` Port Numbers: [${device.portNumbers.join(', ')}]`);
160
161
// Access device descriptor
162
const desc = device.deviceDescriptor;
163
console.log(` Vendor ID: 0x${desc.idVendor.toString(16)}`);
164
console.log(` Product ID: 0x${desc.idProduct.toString(16)}`);
165
console.log(` Device Class: ${desc.bDeviceClass}`);
166
console.log(` USB Version: ${desc.bcdUSB.toString(16)}`);
167
168
// Check if device has parent (hub)
169
if (device.parent) {
170
console.log(` Connected through hub: Bus ${device.parent.busNumber}`);
171
}
172
173
// Access configuration information
174
if (device.configDescriptor) {
175
console.log(` Configuration Value: ${device.configDescriptor.bConfigurationValue}`);
176
console.log(` Number of Interfaces: ${device.configDescriptor.bNumInterfaces}`);
177
console.log(` Max Power: ${device.configDescriptor.bMaxPower * 2}mA`);
178
}
179
```
180
181
### Device Filtering and Selection
182
183
Filter devices based on various criteria.
184
185
**Usage Examples:**
186
187
```typescript
188
import { getDeviceList } from 'usb';
189
190
const devices = getDeviceList();
191
192
// Filter by device class (e.g., HID devices)
193
const hidDevices = devices.filter(device =>
194
device.deviceDescriptor.bDeviceClass === 3 // HID class
195
);
196
197
// Filter by manufacturer (requires opening device to get string)
198
const filterByManufacturer = async (manufacturerName: string) => {
199
const matchingDevices = [];
200
201
for (const device of devices) {
202
try {
203
device.open();
204
if (device.deviceDescriptor.iManufacturer > 0) {
205
device.getStringDescriptor(device.deviceDescriptor.iManufacturer, (error, value) => {
206
if (!error && value === manufacturerName) {
207
matchingDevices.push(device);
208
}
209
});
210
}
211
device.close();
212
} catch (error) {
213
// Skip devices that can't be opened
214
continue;
215
}
216
}
217
218
return matchingDevices;
219
};
220
221
// Filter by vendor ID range
222
const vendorDevices = devices.filter(device =>
223
device.deviceDescriptor.idVendor >= 0x1000 &&
224
device.deviceDescriptor.idVendor < 0x2000
225
);
226
227
// Find devices with specific interface class
228
const devicesWithAudioInterface = devices.filter(device => {
229
if (!device.configDescriptor) return false;
230
231
return device.configDescriptor.interfaces.some(interfaceGroup =>
232
interfaceGroup.some(altSetting => altSetting.bInterfaceClass === 1) // Audio class
233
);
234
});
235
```
236
237
### Utility Functions
238
239
Additional utility functions for USB management and debugging.
240
241
```typescript { .api }
242
/**
243
* Set the libusb debug level (between 0 and 4)
244
* Higher levels provide more verbose logging
245
* @param level - Debug level (0=none, 1=error, 2=warning, 3=info, 4=debug)
246
*/
247
function setDebugLevel(level: number): void;
248
249
/**
250
* Use USBDK Backend (Windows only)
251
* On Windows, use the USBDK backend of libusb instead of WinUSB
252
*/
253
function useUsbDkBackend(): void;
254
255
/**
256
* Restore (re-reference) the hotplug events unreferenced by unrefHotplugEvents()
257
* Hotplug events are referenced by default
258
*/
259
function refHotplugEvents(): void;
260
261
/**
262
* Unreference the hotplug events from the event loop
263
* Allows the process to exit even when listening for attach and detach events
264
*/
265
function unrefHotplugEvents(): void;
266
```
267
268
**Usage Examples:**
269
270
```typescript
271
import { setDebugLevel, useUsbDkBackend, refHotplugEvents, unrefHotplugEvents, usb } from 'usb';
272
273
// Enable debug logging
274
console.log('Enabling USB debug logging...');
275
setDebugLevel(3); // Info level logging
276
277
// On Windows, optionally use USBDK backend
278
if (process.platform === 'win32') {
279
console.log('Using USBDK backend on Windows');
280
useUsbDkBackend();
281
}
282
283
// Set up device monitoring with proper cleanup
284
function setupDeviceMonitoring() {
285
let deviceCount = 0;
286
287
// Set up event handlers
288
usb.on('attach', (device) => {
289
deviceCount++;
290
console.log(`Device attached (${deviceCount} total):`, {
291
vendorId: `0x${device.deviceDescriptor.idVendor.toString(16)}`,
292
productId: `0x${device.deviceDescriptor.idProduct.toString(16)}`,
293
busNumber: device.busNumber,
294
deviceAddress: device.deviceAddress
295
});
296
});
297
298
usb.on('detach', (device) => {
299
deviceCount--;
300
console.log(`Device detached (${deviceCount} total):`, {
301
vendorId: `0x${device.deviceDescriptor.idVendor.toString(16)}`,
302
productId: `0x${device.deviceDescriptor.idProduct.toString(16)}`
303
});
304
});
305
306
console.log('Device monitoring started');
307
console.log('Note: Process will not exit due to hotplug event listeners');
308
309
// Allow process to exit after some time
310
setTimeout(() => {
311
console.log('Unreferencing hotplug events to allow process exit...');
312
unrefHotplugEvents();
313
314
// Process can now exit naturally
315
console.log('Process can now exit. Device monitoring continues.');
316
317
// Later, if you want to prevent exit again
318
setTimeout(() => {
319
console.log('Re-referencing hotplug events...');
320
refHotplugEvents();
321
console.log('Process will now stay alive for hotplug events');
322
323
// Clean up after demo
324
setTimeout(() => {
325
console.log('Demo complete, stopping monitoring...');
326
usb.removeAllListeners('attach');
327
usb.removeAllListeners('detach');
328
}, 5000);
329
330
}, 3000);
331
}, 10000);
332
}
333
334
// Debug level examples
335
function demonstrateDebugLevels() {
336
console.log('Testing different debug levels:');
337
338
// Test each debug level
339
[0, 1, 2, 3, 4].forEach((level, index) => {
340
setTimeout(() => {
341
console.log(`\n--- Setting debug level to ${level} ---`);
342
setDebugLevel(level);
343
344
// Perform some USB operations to generate debug output
345
const devices = getDeviceList();
346
console.log(`Found ${devices.length} devices at debug level ${level}`);
347
348
if (devices.length > 0) {
349
const device = devices[0];
350
console.log(`First device: VID:PID = ${device.deviceDescriptor.idVendor.toString(16)}:${device.deviceDescriptor.idProduct.toString(16)}`);
351
}
352
}, index * 2000);
353
});
354
}
355
356
// Windows USBDK backend example
357
function demonstrateUsbDkBackend() {
358
if (process.platform !== 'win32') {
359
console.log('USBDK backend is only available on Windows');
360
return;
361
}
362
363
console.log('Testing USBDK backend on Windows...');
364
365
// Get devices with default WinUSB backend
366
const devicesWinUsb = getDeviceList();
367
console.log(`Devices found with WinUSB: ${devicesWinUsb.length}`);
368
369
// Switch to USBDK backend
370
useUsbDkBackend();
371
console.log('Switched to USBDK backend');
372
373
// Get devices with USBDK backend
374
const devicesUsbDk = getDeviceList();
375
console.log(`Devices found with USBDK: ${devicesUsbDk.length}`);
376
377
// Compare results
378
if (devicesUsbDk.length !== devicesWinUsb.length) {
379
console.log('Different device counts detected between backends');
380
console.log('This might indicate driver compatibility differences');
381
} else {
382
console.log('Same device count with both backends');
383
}
384
}
385
386
// Graceful shutdown pattern
387
function setupGracefulShutdown() {
388
let shutdownInProgress = false;
389
390
// Set up device monitoring
391
usb.on('attach', (device) => {
392
if (!shutdownInProgress) {
393
console.log('Device attached:', device.deviceDescriptor.idVendor.toString(16));
394
}
395
});
396
397
usb.on('detach', (device) => {
398
if (!shutdownInProgress) {
399
console.log('Device detached:', device.deviceDescriptor.idVendor.toString(16));
400
}
401
});
402
403
// Handle shutdown signals
404
const gracefulShutdown = (signal: string) => {
405
if (shutdownInProgress) return;
406
shutdownInProgress = true;
407
408
console.log(`\nReceived ${signal}, shutting down gracefully...`);
409
410
// Remove all USB event listeners
411
usb.removeAllListeners('attach');
412
usb.removeAllListeners('detach');
413
414
// Unreference hotplug events to allow exit
415
unrefHotplugEvents();
416
417
console.log('USB monitoring stopped');
418
process.exit(0);
419
};
420
421
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
422
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
423
424
console.log('Graceful shutdown handlers installed');
425
console.log('Press Ctrl+C to shutdown gracefully');
426
}
427
428
// Run demonstrations
429
if (require.main === module) {
430
console.log('USB Utility Functions Demo');
431
console.log('===========================\n');
432
433
demonstrateDebugLevels();
434
435
setTimeout(() => {
436
demonstrateUsbDkBackend();
437
}, 12000);
438
439
setTimeout(() => {
440
setupDeviceMonitoring();
441
}, 15000);
442
443
setTimeout(() => {
444
setupGracefulShutdown();
445
}, 18000);
446
}
447
```