The chat responses are generated using Generative AI technology for intuitive search and may not be entirely accurate. They are not intended as professional advice. For full details, including our use rights, privacy practices and potential export control restrictions, please refer to our Generative AI Service Privacy Information. As this is a test version, please let us know if something irritating comes up. Like you get recommended a chocolate fudge ice cream instead of an energy managing application. If that occurs, please use the feedback button in our contact form!
Skip to content

Revolutionize your AI operations across locations with seamless cloud integration. Our Industrial AI Suite runs on a new line of Industrial PCs powered by NVIDIA's GPUs accelerating AI execution. This makes complex AI tasks in advanced automation broadly available and boosts efficiency.

payloads

Connection dataclass

Represents a connection with a name and an optional predefined combination of connection type and payload format.

Attributes:

NameTypeDescription
namestr

The name of the connection.

cptypeOptional[ConnectionTypeAndPayloadFormat]

The connection type and payload format, represented as an Enum.

Methods:

NameDescription
__setattr__

Custom attribute setter that validates attribute assignment. - 'name': Accepts any value. - 'cptype': Must be None or an instance of ConnectionTypeAndPayloadFormat. - Any other attribute: Raises ValueError.

__dict__

Returns a dictionary representation of the connection, including: - 'connectorName': The name of the connector. - 'connectorType': The type of the connector (if cptype is set). - 'payloadType': The payload type (if cptype is set).

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/connection.py
@dataclass
class Connection:
    """
    Represents a connection with a name and an optional predefined combination of connection type and payload format.

    Attributes:
        name (str): The name of the connection.
        cptype (Optional[ConnectionTypeAndPayloadFormat]): The connection type and payload format, represented as an Enum.

    Methods:
        __setattr__(name, value):
            Custom attribute setter that validates attribute assignment.
            - 'name': Accepts any value.
            - 'cptype': Must be None or an instance of ConnectionTypeAndPayloadFormat.
            - Any other attribute: Raises ValueError.

        __dict__():
            Returns a dictionary representation of the connection, including:
            - 'connectorName': The name of the connector.
            - 'connectorType': The type of the connector (if cptype is set).
            - 'payloadType': The payload type (if cptype is set).
    """

    name: str
    cptype: Optional[ConnectionTypeAndPayloadFormat] = None

    def __setattr__(self, name, value):
        """
        Setter for all attributes
        """
        match name:
            case "name":
                pass
            case "cptype":
                if value is not None and not isinstance(value, ConnectionTypeAndPayloadFormat):
                    raise ValueError("ERROR! 'type' must be an instance of ConnectionTypeAndPayloadFormat Enum.")
            case _:
                raise ValueError(f"ERROR! Unknown attribute '{name}' for connector '{self.name}'.")
        super(self.__class__, self).__setattr__(name, value)

    def __dict__(self):
        connection_dict = {
            "connectorName": self.name
        }
        if self.cptype is not None:
            connection_dict["connectorType"] = self.cptype.value[0]
            connection_dict["payloadType"] = self.cptype.value[1]

        return connection_dict

__setattr__(name, value)

Setter for all attributes

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/connection.py
def __setattr__(self, name, value):
    """
    Setter for all attributes
    """
    match name:
        case "name":
            pass
        case "cptype":
            if value is not None and not isinstance(value, ConnectionTypeAndPayloadFormat):
                raise ValueError("ERROR! 'type' must be an instance of ConnectionTypeAndPayloadFormat Enum.")
        case _:
            raise ValueError(f"ERROR! Unknown attribute '{name}' for connector '{self.name}'.")
    super(self.__class__, self).__setattr__(name, value)

ConnectionTypeAndPayloadFormat

Bases: Enum

Enum for predefined connection on AI Inference Server. The Attributes of the enum are tuples with the Type and Payload Format supported on AI Inference Server.

Attributes:

NameTypeDescription
Databus_Stringtuple

("databus", "String")

Databus_SIMATICv1tuple

("databus", "S7Json")

External_Databustuple

("mqtt", "String")

IE_Visiontuple

("vision", "VisionConnectorRaw")

ZMQ_Visiontuple

("zmq", "VisionConnectorRaw")

ZMQ_Multiparttuple

("zmq", "ZmqPayload")

ZMQ_Multipart_with_Metadatatuple

("zmq", "ZmqImageOutput")

Realtime_Backbonetuple

("rib", "RIBPayload")

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/connection.py
class ConnectionTypeAndPayloadFormat(Enum):
    """
    Enum for predefined connection on AI Inference Server.
    The Attributes of the enum are tuples with the Type and Payload Format supported on AI Inference Server.

    Attributes:
        Databus_String (tuple): ("databus", "String")
        Databus_SIMATICv1 (tuple): ("databus", "S7Json")

        External_Databus (tuple): ("mqtt", "String")

        IE_Vision (tuple): ("vision", "VisionConnectorRaw")

        ZMQ_Vision (tuple): ("zmq", "VisionConnectorRaw")
        ZMQ_Multipart (tuple): ("zmq", "ZmqPayload")
        ZMQ_Multipart_with_Metadata (tuple): ("zmq", "ZmqImageOutput")

        Realtime_Backbone (tuple): ("rib", "RIBPayload")
    """

    Databus_String = ("databus", "String")
    """
    Databus String or Json
    """

    Databus_SIMATICv1 = ("databus", "S7Json")
    """
    SIMATIC v1 (S7, S7+, OPC-UA, PROFINET IO)
    """

    External_String = ("mqtt", "String")
    """
    External Databus String
    """

    IE_Vision = ("vision", "VisionConnectorRaw")
    """
    IE Vision Connector (High throughput, ZMQ Based, Multipart)
    """

    ZMQ_Vision  = ("zmq", "VisionConnectorRaw")
    """
    Zero Message Queue Vision Connector Raw (Vision payload)
    """

    ZMQ_Multipart     = ("zmq", "ZmqPayload")
    """
    Zero Message Queue Internal multipart message (Topic, binary data or string)
    """

    ZMQ_Multipart_with_Metadata       = ("zmq", "ZmqImageOutput")
    """
    Zero Message Queue Internal multipart message (Topic, metadata, binary)
    """

    Realtime_Backbone = ("rib", "RIBPayload")
    """
    Real-time Information Backbone
    """

Databus_String = ('databus', 'String') class-attribute instance-attribute

Databus String or Json

Databus_SIMATICv1 = ('databus', 'S7Json') class-attribute instance-attribute

SIMATIC v1 (S7, S7+, OPC-UA, PROFINET IO)

External_String = ('mqtt', 'String') class-attribute instance-attribute

External Databus String

IE_Vision = ('vision', 'VisionConnectorRaw') class-attribute instance-attribute

IE Vision Connector (High throughput, ZMQ Based, Multipart)

ZMQ_Vision = ('zmq', 'VisionConnectorRaw') class-attribute instance-attribute

Zero Message Queue Vision Connector Raw (Vision payload)

ZMQ_Multipart = ('zmq', 'ZmqPayload') class-attribute instance-attribute

Zero Message Queue Internal multipart message (Topic, binary data or string)

ZMQ_Multipart_with_Metadata = ('zmq', 'ZmqImageOutput') class-attribute instance-attribute

Zero Message Queue Internal multipart message (Topic, metadata, binary)

Realtime_Backbone = ('rib', 'RIBPayload') class-attribute instance-attribute

Real-time Information Backbone

PipelineVariable dataclass

Bases: MappableMixin

Represents a variable in a pipeline, linking a component's variable to a connection and optional mapping. For IE Vision connections, cameraName should be defined, otherwise tagName is preferred.

Attributes:

NameTypeDescription
componentNamestr

The name of the component the variable belongs to.

variableNamestr

The name of the variable.

connectionOptional[Connection]

The connection associated with the variable.

tagNameOptional[str]

The tag name to map to.

cameraNameOptional[str]

The camera name to map to. Used only via IE_Vision connection.

mappingOptional[str]

