devctrl.devices.device.Device#

class Device[source]#

Bases: ABC

Base class for all devices.

The hierarchy is as follow: Device is the base class for all the devices. Subclasses of Device are supposed to be base classes of a specific device type, for example TemperatureSensor. Subclasses of the device type classes are specific implementations of this device type, for example ModelXYZ9000. These classes handle all the communication with the actual device. The device type base class should define additional abstract methods like a get_temperature_C() method, which all device implementation classes must implement. That way, get_temperature_C() works regardless of which actual device is connected.

To make testing code easier, each device type should have a dummy implementation. This dummy device must implement all the necessary functions, but not connect to any physical device. Return values should have the correct data type, but in an ideal case should be chosen so that it is immediately clear that they are not valid data. For the example, get_temperature_C() could always return 0.

It is also possible to ‘hard-code’ devices see the add_device() method. The information for these devices is internally stored in _manual_devices of the Device base class, which makes it possible to add retrieve all manually added devices in list_devices() for a device type.

Every subclass must have a _CLASS_TYPE member which is either ‘base’, ‘implementation’ or ‘dummy’. If a subclass is also a subclass of DummyDevice, the _CLASS_TYPE will be automatically set to ‘dummy’.

Methods

add_device

Manually add a specific device.

allow_only_dummy_devices

connect

connect_device

This function should be overridden by device implementations only, and is not intended to be used directly.

connect_dummy

Connect an instance of the device's dummy implementation

get_base_classes

Return a flat dictionary of all base classes below this class :param recurse: If True, recursively search for base classes :return: dict of {class name: class}

get_device_name

get_device_type_name

get_status

Query the status of the device and return a string describing errors.

is_connected

Query whether the device is (still) connected

list_devices

Get a list of all devices for this type.

_CLASS_TYPE = ''#
__abstractmethods__ = frozenset({'__repr__', 'connect_device', 'get_device_type_name', 'is_connected'})#
__annotations__ = {'_manual_devices': list[str]}#
__dict__ = mappingproxy({'__module__': 'devctrl.devices.device', '__firstlineno__': 52, '__annotations__': {'_manual_devices': list[str]}, '__doc__': "\nBase class for all devices.\n\nThe hierarchy is as follow:\n`Device` is the base class for all the devices.\nSubclasses of `Device` are supposed to be base classes of a specific device type, for example `TemperatureSensor`. \nSubclasses of the device type classes are specific implementations of this device type, for example `ModelXYZ9000`.\nThese classes handle all the communication with the actual device.\nThe device type base class should define additional abstract methods like a `get_temperature_C()` method, which all device implementation classes must implement.\nThat way, `get_temperature_C()` works regardless of which actual device is connected.\n\nTo make testing code easier, each device type should have a dummy implementation. \nThis dummy device must implement all the necessary functions, but not connect to any physical device.\nReturn values should have the correct data type, but in an ideal case should be chosen so that it is immediately clear that they are not valid data.\nFor the example, `get_temperature_C()` could always return `0`.\n\nIt is also possible to 'hard-code' devices see the `add_device()` method. \nThe information for these devices is internally stored in _manual_devices of the Device base class, which makes it possible to add retrieve all manually added devices in `list_devices()` for a device type.\n\nEvery subclass must have a _CLASS_TYPE member which is either 'base', 'implementation' or 'dummy'. If a subclass is also a subclass of DummyDevice, the _CLASS_TYPE will be automatically set to 'dummy'.\n", 'get_status': <function Device.get_status>, 'is_connected': <function Device.is_connected>, '__repr__': <function Device.__repr__>, 'get_device_name': <classmethod(<function Device.get_device_name>)>, 'get_base_classes': <classmethod(<function Device.get_base_classes>)>, 'get_device_type_name': <classmethod(<function Device.get_device_type_name>)>, 'list_devices': <classmethod(<function Device.list_devices>)>, 'connect': <classmethod(<function Device.connect>)>, 'connect_dummy': <classmethod(<function Device.connect_dummy>)>, 'connect_device': <classmethod(<function Device.connect_device>)>, '_enumerate_devices': <classmethod(<function Device._enumerate_devices>)>, 'add_device': <classmethod(<function Device.add_device>)>, '_dummies_only': False, 'allow_only_dummy_devices': <staticmethod(<function Device.allow_only_dummy_devices>)>, '_CLASS_TYPE': '', '_manual_devices': [], '_children': {'DummyDevice': <class 'devctrl.devices.device.DummyDevice'>, 'Amplifier': <class 'devctrl.devices.amplifier.base.Amplifier'>, 'Lamp': <class 'devctrl.devices.lamp.base.Lamp'>, 'Laser': <class 'devctrl.devices.laser.base.Laser'>, 'LedController': <class 'devctrl.devices.led_controller.base.LedController'>, 'LockInAmp': <class 'devctrl.devices.lock_in.base.LockInAmp'>, 'Monochromator': <class 'devctrl.devices.monochromator.base.Monochromator'>, 'Oscilloscope': <class 'devctrl.devices.oscilloscope.base.Oscilloscope'>, 'PressureSensor': <class 'devctrl.devices.pressure_sensor.base.PressureSensor'>, 'Shutter': <class 'devctrl.devices.shutter.base.Shutter'>, 'Switch': <class 'devctrl.devices.switch.base.Switch'>, 'TemperatureController': <class 'devctrl.devices.temperature_controller.base.TemperatureController'>, 'TemperatureSensor': <class 'devctrl.devices.temperature_sensor.base.TemperatureSensor'>, 'Voltmeter': <class 'devctrl.devices.voltmeter.base.Voltmeter'>, 'Wheel': <class 'devctrl.devices.wheel.base.Wheel'>}, '__static_attributes__': (), '__dict__': <attribute '__dict__' of 'Device' objects>, '__weakref__': <attribute '__weakref__' of 'Device' objects>, '__abstractmethods__': frozenset({'__repr__', 'is_connected', 'get_device_type_name', 'connect_device'}), '_abc_impl': <_abc._abc_data object>})#
__firstlineno__ = 52#
__module__ = 'devctrl.devices.device'#
abstractmethod __repr__() str[source]#
Returns:

