Explore Devices¶
Understanding the hardware connected to an Inscoper system requires querying two complementary sources of information exposed by the API. This example demonstrates how to combine both sources to build a complete picture of the configured devices and their sub-devices.
Overview¶
Device information in the Inscoper API is split across two distinct sources:
| Source | File | Content |
|---|---|---|
| Device List | config.xml |
The instance-level configuration of the system — which devices have been added, their assigned names, and which sub-devices have been selected |
| Device Description List | descriptions.xml |
The class-level definitions for all hardware supported by Inscoper — providing metadata such as the generic type (purpose) of each sub-device |
Combining these two sources makes it possible to determine not only which devices are present in a given configuration, but also what role each sub-device plays (e.g., shutter, objective turret, filter cube).
The example proceeds in two steps:
- Iterate over the Device List from the loaded configuration to collect the device instances, their names, and their configured sub-devices.
- Iterate over the Device Description List to enrich each sub-device with its functional type, matching entries by hardware ID and sub-device tag.
Note
This example uses a configuration named camera_and_microscope. Replace this value with the name defined in your own hardware configuration file.
Device exploration¶
from dataclasses import dataclass
import os
import sys
from typing import Dict
import inscoper_api
@dataclass
class SubDevice:
name: str = None # a descriptive string for the sub-device
tag: int = None # a unique identifier within the device for this sub-device
inscoper_type: int = None # a "purpose" type for the sub-device (what it does, e.g., CUBE, OBJECTIVE, SHUTTER...)
@dataclass
class Device:
name: str # the name given to the device during the configuration step
hardware_id: int # an identifier for this device model
sub_device_map: Dict[int, SubDevice] # the collection of chosen sub-devices for this particular device instance
# Macro to all Inscoper configurations
CONFIG_PATH = os.environ['InscoperConfigsPath']
my_bridge = inscoper_api.Bridge()
config = my_bridge.readConfigFile(os.sep.join([CONFIG_PATH, "camera_and_microscope"]))
my_bridge.loadConfigFile(os.sep.join([CONFIG_PATH, "camera_and_microscope"]))
my_bridge.initDevices()
# Dictionary to store the mapping of hardware IDs to our Device objects.
device_map = {}
# Step 1: Iterate over the "Device List" from the configuration.
# This tells us what specific devices have been added to this system's configuration.
for device in config.getDeviceList():
driver_config = device.getDriverConfig()
# In this example, we only keep devices controlled by the Inscoper Device Controller.
if isinstance(driver_config, inscoper_api.InscoperBoxDriverConfig):
device_name = device.getId() # e.g., "My Microscope" or "My Stage"
device_id = driver_config.getHardwareId() # The internal hardware identifier
sub_device_map = {}
# Iterate over all sub-devices configured for this device.
for sub_device_config in device.getSubDeviceConfigList():
sub_device_tag = sub_device_config.getTag() # The unique tag will allow us to connect config and description
sub_device_id = sub_device_config.getId() # Descriptive name of the sub-device
# Create our SubDevice instance and map it by its tag.
sub_device_map[sub_device_tag] = SubDevice(name=sub_device_id, tag=sub_device_tag)
# Store the complete Device object (with its sub-devices) in our global map.
device_map[device_id] = Device(name=device_name, hardware_id=device_id, sub_device_map=sub_device_map)
# At this point, device_map contains our devices, but we are missing the "purpose" of each sub-device.
print(device_map)
# Step 2: Iterate over the "Device Description List".
# This information acts as the "class definitions" (descriptions.xml) for all possible hardware supported by Inscoper,
# providing metadata like the generic type (purpose) of the sub-devices.
for device_desc in my_bridge.getDeviceDescriptionList():
driver_desc = device_desc.getDriverDescription()
# Again, we only keep devices controlled by the Inscoper Device Controller.
if isinstance(driver_desc, inscoper_api.InscoperBoxDriverDescription):
device_id = driver_desc.getHardwareId()
# If this hardware_id matches one of the devices we found in our configuration...
if device_id in device_map:
current_device = device_map[device_id]
sub_device_map = current_device.sub_device_map
# Look at all possible sub-devices described for this hardware model.
for sub_device_desc in device_desc.getSubDeviceDescriptionList():
sub_device_tag = sub_device_desc.getTag()
sub_device_type = sub_device_desc.getType() # The general purpose of the sub-device (e.g., CUBE, SHUTTER, etc.)
# If this configured device actually uses this specific sub-device...
if sub_device_tag in sub_device_map:
current_sub_device = sub_device_map[sub_device_tag]
# Store the human-readable string of the sub-device type
current_sub_device.inscoper_type = inscoper_api.Utils.subDeviceTypeToString(sub_device_type)
# Show the collected information (including sub-device purposes) for the configured devices
print(f"The device map: {device_map}")
my_bridge.close()