The topic or camera id to map to.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
@dataclass
class PipelineVariable(MappableMixin):
    """
    Represents a variable in a pipeline, linking a component's variable to a connection and optional mapping.
    For IE Vision connections, cameraName should be defined, otherwise tagName is preferred.

    Attributes:
        componentName (str): The name of the component the variable belongs to.
        variableName (str): The name of the variable.

        connection (Optional[Connection]): The connection associated with the variable.
        tagName (Optional[str]): The tag name to map to.
        cameraName (Optional[str]): The camera name to map to. Used only via IE_Vision connection.
        mapping (Optional[str]): The topic or camera id to map to.
    """
    componentName: str
    variableName: str

    # Mixin fields as dataclass fields
    connection: Optional[Connection] = field(default=None)
    tagName: Optional[str] = field(default=None)
    cameraName: Optional[str] = field(default=None)
    mapping: Optional[str] = field(default=None)

    def check_connection_type_compatibility(self, variable_type: str) -> tuple[list, list]:
        if self.connection is None:
            return [], []
        supported_types = SUPPORTED_TYPES_BY_CONNECTION.get(self.connection.cptype, [])
        flags = type_validation_flags(variable_type, supported_types)
        if self.connection.cptype == ConnectionTypeAndPayloadFormat.Realtime_Backbone:
            warning_flags = []
            error_flags = [f.value for f in flags]
        else:
            warning_flags = [f.value for f in flags if f != TypeValidationFlags.ARRAY_WITH_MISSING_SIZE]
            error_flags = []
        return warning_flags, error_flags

    def __getitem__(self, item):
        return getattr(self, item)

    def __setattr__(self, name, value):
        """
        Setter for all attributes
        """
        match name:
            case "componentName":
                if re.match("^[a-zA-Z0-9_-]+$", value) is None:
                    raise ValueError(f"ERROR! Invalid name '{value}'. Only alphanumeric characters and underscores are allowed.")
            case "variableName":
                if re.match("^[a-zA-Z0-9_-]+$", value) is None:
                    raise ValueError(f"ERROR! Invalid name '{value}'. Only alphanumeric characters and underscores are allowed.")
                if value in reserved_names:
                    raise ValueError(f"ERROR! '{value}' is a reserved name and cannot be used as variable name.")
            case _:
                # Let the mixin handle mapping attributes
                pass

        super().__setattr__(name, value)

    def __dict__(self, component_io_list: list) -> dict:
        json_dict = {
            "name": self.variableName,
            "type": component_io_list[self.variableName]['type']
        }

        json_dict.update(self.__mappable_dict__())

        return json_dict

__setattr__(name, value)

Setter for all attributes

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
def __setattr__(self, name, value):
    """
    Setter for all attributes
    """
    match name:
        case "componentName":
            if re.match("^[a-zA-Z0-9_-]+$", value) is None:
                raise ValueError(f"ERROR! Invalid name '{value}'. Only alphanumeric characters and underscores are allowed.")
        case "variableName":
            if re.match("^[a-zA-Z0-9_-]+$", value) is None:
                raise ValueError(f"ERROR! Invalid name '{value}'. Only alphanumeric characters and underscores are allowed.")
            if value in reserved_names:
                raise ValueError(f"ERROR! '{value}' is a reserved name and cannot be used as variable name.")
        case _:
            # Let the mixin handle mapping attributes
            pass

    super().__setattr__(name, value)

PipelineParameter dataclass

Bases: MappableMixin

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
@dataclass
class PipelineParameter(MappableMixin):
    name: str
    defaultValue: Optional[str] = None
    dtype: Optional[str] = None  # 'String', 'Integer', 'Float', 'Boolean'
    description: Optional[str] = None
    topicBased: Optional[bool] = False
    valueTopic: Optional[str] = None

    # Mixin fields as dataclass fields
    connection: Optional[Connection] = field(default=None)
    tagName: Optional[str] = field(default=None)
    mapping: Optional[str] = field(default=None)

    def __post_init__(self):
        # Validate if the topicBased flag is False, then valueTopic, connection, tag, and topic should not be set
        if not self.topicBased and (self.valueTopic is not None or self.connection is not None or self.tagName is not None or self.mapping is not None):
            raise ValueError("ERROR! 'valueTopic', 'connection', 'tag', and 'topic' must be None when 'topicBased' is False.")
        if self.dtype != _get_is_type(type(self.defaultValue)):
            raise ValueError(f"'The given value type does not match the type of defaultValue: '{self.defaultValue}'")

    def __setattr__(self, name, value):
        """
        Setter for all attributes
        """
        match name:
            case "name":
                _check_name_validity(value)
            case "dtype":
                if value is None:
                    return
                elif value not in ['String', 'Integer', 'Double', 'Boolean']:
                    raise ValueError("ERROR! 'dtype' must be one of 'String', 'Integer', 'Double', 'Boolean', or None.")
            case "defaultValue":
                dtype = _get_is_type(type(value))
                if dtype is None:
                    raise ValueError("ERROR! 'dtype' must be one of 'String', 'Integer', 'Double', 'Boolean', or None.")
                self.dtype = dtype
            case "description":
                _check_description_validity(value)
            case "topicBased":
                if not isinstance(value, bool):
                    raise ValueError("Type of the given `topic_based` parameter is not `bool`")
            case "valueTopic":
                if not (value is None or value == ""):
                    self.topicBased = True
            case _:
                # Let the mixin handle mapping attributes
                pass

        super().__setattr__(name, value)

    def has_valid_connection(self) -> set:
        if self.connection is None:
            return True
        supported_types = SUPPORTED_TYPES_BY_CONNECTION.get(self.connection.cptype, [])
        return type_validation_flags(self.dtype, supported_types) == set()

    def __param_dict__(self) -> dict:
        json_dict = {
            'name': self.name,
            'defaultValue': self.defaultValue,
            'dtype': self.dtype
        }

        json_dict.update(self.__mappable_dict__())

        json_dict['type'] = json_dict.pop('dtype', None)
        if self.topicBased:
            json_dict['topicBased'] = True
            json_dict['valueTopic'] = json_dict.pop('topic', None)

        return json_dict

__setattr__(name, value)

Setter for all attributes

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
def __setattr__(self, name, value):
    """
    Setter for all attributes
    """
    match name:
        case "name":
            _check_name_validity(value)
        case "dtype":
            if value is None:
                return
            elif value not in ['String', 'Integer', 'Double', 'Boolean']:
                raise ValueError("ERROR! 'dtype' must be one of 'String', 'Integer', 'Double', 'Boolean', or None.")
        case "defaultValue":
            dtype = _get_is_type(type(value))
            if dtype is None:
                raise ValueError("ERROR! 'dtype' must be one of 'String', 'Integer', 'Double', 'Boolean', or None.")
            self.dtype = dtype
        case "description":
            _check_description_validity(value)
        case "topicBased":
            if not isinstance(value, bool):
                raise ValueError("Type of the given `topic_based` parameter is not `bool`")
        case "valueTopic":
            if not (value is None or value == ""):
                self.topicBased = True
        case _:
            # Let the mixin handle mapping attributes
            pass

    super().__setattr__(name, value)

SecretPipelineParameter dataclass

Represents a secret pipeline parameter for handling sensitive information. Cannot be modified after creation.

Attributes:

NameTypeDescription
namestr

The name of the secret parameter.

descriptionOptional[str]

An optional description of the secret parameter.

defaultValuestr

Pipeline parameters must have a default value, which is an empty string for secret parameters.

dtypestr

The data type of the secret parameter is always "Secret".

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
@dataclass(frozen=True)
class SecretPipelineParameter:
    """
    Represents a secret pipeline parameter for handling sensitive information.
    Cannot be modified after creation.

    Attributes:
        name (str): The name of the secret parameter.
        description (Optional[str]): An optional description of the secret parameter.
        defaultValue (str): Pipeline parameters must have a default value, which is an empty string for secret parameters.
        dtype (str): The data type of the secret parameter is always "Secret".
    """

    name: str
    description: Optional[str] = None
    defaultValue: str = field(init=False, default="")
    dtype: str = field(init=False, default="Secret")

    def __post_init__(self):
        _check_name_validity(self.name)
        _check_description_validity(self.description)

    def __param_dict__(self) -> dict:
        json_dict = {
            'name': self.name,
            'defaultValue': "",
            'type': self.dtype
        }
        return json_dict

ConnectionTypeAndPayloadFormat

Bases: Enum

Enum for predefined connection on AI Inference Server. The Attributes of the enum are tuples with the Type and Payload Format supported on AI Inference Server.

Attributes:

NameTypeDescription
Databus_Stringtuple

("databus", "String")

Databus_SIMATICv1tuple

("databus", "S7Json")

External_Databustuple

("mqtt", "String")

IE_Visiontuple

("vision", "VisionConnectorRaw")

ZMQ_Visiontuple

("zmq", "VisionConnectorRaw")

ZMQ_Multiparttuple

("zmq", "ZmqPayload")

ZMQ_Multipart_with_Metadatatuple

("zmq", "ZmqImageOutput")

Realtime_Backbonetuple

