import abc
import logging
import basyx.aas.model
from basyx.aas.model import SubmodelElementList, SubmodelElement, Operation, Submodel, RelationshipElement, \
AnnotatedRelationshipElement, BasicEventElement, SubmodelElementCollection, Property, MultiLanguageProperty, \
Range, Blob, File, ReferenceElement, Capability
from smia.aas_model.extended_aas import ExtendedGeneralMethods
from smia.logic.exceptions import AASModelOntologyError, AASModelReadingError
from smia.css_ontology.css_ontology_utils import CapabilitySkillOntologyInfo
from smia.utilities.smia_info import AssetInterfacesInfo
_logger = logging.getLogger(__name__)
[docs]
class ExtendedSubmodel(Submodel):
"""This class contains methods to be added to Submodel class of Basyx Python SDK model."""
[docs]
class ExtendedSubmodelElement(SubmodelElement):
"""This class contains methods to be added to SubmodelElement class of Basyx Python SDK model."""
[docs]
def get_qualifier_by_semantic_id(self, semantic_id_reference):
if self.qualifier is None:
return None
else:
for qualifier in self.qualifier:
if qualifier.check_semantic_id_exist(semantic_id_reference):
return qualifier
return None
[docs]
def get_parent_submodel(self):
"""
This method gets the submodel where the self SubmodelElement is defined.
Returns:
basyx.aas.model.Submodel: parent submodel in form of a Python object.
"""
if isinstance(self.parent, basyx.aas.model.Submodel):
return self.parent
else:
return self.parent.get_parent_submodel()
[docs]
def check_cap_skill_ontology_semantics_and_qualifiers(self):
"""
This method checks if the SubmodelElement of the Skill has the required semanticIDs and qualifiers defined in
the Capability-Skill ontology.
Returns:
bool: result of the check (only True if both semanticIDs and qualifiers of Capability-Skill ontology exist).
"""
# It will be checked if the semantic id of the skill is valid within the ontology
if self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_SKILL_IRI) is False:
_logger.error("The skill {} has not valid semanticID regarding the "
"Capability-Skill ontology.".format(self))
return False
if self.check_cap_skill_ontology_qualifier_for_skills() is False:
_logger.error("The skill {} has not valid qualifiers regarding the "
"Capability-Skill ontology.".format(self))
return False
return True
[docs]
def check_cap_skill_ontology_qualifier_for_skills(self):
"""
This method checks if the SubmodelElement of the Skill has valid qualifiers defined in the Capability-Skil
ontology.
Returns:
bool: result of the check (only True if the qualifier of Capability-Skill ontology exists).
"""
skill_qualifier = self.get_qualifier_by_type('SkillImplementationType')
if skill_qualifier is not None:
if skill_qualifier.value in ['STATE', 'TRIGGER', 'OPERATION', 'FUNCTIONBLOCK']:
return True
_logger.error("ERROR: the qualifier is not valid in the skill {}".format(self))
return False
[docs]
def get_parent_ref_by_semantic_id(self, semantic_id):
"""
This method gets the reference of a parent element of the SubmodelElement by the semanticID.
Args:
semantic_id (str): semantic identifier of the parent element.
Returns:
basyx.aas.model.ModelReference: model reference of the parent element (None if the parent does not exist)
"""
parent_elem = self.parent
while parent_elem:
if parent_elem.check_semantic_id_exist(semantic_id):
return basyx.aas.model.ModelReference.from_referable(parent_elem)
else:
parent_elem = parent_elem.parent
return None
[docs]
class ExtendedRelationshipElement(RelationshipElement):
[docs]
class ExtendedAnnotatedRelationshipElement(AnnotatedRelationshipElement):
[docs]
def check_cap_skill_ontology_semantic_id(self):
"""
This method checks if the Capability has one of the required semanticIDs defined in the Capability-Skill
ontology, exactly for Capabilities.
Returns:
bool: result of the check (only True if the semanticID of Capability-Skill ontology exists).
"""
if ((self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_CAPABILITY_IRI))
or (self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_ASSET_CAPABILITY_IRI))
or (self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_AGENT_CAPABILITY_IRI))):
return True
else:
_logger.error("ERROR: the capability is not valid within the ontology.")
return False
[docs]
def check_cap_skill_ontology_qualifiers(self):
"""
This method checks if the Capability has valid qualifiers, defined in the Capability-Skil ontology.
Returns:
bool: result of the check (only True if the qualifier of Capability-Skill ontology exists).
"""
capability_qualifier = self.get_qualifier_by_type('ExpressionSemantic')
if capability_qualifier is not None:
if capability_qualifier.value in ['REQUIREMENT', 'OFFER', 'ASSURANCE']:
return True
_logger.error("ERROR: the qualifier is not valid in the capability {}".format(self))
return False
[docs]
def get_capability_type_in_ontology(self):
"""
This method gets the type of the capability within the Capability-Skill ontology.
Returns:
str: value of the type of the capability within the Capability-Skill ontology.
"""
if self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_CAPABILITY_IRI):
return 'ManufacturingCapability'
elif self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_ASSET_CAPABILITY_IRI):
return 'AssetCapability'
elif self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_AGENT_CAPABILITY_IRI):
return 'AgentCapability'
else:
_logger.error("ERROR: the capability type is not valid within the ontology.")
return None
[docs]
def get_semantic_id_of_css_ontology(self):
"""
This method gets the semanticID of the capability within the Capability-Skill ontology.
Returns:
str: value of the semanticID of the capability within the Capability-Skill ontology.
"""
if self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_CAPABILITY_IRI):
return CapabilitySkillOntologyInfo.CSS_ONTOLOGY_CAPABILITY_IRI
elif self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_AGENT_CAPABILITY_IRI):
return CapabilitySkillOntologyInfo.CSS_ONTOLOGY_AGENT_CAPABILITY_IRI
elif self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_ASSET_CAPABILITY_IRI):
return CapabilitySkillOntologyInfo.CSS_ONTOLOGY_ASSET_CAPABILITY_IRI
else:
raise AASModelOntologyError("The capability {} does not have a valid semanticID within the "
"ontology.".format(self.id_short), self, "OntologySemanticIdMissing")
[docs]
class ExtendedOperation(Operation):
[docs]
def get_variable_value_id(self, value_id):
"""
This method gets the variable of the Operation that matches with the given valueId.
Args:
value_id (str): the value id of the variable to find.
Returns:
(str): id_short of the variable
"""
all_variables = [self.input_variable, self.output_variable, self.in_output_variable]
for var_type_set in all_variables:
for var in var_type_set:
if var.value_id:
for key in var.value_id.key:
if key.value == value_id:
return var.id_short
return None
[docs]
def get_operation_variables_by_semantic_id(self, semantic_id):
"""
This method gets all operation variables that have the given semanticID.
Args:
semantic_id (str): semantic identifier of the operation variables to find.
Returns:
list: all valid operation variables in form of a list of SubmodelElements.
"""
operation_variables = []
all_var_sets = [self.input_variable, self.output_variable, self.in_output_variable]
for var_set in all_var_sets:
for operation_variable in var_set:
if operation_variable.check_semantic_id_exist(semantic_id):
operation_variables.append(operation_variable)
return operation_variables
[docs]
class ExtendedBasicEventElement(BasicEventElement):
# TODO
[docs]
class ExtendedEntity:
# class ExtendedEntity(Entity):
[docs]
class ExtendedSubmodelElementList(SubmodelElementList):
# TODO
[docs]
class ExtendedSubmodelElementCollection(SubmodelElementCollection):
[docs]
def get_sm_element_by_id_short(self, id_short):
"""
This method gets a submodel element inside a SubmodelElementCollection by its id_short.
Args:
id_short (str): id_short of the submodel element to find.
Returns:
basyx.aas.model.SubmodelElement: submodel element in form of Python object.
"""
return self.value.get('id_short', id_short)
[docs]
def get_sm_element_by_semantic_id(self, semantic_id_ref):
"""
This method gets a submodel element inside a SubmodelElementCollection by its semantic identifier.
Args:
semantic_id_ref (str): semantic identifier of the submodel element to find.
Returns:
basyx.aas.model.SubmodelElement: submodel element in form of Python object.
"""
for sm_elem in self.value:
for reference in sm_elem.semantic_id.key:
if reference.value == semantic_id_ref:
return sm_elem
return None
# ------------
# DataElements
# ------------
[docs]
class ExtendedProperty(Property):
"""This class contains methods to be added to Property class of Basyx Python SDK model."""
[docs]
class ExtendedMultiLanguageProperty(MultiLanguageProperty):
[docs]
class ExtendedRange(Range):
# TODO
[docs]
class ExtendedBlob(Blob):
# TODO
[docs]
class ExtendedFile(File):
[docs]
class ExtendedReferenceElement(ReferenceElement):
# TODO
# CLASSES FOR CSS ONTOLOGY-BASED SOFTWARE
# ----------------------------------------
[docs]
class ExtendedGenericCSSClass(metaclass=abc.ABCMeta):
[docs]
def add_old_sme_class(self, sme_class):
"""
This method adds the old Basyx SubmodelElement class to be stored to the correct execution of the software.
Args:
sme_class (basyx.aas.model.SubmodelElement): old submodel element class in BaSyx Python structure.
"""
self.old_sme_class = sme_class
# if issubclass(self.old_sme_class, basyx.aas.model.Operation):
# print("Antes la Skill era una Operation")
# if issubclass(self.old_sme_class, basyx.aas.model.SubmodelElement):
# print("Antes la Skill era una SubmodelElement")
[docs]
def get_semantic_id_of_css_ontology(self):
"""
This method checks the semanticID of the skill within the Capability-Skill ontology.
"""
pass
[docs]
class ExtendedCapability(ExtendedGenericCSSClass, Capability):
[docs]
def check_cap_skill_ontology_semantics_and_qualifiers(self):
"""
This method checks if the Capability has the required semanticIDs and qualifiers defined in the Capability-Skill
ontology, exactly for Capabilities.
Returns:
bool: result of the check (only True if both semanticIDs and qualifiers of Capability-Skill ontology exist).
"""
# It will be checked if the semantic id of the capability is valid within the ontology
if self.check_cap_skill_ontology_semantic_id() is False:
_logger.error("The capability {} has not valid semanticID regarding the "
"Capability-Skill ontology.".format(self))
return False
# It will also be checked if it has any of the qualifiers defined in the ontology for the capabilities
if self.check_cap_skill_ontology_qualifiers() is False:
_logger.error("The capability {} has not valid qualifiers regarding the "
"Capability-Skill ontology.".format(self))
return False
return True
[docs]
class ExtendedSkill(ExtendedGenericCSSClass):
# TODO se ha tenido que separar las skills simples (Operation,Event...) de las complejas (Submodel). De
# momento estas no se han implementado pero en el White paper de PLattform Industrie se menciona que las Skills
# se pueden implementar mediante FunctionBlock (Submodelo)
pass
[docs]
class ExtendedSkillInterface(ExtendedGenericCSSClass):
# TODO se ha tenido que separar las skills interfaces simples (Operation,Event...) de las complejas (SMC). De
# momento se tienen ambas opciones ya que las interfaces de servicios de activos son SMC y las de los servicios de
# agente son simples
[docs]
def get_associated_asset_interface(self):
"""
This method gets the asset interface AAS SubmodelElement associated with this skill interface.
Returns:
basyx.aas.model.SubmodelElement: submodel element of the asset interface.
"""
pass
[docs]
class ExtendedCapabilityConstraint(ExtendedGenericCSSClass, ExtendedSubmodelElement, ExtendedProperty):
[docs]
def get_semantic_id_of_css_ontology(self):
"""
This method checks the semanticID of the skill within the Capability-Skill ontology.
"""
if not self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_CAPABILITY_CONSTRAINT_IRI):
raise AASModelOntologyError("The skill {} does not have the valid semanticID within the "
"ontology.".format(self.id_short), self, "OntologySemanticIdMissing")
[docs]
class ExtendedSimpleSkill(ExtendedSkill, ExtendedSubmodelElement, ExtendedOperation):
[docs]
def get_semantic_id_of_css_ontology(self):
"""
This method checks the semanticID of the skill within the Capability-Skill ontology.
"""
if not self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_SKILL_IRI):
raise AASModelOntologyError("The skill {} does not have the valid semanticID within the "
"ontology.".format(self.id_short), self, "OntologySemanticIdMissing")
[docs]
class ExtendedComplexSkill(ExtendedSkill, ExtendedSubmodel):
[docs]
def get_semantic_id_of_css_ontology(self):
"""
This method checks the semanticID of the skill within the Capability-Skill ontology.
"""
if not self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_SKILL_IRI):
raise AASModelOntologyError("The skill {} does not have the valid semanticID within the "
"ontology.".format(self.id_short), self, "OntologySemanticIdMissing")
[docs]
class ExtendedSkillParameter(ExtendedGenericCSSClass, ExtendedProperty):
pass
[docs]
class ExtendedSimpleSkillInterface(ExtendedSkillInterface, ExtendedOperation, ExtendedSubmodelElement):
[docs]
def get_semantic_id_of_css_ontology(self):
"""
This method checks the semanticID of the skill within the Capability-Skill ontology.
"""
if not self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_SKILL_INTERFACE_IRI):
raise AASModelOntologyError("The skill {} does not have the valid semanticID within the "
"ontology.".format(self.id_short), self, "OntologySemanticIdMissing")
[docs]
class ExtendedComplexSkillInterface(ExtendedSkillInterface, ExtendedSubmodelElementCollection):
[docs]
def get_semantic_id_of_css_ontology(self):
"""
This method checks the semanticID of the skill within the Capability-Skill ontology.
"""
if not self.check_semantic_id_exist(CapabilitySkillOntologyInfo.CSS_ONTOLOGY_SKILL_INTERFACE_IRI):
raise AASModelOntologyError("The skill {} does not have the valid semanticID within the "
"ontology.".format(self.id_short), self, "OntologySemanticIdMissing")
[docs]
def get_associated_asset_interface(self):
"""
This method gets the asset interface AAS SubmodelElement associated with this skill interface.
Returns:
basyx.aas.model.SubmodelElement: submodel element of the asset interface.
"""
#
asset_interface_elem = self.get_parent_ref_by_semantic_id(AssetInterfacesInfo.SEMANTICID_INTERFACE)
if asset_interface_elem is None:
raise AASModelReadingError("The skill interface is not inside the AssetInterfaceSubmodel.", self,
"SubmodelElementNotInValidSubmodel")
return asset_interface_elem