ENLIGHTEN
Cross-platform desktop GUI for Wasatch Photonics spectrometers
Loading...
Searching...
No Matches
wasatch.DeviceID.DeviceID Class Reference

Represents a persistent unique identifier for a spectrometer device (USB, BLE, TCP, whatever) which should remain valid for connected devices in spite of hotplug events around them. More...

Public Member Functions

 __eq__ (self, other)
 
 __hash__ (self)
 
 __init__ (self, device=None, label=None, directory=None, device_type=None, overrides=None, spectra_options=None, bleak_ble_device=None)
 Instantiates a DeviceID object from either a usb.device or an existing device_id string representation.
 
 __lt__ (self, other)
 
 __ne__ (self, other)
 
 __repr__ (self)
 Whether a given device is USB, FILE or otherwise, render the DeviceID as a string containing all the relevant bits neccessary to reconstruct the object into a parsed structure while providing a concise, readable and hashable unique key.
 
 determine_bus_and_address (self, device)
 This is for USB devices.
 
 get_pid_hex (self)
 
 get_vid_hex (self)
 
 is_andor (self)
 
 is_ble (self)
 
 is_file (self)
 
 is_ids_peak (self)
 
 is_mock (self)
 
 is_tcp (self)
 
 is_usb (self)
 
 to_dict (self)
 So that dict() can return a clean dict without any "private" attributes (which we should probably __prefix or something)
 

Public Attributes

int address = None
 
 bleak_ble_device = bleak_ble_device
 
 bleak_device = None
 
int bus = None
 
 device_type = device_type
 
 directory = None
 
 name = None
 
 overrides = overrides
 
int pid = None
 
 port = int(tok[2])
 
 product = device.dev.product.rstrip('\x00')
 
 serial_number = None
 
 spectra_options = spectra_options
 
str type = None
 
int vid = None
 

Detailed Description

Represents a persistent unique identifier for a spectrometer device (USB, BLE, TCP, whatever) which should remain valid for connected devices in spite of hotplug events around them.

Statement of the Problem

Assume we have four WP-785 spectrometers: A, B, C and D. We connect A, B and C, then launch ENLIGHTEN. A is the first on the USB chain, so in a positional listing A would be #1, B is #2, C is #3.

Now we unplug B. That leaves us with A (1) and C (3). Except that, positionally C is really now 2. Now we plug in D. Is D now 4th on the list, or did it slip into the unoccupied 2 slot? Or was C internally moved back to 2, and now D is 3, but C also thinks it's 3?