("rib", "RIBPayload")

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/connection.py
class ConnectionTypeAndPayloadFormat(Enum):
    """
    Enum for predefined connection on AI Inference Server.
    The Attributes of the enum are tuples with the Type and Payload Format supported on AI Inference Server.

    Attributes:
        Databus_String (tuple): ("databus", "String")
        Databus_SIMATICv1 (tuple): ("databus", "S7Json")

        External_Databus (tuple): ("mqtt", "String")

        IE_Vision (tuple): ("vision", "VisionConnectorRaw")

        ZMQ_Vision (tuple): ("zmq", "VisionConnectorRaw")
        ZMQ_Multipart (tuple): ("zmq", "ZmqPayload")
        ZMQ_Multipart_with_Metadata (tuple): ("zmq", "ZmqImageOutput")

        Realtime_Backbone (tuple): ("rib", "RIBPayload")
    """

    Databus_String = ("databus", "String")
    """
    Databus String or Json
    """

    Databus_SIMATICv1 = ("databus", "S7Json")
    """
    SIMATIC v1 (S7, S7+, OPC-UA, PROFINET IO)
    """

    External_String = ("mqtt", "String")
    """
    External Databus String
    """

    IE_Vision = ("vision", "VisionConnectorRaw")
    """
    IE Vision Connector (High throughput, ZMQ Based, Multipart)
    """

    ZMQ_Vision  = ("zmq", "VisionConnectorRaw")
    """
    Zero Message Queue Vision Connector Raw (Vision payload)
    """

    ZMQ_Multipart     = ("zmq", "ZmqPayload")
    """
    Zero Message Queue Internal multipart message (Topic, binary data or string)
    """

    ZMQ_Multipart_with_Metadata       = ("zmq", "ZmqImageOutput")
    """
    Zero Message Queue Internal multipart message (Topic, metadata, binary)
    """

    Realtime_Backbone = ("rib", "RIBPayload")
    """
    Real-time Information Backbone
    """

Databus_String = ('databus', 'String') class-attribute instance-attribute

Databus String or Json

Databus_SIMATICv1 = ('databus', 'S7Json') class-attribute instance-attribute

SIMATIC v1 (S7, S7+, OPC-UA, PROFINET IO)

External_String = ('mqtt', 'String') class-attribute instance-attribute

External Databus String

IE_Vision = ('vision', 'VisionConnectorRaw') class-attribute instance-attribute

IE Vision Connector (High throughput, ZMQ Based, Multipart)

ZMQ_Vision = ('zmq', 'VisionConnectorRaw') class-attribute instance-attribute

Zero Message Queue Vision Connector Raw (Vision payload)

ZMQ_Multipart = ('zmq', 'ZmqPayload') class-attribute instance-attribute

Zero Message Queue Internal multipart message (Topic, binary data or string)

ZMQ_Multipart_with_Metadata = ('zmq', 'ZmqImageOutput') class-attribute instance-attribute

Zero Message Queue Internal multipart message (Topic, metadata, binary)

Realtime_Backbone = ('rib', 'RIBPayload') class-attribute instance-attribute

Real-time Information Backbone

Connection dataclass

Represents a connection with a name and an optional predefined combination of connection type and payload format.

Attributes:

NameTypeDescription
namestr

The name of the connection.

cptypeOptional[ConnectionTypeAndPayloadFormat]

The connection type and payload format, represented as an Enum.

Methods:

NameDescription
__setattr__

Custom attribute setter that validates attribute assignment. - 'name': Accepts any value. - 'cptype': Must be None or an instance of ConnectionTypeAndPayloadFormat. - Any other attribute: Raises ValueError.

__dict__

Returns a dictionary representation of the connection, including: - 'connectorName': The name of the connector. - 'connectorType': The type of the connector (if cptype is set). - 'payloadType': The payload type (if cptype is set).

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/connection.py
@dataclass
class Connection:
    """
    Represents a connection with a name and an optional predefined combination of connection type and payload format.

    Attributes:
        name (str): The name of the connection.
        cptype (Optional[ConnectionTypeAndPayloadFormat]): The connection type and payload format, represented as an Enum.

    Methods:
        __setattr__(name, value):
            Custom attribute setter that validates attribute assignment.
            - 'name': Accepts any value.
            - 'cptype': Must be None or an instance of ConnectionTypeAndPayloadFormat.
            - Any other attribute: Raises ValueError.

        __dict__():
            Returns a dictionary representation of the connection, including:
            - 'connectorName': The name of the connector.
            - 'connectorType': The type of the connector (if cptype is set).
            - 'payloadType': The payload type (if cptype is set).
    """

    name: str
    cptype: Optional[ConnectionTypeAndPayloadFormat] = None

    def __setattr__(self, name, value):
        """
        Setter for all attributes
        """
        match name:
            case "name":
                pass
            case "cptype":
                if value is not None and not isinstance(value, ConnectionTypeAndPayloadFormat):
                    raise ValueError("ERROR! 'type' must be an instance of ConnectionTypeAndPayloadFormat Enum.")
            case _:
                raise ValueError(f"ERROR! Unknown attribute '{name}' for connector '{self.name}'.")
        super(self.__class__, self).__setattr__(name, value)

    def __dict__(self):
        connection_dict = {
            "connectorName": self.name
        }
        if self.cptype is not None:
            connection_dict["connectorType"] = self.cptype.value[0]
            connection_dict["payloadType"] = self.cptype.value[1]

        return connection_dict

__setattr__(name, value)

Setter for all attributes

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/connection.py
def __setattr__(self, name, value):
    """
    Setter for all attributes
    """
    match name:
        case "name":
            pass
        case "cptype":
            if value is not None and not isinstance(value, ConnectionTypeAndPayloadFormat):
                raise ValueError("ERROR! 'type' must be an instance of ConnectionTypeAndPayloadFormat Enum.")
        case _:
            raise ValueError(f"ERROR! Unknown attribute '{name}' for connector '{self.name}'.")
    super(self.__class__, self).__setattr__(name, value)

This module defines the ImageDetails and ImageSet data structures for handling image payloads in the context of AI Inference Server communication. It includes functionality for parsing and formatting timestamps, converting image formats, and serializing/deserializing image data.

Examples:

  • Creating an ImageDetails object from an image file: image_details = ImageDetails.from_image("path/to/image.jpg", format="RGB8")

  • Creating an ImageSet and adding images: image_set = ImageSet() image_set.add_image(image_details) images_set.add_image(ImageDetails.from_image("path/to/another_image.png", format="Mono8"))

  • Converting a BGR image to a different format: converted_image, height, width = ImageDetails.convert_image_from_BGR(bgr_image, "Mono8")

  • Creating an ImageSet from a dictionary payload: image_set = ImageSet.from_dict(payload_dict)

  • Serializing an ImageSet to a dictionary: payload_dict = image_set.to_dict()

Vision Payload Specification https://docs.eu1.edge.siemens.cloud/apis_and_references/apis/point-to-point/VisionPayloadspecification_V1-0-0.html#vision-connector-image-format However, the above documentation is incomplete. The following are the

Required fields for ImageSet, based on AI Inference Server source {"version", FieldType::String}, {"cameraid", FieldType::String}, {"timestamp", FieldType::String}, {"detail", FieldType::StructArray} };

Required fields for ImageDetails, based on AI Inference Server source: {"id", FieldType::String}, {"seq", FieldType::Integer}, {"format", FieldType::String}, {"image", FieldType::Binary} };

ImageFormat

Bases: Enum

Enumeration of supported image formats. To extend supported formats, update the ImageDetails conversion methods accordingly.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
class ImageFormat(Enum):
    """Enumeration of supported image formats.
    To extend supported formats, update the ImageDetails conversion methods accordingly.
    """
    RGB8 = "RGB8"
    BGR8 = "BGR8"
    YUV422Packed = "YUV422Packed"
    YUV422_YUYV_Packed = "YUV422_YUYV_Packed"
    Mono8 = "Mono8"
    BayerRG8 = "BayerRG8"
    BayerGR8 = "BayerGR8"
    BayerBG8 = "BayerBG8"
    BayerGB8 = "BayerGB8"

ImageDetails dataclass

Data structure representing the details of a single image in an ImageSet payload. Represents the details of a single image in an ImageSet payload. Fields: id (str): Unique identifier for the image. width (int): Width of the image in pixels. height (int): Height of the image in pixels. seq (int): Sequence number of the image. timestamp (datetime): Timestamp when the image was captured. metadata (dict): Additional metadata associated with the image. format (ImageFormat): Format of the image. image (bytes): Binary data of the image.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
@dataclass
class ImageDetails:
    """Data structure representing the details of a single image in an ImageSet payload.
    Represents the details of a single image in an ImageSet payload.
    Fields:
        id (str): Unique identifier for the image.
        width (int): Width of the image in pixels.
        height (int): Height of the image in pixels.
        seq (int): Sequence number of the image.
        timestamp (datetime): Timestamp when the image was captured.
        metadata (dict): Additional metadata associated with the image.
        format (ImageFormat): Format of the image.
        image (bytes): Binary data of the image.
    """

    id: str
    width: int
    height: int

    seq: int = field(default=0)
    timestamp: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
    metadata: dict = field(default_factory=dict)

    format: ImageFormat = field(default=ImageFormat.RGB8)
    image: bytes = field(default=b"")

    def __post_init__(self):
        assert isinstance(self.id, str)
        assert isinstance(self.timestamp, datetime)
        assert isinstance(self.width, int) and self.width > 0
        assert isinstance(self.height, int) and self.height > 0
        assert isinstance(self.format, ImageFormat) and self.format in ImageFormat.__members__.values()
        assert isinstance(self.image, bytes) and len(self.image) > 0

    @staticmethod
    def _parse_image_format(format: str | ImageFormat | None = None) -> ImageFormat:
        match format:
            case None:
                return ImageFormat.RGB8
            case ImageFormat():
                return format
            case str() if format in ImageFormat.__members__.keys():
                return ImageFormat[format]
        _supported_image_formats = [format.value for format in ImageFormat.__members__.values()]
        raise ValueError(f"ERROR Provided image format '{format}' is not supported. image_format must be one of {_supported_image_formats}")

    @staticmethod
    def from_image(image_path: Path | str, format: ImageFormat | str | None = None) -> 'ImageDetails':
        """Creates an ImageDetails object from an image file.
        Args:
            image_path (Path | str): Path to the image file.
            format (ImageFormat | str | None): Desired image format (default: RGB8).
        Raises:
            ValueError: If the image file is not found or cannot be read.
        Returns: ImageDetails: Created ImageDetails object.
        """
        format = ImageDetails._parse_image_format(format)

        image_path = Path(image_path)
        image = cv2.imread(str(image_path))
        if image is None:
            raise ValueError(f"Image file {image_path} not found")

        res_image, height, width = ImageDetails.convert_image_from_BGR(image, format)
        return ImageDetails(
            id=image_path.name,
            timestamp=datetime.now(timezone.utc),
            width=width,
            height=height,
            format=format,
            image=res_image
        )

    @staticmethod
    def _bgr_to_bayer(bgr_image: np.ndarray, bayer_order: str) -> np.ndarray:
        (height, width) = bgr_image.shape[:2]
        bayer_image = np.zeros((height, width), dtype=np.uint8)

        BLUE, GREEN, RED = 0, 1, 2
        match bayer_order:
            case 'BayerRG8':
                channels = (RED, GREEN, GREEN, BLUE)
            case 'BayerGR8':
                channels = (GREEN, RED, BLUE, GREEN)
            case 'BayerBG8':
                channels = (BLUE, GREEN, GREEN, RED)
            case 'BayerGB8':
                channels = (GREEN, BLUE, RED, GREEN)
            case _:
                raise ValueError(f"Unsupported bayer order: {bayer_order}")

        top_left_ch, top_right_ch, bottom_left_ch, bottom_right_ch = channels
        bayer_image[0::2, 0::2] = bgr_image[0::2, 0::2, top_left_ch]
        bayer_image[0::2, 1::2] = bgr_image[0::2, 1::2, top_right_ch]
        bayer_image[1::2, 0::2] = bgr_image[1::2, 0::2, bottom_left_ch]
        bayer_image[1::2, 1::2] = bgr_image[1::2, 1::2, bottom_right_ch]
        return bayer_image

    @staticmethod
    def convert_image_from_BGR(bgr_image: np.ndarray, target_format: str | ImageFormat | None = None) -> tuple[bytes, int, int]:
        """
        Converts a BGR image to the specified target format.
        Args:
            bgr_image (np.ndarray): Input image in BGR format.
            target_format (str | ImageFormat): Target image format.
        Raises:
            ValueError: If the target format is unsupported.
        Returns: A tuple containing the converted image as bytes, height, and width.
        """

        _target_format: ImageFormat = ImageDetails._parse_image_format(target_format)

        match _target_format:
            case "BGR8" | ImageFormat.BGR8:
                res_image = bgr_image
            case "RGB8" | ImageFormat.RGB8:
                res_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)
            case "Mono8" | ImageFormat.Mono8:
                res_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2GRAY)
            case "BayerRG8" | ImageFormat.BayerRG8:
                res_image = ImageDetails._bgr_to_bayer(bgr_image, "BayerRG8")
            case "BayerGR8" | ImageFormat.BayerGR8:
                res_image = ImageDetails._bgr_to_bayer(bgr_image, "BayerGR8")
            case "BayerBG8" | ImageFormat.BayerBG8:
                res_image = ImageDetails._bgr_to_bayer(bgr_image, "BayerBG8")
            case "BayerGB8" | ImageFormat.BayerGB8:
                res_image = ImageDetails._bgr_to_bayer(bgr_image, "BayerGB8")
            case "YUV422Packed" | ImageFormat.YUV422Packed:
                # COLOR_BGR2YUV_Y422 is the 4:2:2 sampling format of YUV, with coefficients correspond to the BT.601 standard.
                # After ravel() it becomes a packed format, where the order of the channels is UYVY.
                res_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2YUV_Y422)
            case "YUV422_YUYV_Packed" | ImageFormat.YUV422_YUYV_Packed:
                # Same as the above but with YUYV order.
                res_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2YUV_YUYV)
            case _:
                raise ValueError(f"Unsupported target format: {target_format}")
        height, width = res_image.shape[:2]
        res_image = res_image.ravel().tobytes()
        return res_image, height, width

    @staticmethod
    def from_dict(data: dict):
        """
        Creates an ImageDetails object from the details of a given ImageSet payload.

        Args:
            data (dict): Dictionary containing image details
        Raises:
            ValueError: If there is an error parsing the image details
        Returns: ImageDetails: Parsed ImageDetails object
        """
        try:
            details = ImageDetails(
                id          =   data.get("id", f"simaticai-image-{datetime.now().timestamp()}"),
                seq         =   data.get("seq", 0),
                timestamp   =   parse_aiis_timestamp(data.get("timestamp")),
                format      =   ImageFormat[data.get("format", "RGB8")],
                width       =   data.get("width", 0),
                height      =   data.get("height", 0),
                metadata    =   data.get("metadata", {}),
                image       =   data.get("image", b"")
            )
        except Exception as e:
            raise ValueError(f"Error parsing image details: {repr(e)}")
        return details

    def to_dict(self) -> dict:
        """
        Converts the ImageDetails object to a dictionary.

        Returns:
            dict: Dictionary representation of the ImageDetails object.
        """
        return {
            "id": self.id,
            "seq": self.seq,
            "timestamp": format_aiis_timestamp(self.timestamp),
            "format": self.format.value,
            "width": self.width,
            "height": self.height,
            "metadata": self.metadata,
            "image": self.image
        }

    def update_image(self, image: np.ndarray, image_format: ImageFormat):
        """
        Updates the image data and format of the ImageDetails object.
        Args:
            image (np.ndarray): New image data as a NumPy array.
            image_format (ImageFormat): New image format.
        """
        self.format = image_format
        self.height = image.shape[0]
        self.width = image.shape[1]
        self.image = image.ravel().tobytes()

    def get_image_array(self) -> np.ndarray:
        """Returns the image as a NumPy array based on its format.
        Raises:
            ValueError: If the image format is unsupported.
        Returns: np.ndarray: Image as a NumPy array.
        """
        image = self.image
        image = np.frombuffer(image, dtype=np.uint8)
        match self.format:
            case ImageFormat.RGB8 | ImageFormat.BGR8:
                image = image.reshape(self.height, self.width, 3)
            case ImageFormat.Mono8 | ImageFormat.BayerRG8 | ImageFormat.BayerGR8 | ImageFormat.BayerBG8 | ImageFormat.BayerGB8:
                image = image.reshape(self.height, self.width)
            case ImageFormat.YUV422Packed | ImageFormat.YUV422_YUYV_Packed:
                image = image.reshape(self.height, self.width, 2)
            case _:
                raise ValueError(f"Unsupported image format: {self.format}")
        return image

    def get_image_rgb(self) -> np.ndarray:
        """Returns the image converted to RGB format as a NumPy array.
        Raises:
            ValueError: If the image format is unsupported.
        Returns: np.ndarray: Image in RGB format as a NumPy array.
        """
        image = self.get_image_array()
        match self.format:
            case ImageFormat.Mono8:
                return cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)
            case ImageFormat.RGB8:
                return image
            case ImageFormat.BGR8:
                return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
            case ImageFormat.BayerRG8:
                return cv2.cvtColor(image, cv2.COLOR_BayerRGGB2RGB)
            case ImageFormat.BayerGR8:
                return cv2.cvtColor(image, cv2.COLOR_BayerGRBG2RGB)
            case ImageFormat.BayerBG8:
                return cv2.cvtColor(image, cv2.COLOR_BayerBGGR2RGB)
            case ImageFormat.BayerGB8:
                return cv2.cvtColor(image, cv2.COLOR_BayerGBRG2RGB)
            case ImageFormat.YUV422Packed:
                return cv2.cvtColor(image, cv2.COLOR_YUV2RGB_Y422)
            case ImageFormat.YUV422_YUYV_Packed:
                return cv2.cvtColor(image, cv2.COLOR_YUV2RGB_YUYV)
            case _:
                raise ValueError(f"Unsupported image format: {self.format}")