The name of the device. If applicable, this should include serial port, GPIB address, etc.

__slots__ = ()#
__static_attributes__ = ()#
__weakref__#

list of weak references to the object

_abc_impl = <_abc._abc_data object>#
_children = {'Amplifier': <class 'devctrl.devices.amplifier.base.Amplifier'>, 'DummyDevice': <class 'devctrl.devices.device.DummyDevice'>, 'Lamp': <class 'devctrl.devices.lamp.base.Lamp'>, 'Laser': <class 'devctrl.devices.laser.base.Laser'>, 'LedController': <class 'devctrl.devices.led_controller.base.LedController'>, 'LockInAmp': <class 'devctrl.devices.lock_in.base.LockInAmp'>, 'Monochromator': <class 'devctrl.devices.monochromator.base.Monochromator'>, 'Oscilloscope': <class 'devctrl.devices.oscilloscope.base.Oscilloscope'>, 'PressureSensor': <class 'devctrl.devices.pressure_sensor.base.PressureSensor'>, 'Shutter': <class 'devctrl.devices.shutter.base.Shutter'>, 'Switch': <class 'devctrl.devices.switch.base.Switch'>, 'TemperatureController': <class 'devctrl.devices.temperature_controller.base.TemperatureController'>, 'TemperatureSensor': <class 'devctrl.devices.temperature_sensor.base.TemperatureSensor'>, 'Voltmeter': <class 'devctrl.devices.voltmeter.base.Voltmeter'>, 'Wheel': <class 'devctrl.devices.wheel.base.Wheel'>}#
_dummies_only = False#
classmethod _enumerate_devices() list[str][source]#

This function should be overridden by device implementations only, and is not intended to be used directly. Instead, use list_devices() to get a list of devices. Use enumerate_devices only directly when you only want to list devices of one specific implementation, i.e., only SR830 Lock-In: SR830._enumerate_devices() :param class_name: The name of the device class

_manual_devices: list[str] = []#
classmethod add_device(connect_info)[source]#

Manually add a specific device. The device will show up when list_devices() is called for the device type. Call this from the device class implementation, e.g. use ModelXYZ9000.add_device(‘GPIB:1234:5678’) to add a specific device with a fixed GPIB address. This is useful when automatic discovery is undesired/impossible, either because it is not implemented or it disturbs other devices which can’t handle a identification request. :param cls: The device implementation class :param connect_info: A string argument that is passed to the connect() method of the device implementation, when the device is being connected.

static allow_only_dummy_devices()[source]#
classmethod connect(device_type_name: str, device_name: str | None, **kwargs) Device[source]#
Parameters:
  • device_type_name – The name of the device class

  • device_name – The name of the device class

abstractmethod classmethod connect_device(device_name: str) Device[source]#

This function should be overridden by device implementations only, and is not intended to be used directly. Instead, use list_devices() to get a list of devices, and pass the selected device type and name to connect() :param device_name: The name of the device class

classmethod connect_dummy(**kwargs) Device[source]#

Connect an instance of the device’s dummy implementation

classmethod get_base_classes(recurse=True) dict[str, type[Device]][source]#

Return a flat dictionary of all base classes below this class :param recurse: If True, recursively search for base classes :return: dict of {class name: class}

classmethod get_device_name() str[source]#
Returns:

The specific type name of the device, e.g., SR830 or Keithly2600

abstractmethod classmethod get_device_type_name() str[source]#
Returns:

The general type name of the device, e.g., Lock-In Amplifier or Voltmeter

get_status() str[source]#

Query the status of the device and return a string describing errors. If everything is ok, empty string must be returned :return: String of device status

abstractmethod is_connected() bool[source]#

Query whether the device is (still) connected

classmethod list_devices() list[tuple[str, str]][source]#

Get a list of all devices for this type. The list made up of: - Manually added devices - Available devices (those returned by _enumerate_devices) - A dummy device (if a dummy implementation exists) - List of all devices of child classes

Returns:

list of available devices