I’ve discovered another problem. USB device serial numbers aren’t reliably available on Windows. Neither the current implementation nor my “new one” gets it right.
Here is what’s called the “device path” in Windows for an Aeotec Gen-5 Z-wave stick I have.
\\?\usb#vid_0658&pid_0200#5&1c80a72c&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
The same basic information is available with slightly different formatting, e.g.
- symbolic name:
\??\USB#VID_0658&PID_0200#5&1c80a72c&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
- hardware ID:
USB\VID_0658&PID_0200&REV_0000
..and there are others like “instance ID” that’s just a variation of the same information in upper or lower case. The “device path” is the one that consistently has the most information from what I’ve found.
This is how the “old”/current implementation parses this device:
UsbSerialDeviceInformation [vendorId=0x0658, productId=0x0200, serialNumber=null, manufacturer=Sigma Designs, product=UZB, interfaceNumber=0x00, interfaceDescription=5&1c80a72c&0&2, serialPort=COM5, remote=false]
This is how my “new” implementation parses this device:
UsbSerialDeviceInformation [vendorId=0x0658, productId=0x0200, serialNumber=5&1c80a72c&0&2, manufacturer=Sigma Designs, product=UZB (COM5), interfaceNumber=0x00, interfaceDescription=5&1c80a72c&0&2, serialPort=COM5, remote=false]
The results are identical, except for the serial number. From what I can tell, the current implementation will never find a serial number, because it assumes a syntax that I don’t think exists (it’s impossible to be 100% sure of anything here). “My” implementation uses the “unique device ID” as the serial number, but this is where it gets difficult.
It isn’t exactly easy to get implementation details about closed source projects like Windows, so I’ve just had to try to pick up some information here and there. The consensus seems to be that this “ID” is guaranteed to be unique for that device on any given Windows installation, but it’s not guaranteed to match the actual device serial number. In fact, it often won’t be. Not all USB devices even have a serial number, and even if they do, it’s “up to Windows” whether that serial number will be used as the “unique ID” or not. It is in some cases, in which “my” implementation will get it right, but it doesn’t for any of my test devices. As far as I can tell, there’s absolutely no way to tell if the information we acquire is a genuine serial number or not. It also seems like it depends on the driver exactly how this ID is derived, so you might consistently get a real serial number for some drivers.
You can get the actual serial number from the device, but that requires opening the device and querying it for information. This procedure is driver-dependent, so it would have to be implemented for each potential driver we’d be interested in. “WinUSB” is a generic driver that is used for many devices, but that’s not something you can rely on to always be true. Even if you figure out the driver and use the correct approach to query that driver, there’s an exclusive lock on USB devices by default on Windows. So, only one process can “open” the device at any one time. That means that if any other software have the device open, OH would be blocked from doing this - and vice versa - if OH did this to read the serial number, it might block other applications from accessing the device. For all the complications and caveats, I consider querying the driver “unfit for purpose” here.
This might look completely different on Linux, maybe the device serial number is routinely available from the “sysfs” - I don’t know. After looking around in the /sys/devices/platform/ structure on openHABian, it seems like much of the “raw USB descriptor” is found in there, so the serial number found there would probably be genuine.
The question now is what to do with USB device serial numbers under Windows. I can’t find a reliable way to acquire them, but the “ID” I get should be a reliable identificator for that particular device on a given installation. Do we want to use that or not, given that it might not correspond to the actual device serial number? What exactly is it used for?
edit: The current implementation gets it wrong when a device have multiple interfaces, becauseit then parses the interface indication as the serial number, e.g MI_02.