from_image(image_path, format=None) staticmethod

Creates an ImageDetails object from an image file. Args: image_path (Path | str): Path to the image file. format (ImageFormat | str | None): Desired image format (default: RGB8). Raises: ValueError: If the image file is not found or cannot be read. Returns: ImageDetails: Created ImageDetails object.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
@staticmethod
def from_image(image_path: Path | str, format: ImageFormat | str | None = None) -> 'ImageDetails':
    """Creates an ImageDetails object from an image file.
    Args:
        image_path (Path | str): Path to the image file.
        format (ImageFormat | str | None): Desired image format (default: RGB8).
    Raises:
        ValueError: If the image file is not found or cannot be read.
    Returns: ImageDetails: Created ImageDetails object.
    """
    format = ImageDetails._parse_image_format(format)

    image_path = Path(image_path)
    image = cv2.imread(str(image_path))
    if image is None:
        raise ValueError(f"Image file {image_path} not found")

    res_image, height, width = ImageDetails.convert_image_from_BGR(image, format)
    return ImageDetails(
        id=image_path.name,
        timestamp=datetime.now(timezone.utc),
        width=width,
        height=height,
        format=format,
        image=res_image
    )

convert_image_from_BGR(bgr_image, target_format=None) staticmethod

Converts a BGR image to the specified target format. Args: bgr_image (np.ndarray): Input image in BGR format. target_format (str | ImageFormat): Target image format. Raises: ValueError: If the target format is unsupported. Returns: A tuple containing the converted image as bytes, height, and width.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
@staticmethod
def convert_image_from_BGR(bgr_image: np.ndarray, target_format: str | ImageFormat | None = None) -> tuple[bytes, int, int]:
    """
    Converts a BGR image to the specified target format.
    Args:
        bgr_image (np.ndarray): Input image in BGR format.
        target_format (str | ImageFormat): Target image format.
    Raises:
        ValueError: If the target format is unsupported.
    Returns: A tuple containing the converted image as bytes, height, and width.
    """

    _target_format: ImageFormat = ImageDetails._parse_image_format(target_format)

    match _target_format:
        case "BGR8" | ImageFormat.BGR8:
            res_image = bgr_image
        case "RGB8" | ImageFormat.RGB8:
            res_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)
        case "Mono8" | ImageFormat.Mono8:
            res_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2GRAY)
        case "BayerRG8" | ImageFormat.BayerRG8:
            res_image = ImageDetails._bgr_to_bayer(bgr_image, "BayerRG8")
        case "BayerGR8" | ImageFormat.BayerGR8:
            res_image = ImageDetails._bgr_to_bayer(bgr_image, "BayerGR8")
        case "BayerBG8" | ImageFormat.BayerBG8:
            res_image = ImageDetails._bgr_to_bayer(bgr_image, "BayerBG8")
        case "BayerGB8" | ImageFormat.BayerGB8:
            res_image = ImageDetails._bgr_to_bayer(bgr_image, "BayerGB8")
        case "YUV422Packed" | ImageFormat.YUV422Packed:
            # COLOR_BGR2YUV_Y422 is the 4:2:2 sampling format of YUV, with coefficients correspond to the BT.601 standard.
            # After ravel() it becomes a packed format, where the order of the channels is UYVY.
            res_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2YUV_Y422)
        case "YUV422_YUYV_Packed" | ImageFormat.YUV422_YUYV_Packed:
            # Same as the above but with YUYV order.
            res_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2YUV_YUYV)
        case _:
            raise ValueError(f"Unsupported target format: {target_format}")
    height, width = res_image.shape[:2]
    res_image = res_image.ravel().tobytes()
    return res_image, height, width

from_dict(data) staticmethod

Creates an ImageDetails object from the details of a given ImageSet payload.

Parameters:

NameTypeDescriptionDefault
datadict

Dictionary containing image details

required
Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
@staticmethod
def from_dict(data: dict):
    """
    Creates an ImageDetails object from the details of a given ImageSet payload.

    Args:
        data (dict): Dictionary containing image details
    Raises:
        ValueError: If there is an error parsing the image details
    Returns: ImageDetails: Parsed ImageDetails object
    """
    try:
        details = ImageDetails(
            id          =   data.get("id", f"simaticai-image-{datetime.now().timestamp()}"),
            seq         =   data.get("seq", 0),
            timestamp   =   parse_aiis_timestamp(data.get("timestamp")),
            format      =   ImageFormat[data.get("format", "RGB8")],
            width       =   data.get("width", 0),
            height      =   data.get("height", 0),
            metadata    =   data.get("metadata", {}),
            image       =   data.get("image", b"")
        )
    except Exception as e:
        raise ValueError(f"Error parsing image details: {repr(e)}")
    return details

to_dict()

Converts the ImageDetails object to a dictionary.

Returns:

NameTypeDescription
dictdict

Dictionary representation of the ImageDetails object.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
def to_dict(self) -> dict:
    """
    Converts the ImageDetails object to a dictionary.

    Returns:
        dict: Dictionary representation of the ImageDetails object.
    """
    return {
        "id": self.id,
        "seq": self.seq,
        "timestamp": format_aiis_timestamp(self.timestamp),
        "format": self.format.value,
        "width": self.width,
        "height": self.height,
        "metadata": self.metadata,
        "image": self.image
    }

update_image(image, image_format)

Updates the image data and format of the ImageDetails object. Args: image (np.ndarray): New image data as a NumPy array. image_format (ImageFormat): New image format.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
def update_image(self, image: np.ndarray, image_format: ImageFormat):
    """
    Updates the image data and format of the ImageDetails object.
    Args:
        image (np.ndarray): New image data as a NumPy array.
        image_format (ImageFormat): New image format.
    """
    self.format = image_format
    self.height = image.shape[0]
    self.width = image.shape[1]
    self.image = image.ravel().tobytes()

get_image_array()

Returns the image as a NumPy array based on its format. Raises: ValueError: If the image format is unsupported. Returns: np.ndarray: Image as a NumPy array.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
def get_image_array(self) -> np.ndarray:
    """Returns the image as a NumPy array based on its format.
    Raises:
        ValueError: If the image format is unsupported.
    Returns: np.ndarray: Image as a NumPy array.
    """
    image = self.image
    image = np.frombuffer(image, dtype=np.uint8)
    match self.format:
        case ImageFormat.RGB8 | ImageFormat.BGR8:
            image = image.reshape(self.height, self.width, 3)
        case ImageFormat.Mono8 | ImageFormat.BayerRG8 | ImageFormat.BayerGR8 | ImageFormat.BayerBG8 | ImageFormat.BayerGB8:
            image = image.reshape(self.height, self.width)
        case ImageFormat.YUV422Packed | ImageFormat.YUV422_YUYV_Packed:
            image = image.reshape(self.height, self.width, 2)
        case _:
            raise ValueError(f"Unsupported image format: {self.format}")
    return image

get_image_rgb()