One solution would be to UPDATE the positional order in a master list on unplug events (detecting B's removal, and changing C from 3 to 2). ENLIGHTEN could do that, but note that it would therefore be a client- side operation, not within the driver itself. Or we could move the multi-process "Controller" ownership of the several WasatchDeviceWrapper processes into Wasatch.PY, such that Wasatch.PY provided a single-object Facade. We could possibly achieve that by maintaining a list of all WasatchDeviceWrapper instances in a static WasatchDeviceWrapper attribute (or WasatchDeviceWrappers or WasatchDeviceWrapperFactory as it were). But either would require some additional refactoring that I'm not diving into right now, although it seems an improved and reasonable architecture.

Or maybe we don't need a DeviceID at all, and just track "the WasatchDeviceWrapper associated with this serial number", and simply assume that all spectrometers will have a unique spectrometer (or be assigned one at connection). So maybe my attempt to generate a UNIQUE and PERSISTENT DeviceID from the usb.device object is quixotic and unnecessary. That's probably the case.

Part of what drove this is that historically ENLIGHTEN supported a bus_order command-line argument which explicitly referenced spectrometers by their position on the USB bus. However, we're now trying to support hotplug use-cases, meaning that position is no longer reliable. But since we had a legacy expectation of being able to explicitly identify devices at the bus level, I'm trying to retain that capability by habit. It probably is no longer needed, and we can probably replace the old –bus-order option with –serial-number instead.

More to the point, the current architecture is such that ENLIGHTEN calls WasatchBus to detect hotplug events, and then ENLIGHTEN instantiates a new WasatchDeviceWrapper to support the new bus device. That means there really ought to be a way to pass the "id" of the device, which was detected by WasatchBus, down into WasatchDeviceWrapper (and hence WasatchDevice and FeatureIdentificationDevice) to be re-instantiated. I don't trust position, I'm not sure how to confirm "claim state" (ASSUMING we wanted the "first eligible unclaimed") , "serial number" seems heavy-handed (and would still require a way to deliberately "skip" already-connected devices, again requiring some sort of key).

ALSO we want to eventually support BLE (which has unique UUID), and perhaps TCP/IP (which has IP addresses)...basically I think objects on a "bus" should be uniquely identifiable and addressable from their bus address, WITHOUT making guesses based on position or ordering or claim-state or anything like that.

So yeah, I think this is useful.

USB
  • .vid and .pid are stored as ints
BLE
  • populates .bleak_ble_device (bleak.BLEDevice from BleakScanner)
  • populates .serial_number

Adding the non-pickleable .bleak_ble_device kind of defeats some of the original intent of this class, as ideally serialized (stringified) DeviceIDs were intended to be passable between processes and "re-instantiated" on the receiving end.

However, now that ENLIGHTEN is multi-threaded (instead of multi-process), we don't have to worry about that, and it seems convenient to simply stash a handle to the Bleak Device directly in the DeviceID, where it can be passed from DeviceFinderBLE to BLEManager to WasatchDeviceWrapper/WrapperWorker to BLEDevice.

Serial number is tracked in the DeviceID (rather than DiscoveredBLEDevice) because the current DeviceID architecture is to dynamically generate its stringified form, based on internal native types.

See also
BLEDevice for consolidated BLE docs
TCP
  • uses .address and .port

Constructor & Destructor Documentation

◆ __init__()

wasatch.DeviceID.DeviceID.__init__ ( self,
device = None,
label = None,
directory = None,
device_type = None,
overrides = None,
spectra_options = None,
bleak_ble_device = None )

Instantiates a DeviceID object from either a usb.device or an existing device_id string representation.

Parameters
deviceis a usb.device from pyusb
directoryis used with FILE spectrometers
device_typethis seems to be currently exclusively used to distinguish between RealUSBDevice and MockUSBDevice (both extending AbstractUSBDevice).

Member Function Documentation

◆ __eq__()

wasatch.DeviceID.DeviceID.__eq__ ( self,
other )

◆ __hash__()

wasatch.DeviceID.DeviceID.__hash__ ( self)

◆ __lt__()

wasatch.DeviceID.DeviceID.__lt__ ( self,
other )

◆ __ne__()

wasatch.DeviceID.DeviceID.__ne__ ( self,
other )

◆ __repr__()

wasatch.DeviceID.DeviceID.__repr__ ( self)

Whether a given device is USB, FILE or otherwise, render the DeviceID as a string containing all the relevant bits neccessary to reconstruct the object into a parsed structure while providing a concise, readable and hashable unique key.

◆ determine_bus_and_address()

wasatch.DeviceID.DeviceID.determine_bus_and_address ( self,
device )

This is for USB devices.

It seems to work on tested platforms, but is not guaranteed by the protocol or library.

◆ get_pid_hex()

wasatch.DeviceID.DeviceID.get_pid_hex ( self)

◆ get_vid_hex()

wasatch.DeviceID.DeviceID.get_vid_hex ( self)

◆ is_andor()

wasatch.DeviceID.DeviceID.is_andor ( self)

◆ is_ble()

wasatch.DeviceID.DeviceID.is_ble ( self)

◆ is_file()

wasatch.DeviceID.DeviceID.is_file ( self)

◆ is_ids_peak()

wasatch.DeviceID.DeviceID.is_ids_peak ( self)

◆ is_mock()

wasatch.DeviceID.DeviceID.is_mock ( self)

◆ is_tcp()

wasatch.DeviceID.DeviceID.is_tcp ( self)

◆ is_usb()

wasatch.DeviceID.DeviceID.is_usb ( self)

◆ to_dict()

wasatch.DeviceID.DeviceID.to_dict ( self)

So that dict() can return a clean dict without any "private" attributes (which we should probably __prefix or something)

Member Data Documentation

◆ address

int wasatch.DeviceID.DeviceID.address = None

◆ bleak_ble_device

wasatch.DeviceID.DeviceID.bleak_ble_device = bleak_ble_device

◆ bleak_device

wasatch.DeviceID.DeviceID.bleak_device = None

◆ bus

int wasatch.DeviceID.DeviceID.bus = None

◆ device_type

wasatch.DeviceID.DeviceID.device_type = device_type

◆ directory

wasatch.DeviceID.DeviceID.directory = None

◆ name

wasatch.DeviceID.DeviceID.name = None

◆ overrides

wasatch.DeviceID.DeviceID.overrides = overrides

◆ pid

int wasatch.DeviceID.DeviceID.pid = None

◆ port

wasatch.DeviceID.DeviceID.port = int(tok[2])

◆ product

wasatch.DeviceID.DeviceID.product = device.dev.product.rstrip('\x00')

◆ serial_number

wasatch.DeviceID.DeviceID.serial_number = None

◆ spectra_options

wasatch.DeviceID.DeviceID.spectra_options = spectra_options

◆ type

wasatch.DeviceID.DeviceID.type = None

◆ vid

int wasatch.DeviceID.DeviceID.vid = None

The documentation for this class was generated from the following file: