payloads¶
Connection dataclass ¶
Represents a connection with a name and an optional predefined combination of connection type and payload format.
Attributes:
| Name | Type | Description |
|---|---|---|
name | str | The name of the connection. |
cptype | Optional[ConnectionTypeAndPayloadFormat] | The connection type and payload format, represented as an Enum. |
Methods:
| Name | Description |
|---|---|
__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 attributesSource code in
docs/industrial-ai-suite/sdk/simaticai/payloads/connection.pydef __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:
| Name | Type | Description |
|---|---|---|
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") |
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:
| Name | Type | Description |
|---|---|---|
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. |
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 attributesSource code in
docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.pydef __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: MappableMixinSource 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 attributesSource code in
docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.pydef __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:
| Name | Type | Description |
|---|---|---|
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". |
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:
| Name | Type | Description |
|---|---|---|
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") |
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:
| Name | Type | Description |
|---|---|---|
name | str | The name of the connection. |
cptype | Optional[ConnectionTypeAndPayloadFormat] | The connection type and payload format, represented as an Enum. |
Methods:
| Name | Description |
|---|---|
__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 attributesSource code in
docs/industrial-ai-suite/sdk/simaticai/payloads/connection.pydef __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.pyclass 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:
| Name | Type | Description | Default |
|---|---|---|---|
data | dict | 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:
| Name | Type | Description |
|---|---|---|
dict | dict | 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.pydef 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.pydef 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.pydef 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.pydef 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.pydef 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.pydef 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.pydef 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.pydef 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.pydef 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:
| Name | Type | Description |
|---|---|---|
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:
| Name | Description |
|---|---|
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.pydef __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:
| Name | Type | Description | Default |
|---|---|---|---|
tagName | Optional[str] | The tag name to map to. | None |
cameraName | Optional[str] | The camera name to map to. | None |
mapping | Optional[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.pydef 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:
| Name | Type | Description | Default |
|---|---|---|---|
connection | Connection | The connection to add. | required |
tagName | Optional[str] | The tag name to map to. | None |
cameraName | Optional[str] | The camera name to map to. | None |
mapping | Optional[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.pydef __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:
| Name | Type | Description |
|---|---|---|
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. |
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 attributesSource code in
docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.pydef __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: MappableMixinSource 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 attributesSource code in
docs/industrial-ai-suite/sdk/simaticai/payloads/pipeline_variable.pydef __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:
| Name | Type | Description |
|---|---|---|
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". |
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