Returns the image converted to RGB format as a NumPy array. Raises: ValueError: If the image format is unsupported. Returns: np.ndarray: Image in RGB format as a NumPy array.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
def get_image_rgb(self) -> np.ndarray:
    """Returns the image converted to RGB format as a NumPy array.
    Raises:
        ValueError: If the image format is unsupported.
    Returns: np.ndarray: Image in RGB format as a NumPy array.
    """
    image = self.get_image_array()
    match self.format:
        case ImageFormat.Mono8:
            return cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)
        case ImageFormat.RGB8:
            return image
        case ImageFormat.BGR8:
            return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        case ImageFormat.BayerRG8:
            return cv2.cvtColor(image, cv2.COLOR_BayerRGGB2RGB)
        case ImageFormat.BayerGR8:
            return cv2.cvtColor(image, cv2.COLOR_BayerGRBG2RGB)
        case ImageFormat.BayerBG8:
            return cv2.cvtColor(image, cv2.COLOR_BayerBGGR2RGB)
        case ImageFormat.BayerGB8:
            return cv2.cvtColor(image, cv2.COLOR_BayerGBRG2RGB)
        case ImageFormat.YUV422Packed:
            return cv2.cvtColor(image, cv2.COLOR_YUV2RGB_Y422)
        case ImageFormat.YUV422_YUYV_Packed:
            return cv2.cvtColor(image, cv2.COLOR_YUV2RGB_YUYV)
        case _:
            raise ValueError(f"Unsupported image format: {self.format}")

ImageSet dataclass

Data structure representing an ImageSet payload containing multiple images. Fields: version (str): Version of the ImageSet payload. cameraid (str): Unique identifier for the camera. timestamp (datetime): Timestamp when the ImageSet was created. detail (List[ImageDetails]): List of ImageDetails objects representing the images in the set. count (int): Number of images in the ImageSet.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
@dataclass
class ImageSet:
    """Data structure representing an ImageSet payload containing multiple images.
    Fields:
        version (str): Version of the ImageSet payload.
        cameraid (str): Unique identifier for the camera.
        timestamp (datetime): Timestamp when the ImageSet was created.
        detail (List[ImageDetails]): List of ImageDetails objects representing the images in the set.
        count (int): Number of images in the ImageSet.
    """

    version: str = field(default="1.0")
    cameraid: str = field(default_factory=lambda: str(uuid.uuid4()))
    timestamp: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
    detail: List[ImageDetails] = field(default_factory=list)

    count: int = field(default=0)

    def __post_init__(self):
        self.count = len(self.detail)

    def add_image(self, image: ImageDetails):
        """Adds an ImageDetails object to the ImageSet.
        Args:
            image (ImageDetails): ImageDetails object to add.
        """
        self.detail.append(image)
        self.count += 1

    def get_image_array(self, index: int = 0) -> np.ndarray:
        """Returns the image at the specified index as a NumPy array.
        Args:
            index (int): Index of the image to retrieve (default: 0).
        Raises:
            IndexError: If the index is out of range.
        Returns: np.ndarray: Image as a NumPy array.
        """
        if index < 0 or index >= len(self.detail):
            raise IndexError("Index out of range")

        image = self.detail[index].get_image_array()

        return image

    def get_image_rgb(self, index: int = 0) -> np.ndarray:
        """Returns the image at the specified index converted to RGB format as a NumPy array.
        Args:
            index (int): Index of the image to retrieve (default: 0).
        Raises:
            IndexError: If the index is out of range.
        Returns: np.ndarray: Image in RGB format as a NumPy array.
        """
        if index < 0 or index >= len(self.detail):
            raise IndexError("Index out of range")

        return self.detail[index].get_image_rgb()

    def to_dict(self):
        """Converts the ImageSet object to a dictionary.
        Returns:
            dict: Dictionary representation of the ImageSet object.
        """
        return {
            "version": self.version,
            "count": self.count,
            "cameraid": str(self.cameraid),
            "timestamp": format_aiis_timestamp(self.timestamp),
            "detail": [image.to_dict() for image in self.detail]
        }

    @staticmethod
    def from_dict(data: dict):
        """Creates an ImageSet object from a dictionary payload.
        Args:
            data (dict): Dictionary containing ImageSet data.
        Raises:
            ValueError: If there is an error parsing the ImageSet data.
        Returns: ImageSet: Parsed ImageSet object.
        """
        detail = data.get("detail", [])
        return ImageSet(
            version=data.get("version", "1.0"),
            count=data.get("count", len(detail)),
            cameraid=data.get("cameraid", str(uuid.uuid4())),
            timestamp=parse_aiis_timestamp(data.get("timestamp")),
            detail=[ImageDetails.from_dict(image) for image in detail]
        )

add_image(image)

Adds an ImageDetails object to the ImageSet. Args: image (ImageDetails): ImageDetails object to add.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
def add_image(self, image: ImageDetails):
    """Adds an ImageDetails object to the ImageSet.
    Args:
        image (ImageDetails): ImageDetails object to add.
    """
    self.detail.append(image)
    self.count += 1

get_image_array(index=0)

Returns the image at the specified index as a NumPy array. Args: index (int): Index of the image to retrieve (default: 0). Raises: IndexError: If the index is out of range. Returns: np.ndarray: Image as a NumPy array.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
def get_image_array(self, index: int = 0) -> np.ndarray:
    """Returns the image at the specified index as a NumPy array.
    Args:
        index (int): Index of the image to retrieve (default: 0).
    Raises:
        IndexError: If the index is out of range.
    Returns: np.ndarray: Image as a NumPy array.
    """
    if index < 0 or index >= len(self.detail):
        raise IndexError("Index out of range")

    image = self.detail[index].get_image_array()

    return image

get_image_rgb(index=0)

Returns the image at the specified index converted to RGB format as a NumPy array. Args: index (int): Index of the image to retrieve (default: 0). Raises: IndexError: If the index is out of range. Returns: np.ndarray: Image in RGB format as a NumPy array.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
def get_image_rgb(self, index: int = 0) -> np.ndarray:
    """Returns the image at the specified index converted to RGB format as a NumPy array.
    Args:
        index (int): Index of the image to retrieve (default: 0).
    Raises:
        IndexError: If the index is out of range.
    Returns: np.ndarray: Image in RGB format as a NumPy array.
    """
    if index < 0 or index >= len(self.detail):
        raise IndexError("Index out of range")

    return self.detail[index].get_image_rgb()

to_dict()

Converts the ImageSet object to a dictionary. Returns: dict: Dictionary representation of the ImageSet object.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
def to_dict(self):
    """Converts the ImageSet object to a dictionary.
    Returns:
        dict: Dictionary representation of the ImageSet object.
    """
    return {
        "version": self.version,
        "count": self.count,
        "cameraid": str(self.cameraid),
        "timestamp": format_aiis_timestamp(self.timestamp),
        "detail": [image.to_dict() for image in self.detail]
    }

from_dict(data) staticmethod

Creates an ImageSet object from a dictionary payload. Args: data (dict): Dictionary containing ImageSet data. Raises: ValueError: If there is an error parsing the ImageSet data. Returns: ImageSet: Parsed ImageSet object.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
@staticmethod
def from_dict(data: dict):
    """Creates an ImageSet object from a dictionary payload.
    Args:
        data (dict): Dictionary containing ImageSet data.
    Raises:
        ValueError: If there is an error parsing the ImageSet data.
    Returns: ImageSet: Parsed ImageSet object.
    """
    detail = data.get("detail", [])
    return ImageSet(
        version=data.get("version", "1.0"),
        count=data.get("count", len(detail)),
        cameraid=data.get("cameraid", str(uuid.uuid4())),
        timestamp=parse_aiis_timestamp(data.get("timestamp")),
        detail=[ImageDetails.from_dict(image) for image in detail]
    )

parse_aiis_timestamp(timestamp_str)

Parses a timestamp string from AI Inference Server format to a datetime object. Args: timestamp_str (str | None): Timestamp string in AI Inference Server format. Returns: datetime: Parsed datetime object.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
def parse_aiis_timestamp(timestamp_str: str | None) -> datetime:
    """Parses a timestamp string from AI Inference Server format to a datetime object.
    Args:
        timestamp_str (str | None): Timestamp string in AI Inference Server format.
    Returns: datetime: Parsed datetime object.
    """
    if timestamp_str is None or "" == timestamp_str.strip():
        return datetime.now(timezone.utc)
    timestamp_str = re.sub(r'[zZ]$', '+00:00', timestamp_str)
    return datetime.strptime(timestamp_str, DATE_TIME_FORMAT)

format_aiis_timestamp(timestamp)

Formats a datetime object to a timestamp string in AI Inference Server format. Args: timestamp (datetime | None): Datetime object to format. Returns: str: Formatted timestamp string.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/imageset.py
def format_aiis_timestamp(timestamp: datetime | None) -> str:
    """Formats a datetime object to a timestamp string in AI Inference Server format.
    Args:
        timestamp (datetime | None): Datetime object to format.
    Returns: str: Formatted timestamp string.
    """
    if timestamp is None:
        timestamp = datetime.now(timezone.utc)
    return re.sub(r'\+.*$','', timestamp.isoformat(timespec='milliseconds')) + 'Z'

Contains classes for defining pipeline variables and parameters, including their connections and mappings. PipelineVariable links a component's variable to a connection, while PipelineParameter defines parameters that can be set runtime. PipelineParameter can be topic-based, allowing dynamic updates via messaging topics. SecretPipelineParameter is a specialized parameter type for handling sensitive information.

MappableMixin

Mixin class providing mapping functionality for preconfiguration of Pipeline Variables and Parameters.

Attributes:

NameTypeDescription
connectionOptional[Connection]

The connection associated with the variable.

nameOptional[str]

The tag or camera name to map to.

mappingOptional[str]

The mapping to map to.

Methods:

NameDescription
add_mapping

Optional[str], cameraName: Optional[str], mapping: Optional[str]) -> Self: Adds mapping information to the variable.

add_connection

Connection) -> Self: Adds a connection to the variable.

add_mapping_with_connector

Connection, tagName: Optional[str], cameraName: Optional[str], mapping: Optional[str]) -> Self: Adds both mapping information and a connection to the variable.

_to_config_mapping

Returns the mapping configuration as a dictionary.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
class MappableMixin:
    """
    Mixin class providing mapping functionality for preconfiguration of Pipeline Variables and Parameters.

    Attributes:
        connection (Optional[Connection]): The connection associated with the variable.
        name (Optional[str]): The tag or camera name to map to.
        mapping (Optional[str]): The mapping to map to.

    Methods:
        add_mapping(tagName: Optional[str], cameraName: Optional[str], mapping: Optional[str]) -> Self:
            Adds mapping information to the variable.
        add_connection(connection: Connection) -> Self:
            Adds a connection to the variable.
        add_mapping_with_connector(connection: Connection, tagName: Optional[str], cameraName: Optional[str], mapping: Optional[str]) -> Self:
            Adds both mapping information and a connection to the variable.
        _to_config_mapping() -> dict:
            Returns the mapping configuration as a dictionary.

    """

    def __setattr__(self, name, value):
        """Handle setting of mapping-related attributes."""
        match name:
            case "connection":
                if value is not None and not isinstance(value, Connection):
                    raise ValueError("ERROR! 'connection' must be an instance of Connection or None.")
            case "tagName" | "cameraName" | "mapping":
                if hasattr(self, 'topicBased') and value is not None:
                    self.topicBased = True
                if name == "cameraName" and value is not None:
                    self.tagName = value
            case _:
                # Other attributes are handled by the dataclass
                pass

        super().__setattr__(name, value)

    def add_mapping(self, *, tagName: Optional[str] = None, cameraName: Optional[str] = None, mapping: Optional[str] = None):
        """
        Adds mapping information to the variable.
        Property 'tagName' is supposed to be used with message queues, while 'cameraName' with Vision Connector Application.
        In case you define both, only 'tagName' will be used and preconfigured.


        Args:
            tagName (Optional[str]): The tag name to map to.
            cameraName (Optional[str]): The camera name to map to.
            mapping (Optional[str]): The topic or camera id to map to.
        """
        self.tagName = tagName or cameraName
        self.mapping = mapping
        return self

    def add_connection(self, connection: Connection):
        """
        Adds a connection to the variable.
        Args:
            connection (Connection): The connection to add.
        """
        self.connection = connection
        return self

    def add_mapping_with_connection(self, connection: Connection, *, tagName: Optional[str] = None, cameraName: Optional[str] = None, mapping: Optional[str] = None):
        """
        Adds both mapping information and a connection to the variable.
        Property 'tagName' is supposed to be used with message queues, while 'cameraName' with Vision Connector Application.
        In case you define both, only 'tagName' will be used and preconfigured.

        Args:
            connection (Connection): The connection to add.
            tagName (Optional[str]): The tag name to map to.
            cameraName (Optional[str]): The camera name to map to.
            mapping (Optional[str]): The topic or camera id to map to.
        """
        self.add_connection(connection)
        self.add_mapping(tagName=tagName, cameraName=cameraName, mapping=mapping)
        return self

    def __mappable_dict__(self) -> dict:
        """Returns the mapping configuration as a dictionary."""
        json_dict = {}

        if self.connection is not None:
            for k, v in self.connection.__dict__().items():
                json_dict[k] = v

        if self.tagName is not None:
            json_dict['tagName'] = self.tagName
        if self.mapping is not None:
            json_dict['topic'] = self.mapping

        return json_dict

__setattr__(name, value)

Handle setting of mapping-related attributes.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
def __setattr__(self, name, value):
    """Handle setting of mapping-related attributes."""
    match name:
        case "connection":
            if value is not None and not isinstance(value, Connection):
                raise ValueError("ERROR! 'connection' must be an instance of Connection or None.")
        case "tagName" | "cameraName" | "mapping":
            if hasattr(self, 'topicBased') and value is not None:
                self.topicBased = True
            if name == "cameraName" and value is not None:
                self.tagName = value
        case _:
            # Other attributes are handled by the dataclass
            pass

    super().__setattr__(name, value)

add_mapping(*, tagName=None, cameraName=None, mapping=None)

Adds mapping information to the variable. Property 'tagName' is supposed to be used with message queues, while 'cameraName' with Vision Connector Application. In case you define both, only 'tagName' will be used and preconfigured.

Parameters:

NameTypeDescriptionDefault
tagNameOptional[str]

The tag name to map to.

None
cameraNameOptional[str]

The camera name to map to.

None
mappingOptional[str]

The topic or camera id to map to.

None
Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
def add_mapping(self, *, tagName: Optional[str] = None, cameraName: Optional[str] = None, mapping: Optional[str] = None):
    """
    Adds mapping information to the variable.
    Property 'tagName' is supposed to be used with message queues, while 'cameraName' with Vision Connector Application.
    In case you define both, only 'tagName' will be used and preconfigured.


    Args:
        tagName (Optional[str]): The tag name to map to.
        cameraName (Optional[str]): The camera name to map to.
        mapping (Optional[str]): The topic or camera id to map to.
    """
    self.tagName = tagName or cameraName
    self.mapping = mapping
    return self

add_connection(connection)

Adds a connection to the variable. Args: connection (Connection): The connection to add.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
def add_connection(self, connection: Connection):
    """
    Adds a connection to the variable.
    Args:
        connection (Connection): The connection to add.
    """
    self.connection = connection
    return self

add_mapping_with_connection(connection, *, tagName=None, cameraName=None, mapping=None)

Adds both mapping information and a connection to the variable. Property 'tagName' is supposed to be used with message queues, while 'cameraName' with Vision Connector Application. In case you define both, only 'tagName' will be used and preconfigured.

Parameters:

NameTypeDescriptionDefault
connectionConnection

The connection to add.

required
tagNameOptional[str]

The tag name to map to.

None
cameraNameOptional[str]

The camera name to map to.

None
mappingOptional[str]

The topic or camera id to map to.

None
Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
def add_mapping_with_connection(self, connection: Connection, *, tagName: Optional[str] = None, cameraName: Optional[str] = None, mapping: Optional[str] = None):
    """
    Adds both mapping information and a connection to the variable.
    Property 'tagName' is supposed to be used with message queues, while 'cameraName' with Vision Connector Application.
    In case you define both, only 'tagName' will be used and preconfigured.

    Args:
        connection (Connection): The connection to add.
        tagName (Optional[str]): The tag name to map to.
        cameraName (Optional[str]): The camera name to map to.
        mapping (Optional[str]): The topic or camera id to map to.
    """
    self.add_connection(connection)
    self.add_mapping(tagName=tagName, cameraName=cameraName, mapping=mapping)
    return self

__mappable_dict__()

Returns the mapping configuration as a dictionary.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
def __mappable_dict__(self) -> dict:
    """Returns the mapping configuration as a dictionary."""
    json_dict = {}

    if self.connection is not None:
        for k, v in self.connection.__dict__().items():
            json_dict[k] = v

    if self.tagName is not None:
        json_dict['tagName'] = self.tagName
    if self.mapping is not None:
        json_dict['topic'] = self.mapping

    return json_dict

PipelineVariable dataclass

Bases: MappableMixin

Represents a variable in a pipeline, linking a component's variable to a connection and optional mapping. For IE Vision connections, cameraName should be defined, otherwise tagName is preferred.

Attributes:

NameTypeDescription
componentNamestr

The name of the component the variable belongs to.

variableNamestr

The name of the variable.

connectionOptional[Connection]

The connection associated with the variable.

tagNameOptional[str]

The tag name to map to.

cameraNameOptional[str]

The camera name to map to. Used only via IE_Vision connection.

mappingOptional[str]

The topic or camera id to map to.

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
@dataclass
class PipelineVariable(MappableMixin):
    """
    Represents a variable in a pipeline, linking a component's variable to a connection and optional mapping.
    For IE Vision connections, cameraName should be defined, otherwise tagName is preferred.

    Attributes:
        componentName (str): The name of the component the variable belongs to.
        variableName (str): The name of the variable.

        connection (Optional[Connection]): The connection associated with the variable.
        tagName (Optional[str]): The tag name to map to.
        cameraName (Optional[str]): The camera name to map to. Used only via IE_Vision connection.
        mapping (Optional[str]): The topic or camera id to map to.
    """
    componentName: str
    variableName: str

    # Mixin fields as dataclass fields
    connection: Optional[Connection] = field(default=None)
    tagName: Optional[str] = field(default=None)
    cameraName: Optional[str] = field(default=None)
    mapping: Optional[str] = field(default=None)

    def check_connection_type_compatibility(self, variable_type: str) -> tuple[list, list]:
        if self.connection is None:
            return [], []
        supported_types = SUPPORTED_TYPES_BY_CONNECTION.get(self.connection.cptype, [])
        flags = type_validation_flags(variable_type, supported_types)
        if self.connection.cptype == ConnectionTypeAndPayloadFormat.Realtime_Backbone:
            warning_flags = []
            error_flags = [f.value for f in flags]
        else:
            warning_flags = [f.value for f in flags if f != TypeValidationFlags.ARRAY_WITH_MISSING_SIZE]
            error_flags = []
        return warning_flags, error_flags

    def __getitem__(self, item):
        return getattr(self, item)

    def __setattr__(self, name, value):
        """
        Setter for all attributes
        """
        match name:
            case "componentName":
                if re.match("^[a-zA-Z0-9_-]+$", value) is None:
                    raise ValueError(f"ERROR! Invalid name '{value}'. Only alphanumeric characters and underscores are allowed.")
            case "variableName":
                if re.match("^[a-zA-Z0-9_-]+$", value) is None:
                    raise ValueError(f"ERROR! Invalid name '{value}'. Only alphanumeric characters and underscores are allowed.")
                if value in reserved_names:
                    raise ValueError(f"ERROR! '{value}' is a reserved name and cannot be used as variable name.")
            case _:
                # Let the mixin handle mapping attributes
                pass

        super().__setattr__(name, value)

    def __dict__(self, component_io_list: list) -> dict:
        json_dict = {
            "name": self.variableName,
            "type": component_io_list[self.variableName]['type']
        }

        json_dict.update(self.__mappable_dict__())

        return json_dict

__setattr__(name, value)

Setter for all attributes

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
def __setattr__(self, name, value):
    """
    Setter for all attributes
    """
    match name:
        case "componentName":
            if re.match("^[a-zA-Z0-9_-]+$", value) is None:
                raise ValueError(f"ERROR! Invalid name '{value}'. Only alphanumeric characters and underscores are allowed.")
        case "variableName":
            if re.match("^[a-zA-Z0-9_-]+$", value) is None:
                raise ValueError(f"ERROR! Invalid name '{value}'. Only alphanumeric characters and underscores are allowed.")
            if value in reserved_names:
                raise ValueError(f"ERROR! '{value}' is a reserved name and cannot be used as variable name.")
        case _:
            # Let the mixin handle mapping attributes
            pass

    super().__setattr__(name, value)

PipelineParameter dataclass

Bases: MappableMixin

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
@dataclass
class PipelineParameter(MappableMixin):
    name: str
    defaultValue: Optional[str] = None
    dtype: Optional[str] = None  # 'String', 'Integer', 'Float', 'Boolean'
    description: Optional[str] = None
    topicBased: Optional[bool] = False
    valueTopic: Optional[str] = None

    # Mixin fields as dataclass fields
    connection: Optional[Connection] = field(default=None)
    tagName: Optional[str] = field(default=None)
    mapping: Optional[str] = field(default=None)

    def __post_init__(self):
        # Validate if the topicBased flag is False, then valueTopic, connection, tag, and topic should not be set
        if not self.topicBased and (self.valueTopic is not None or self.connection is not None or self.tagName is not None or self.mapping is not None):
            raise ValueError("ERROR! 'valueTopic', 'connection', 'tag', and 'topic' must be None when 'topicBased' is False.")
        if self.dtype != _get_is_type(type(self.defaultValue)):
            raise ValueError(f"'The given value type does not match the type of defaultValue: '{self.defaultValue}'")

    def __setattr__(self, name, value):
        """
        Setter for all attributes
        """
        match name:
            case "name":
                _check_name_validity(value)
            case "dtype":
                if value is None:
                    return
                elif value not in ['String', 'Integer', 'Double', 'Boolean']:
                    raise ValueError("ERROR! 'dtype' must be one of 'String', 'Integer', 'Double', 'Boolean', or None.")
            case "defaultValue":
                dtype = _get_is_type(type(value))
                if dtype is None:
                    raise ValueError("ERROR! 'dtype' must be one of 'String', 'Integer', 'Double', 'Boolean', or None.")
                self.dtype = dtype
            case "description":
                _check_description_validity(value)
            case "topicBased":
                if not isinstance(value, bool):
                    raise ValueError("Type of the given `topic_based` parameter is not `bool`")
            case "valueTopic":
                if not (value is None or value == ""):
                    self.topicBased = True
            case _:
                # Let the mixin handle mapping attributes
                pass

        super().__setattr__(name, value)

    def has_valid_connection(self) -> set:
        if self.connection is None:
            return True
        supported_types = SUPPORTED_TYPES_BY_CONNECTION.get(self.connection.cptype, [])
        return type_validation_flags(self.dtype, supported_types) == set()

    def __param_dict__(self) -> dict:
        json_dict = {
            'name': self.name,
            'defaultValue': self.defaultValue,
            'dtype': self.dtype
        }

        json_dict.update(self.__mappable_dict__())

        json_dict['type'] = json_dict.pop('dtype', None)
        if self.topicBased:
            json_dict['topicBased'] = True
            json_dict['valueTopic'] = json_dict.pop('topic', None)

        return json_dict

__setattr__(name, value)

Setter for all attributes

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
def __setattr__(self, name, value):
    """
    Setter for all attributes
    """
    match name:
        case "name":
            _check_name_validity(value)
        case "dtype":
            if value is None:
                return
            elif value not in ['String', 'Integer', 'Double', 'Boolean']:
                raise ValueError("ERROR! 'dtype' must be one of 'String', 'Integer', 'Double', 'Boolean', or None.")
        case "defaultValue":
            dtype = _get_is_type(type(value))
            if dtype is None:
                raise ValueError("ERROR! 'dtype' must be one of 'String', 'Integer', 'Double', 'Boolean', or None.")
            self.dtype = dtype
        case "description":
            _check_description_validity(value)
        case "topicBased":
            if not isinstance(value, bool):
                raise ValueError("Type of the given `topic_based` parameter is not `bool`")
        case "valueTopic":
            if not (value is None or value == ""):
                self.topicBased = True
        case _:
            # Let the mixin handle mapping attributes
            pass

    super().__setattr__(name, value)

SecretPipelineParameter dataclass

Represents a secret pipeline parameter for handling sensitive information. Cannot be modified after creation.

Attributes:

NameTypeDescription
namestr

The name of the secret parameter.

descriptionOptional[str]

An optional description of the secret parameter.

defaultValuestr

Pipeline parameters must have a default value, which is an empty string for secret parameters.

dtypestr

The data type of the secret parameter is always "Secret".

Source code in docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.py
@dataclass(frozen=True)
class SecretPipelineParameter:
    """
    Represents a secret pipeline parameter for handling sensitive information.
    Cannot be modified after creation.

    Attributes:
        name (str): The name of the secret parameter.
        description (Optional[str]): An optional description of the secret parameter.
        defaultValue (str): Pipeline parameters must have a default value, which is an empty string for secret parameters.
        dtype (str): The data type of the secret parameter is always "Secret".
    """

    name: str
    description: Optional[str] = None
    defaultValue: str = field(init=False, default="")
    dtype: str = field(init=False, default="Secret")

    def __post_init__(self):
        _check_name_validity(self.name)
        _check_description_validity(self.description)

    def __param_dict__(self) -> dict:
        json_dict = {
            'name': self.name,
            'defaultValue': "",
            'type': self.dtype
        }
        return json_dict