Created mapper
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
import { types } from "@aas-core-works/aas-core3.0-typescript";
|
import { types } from "@aas-core-works/aas-core3.0-typescript";
|
||||||
|
import { RelationshipElement } from "@aas-core-works/aas-core3.0-typescript/dist/types/types";
|
||||||
|
import { ResolvedRelationshipElement } from "types/common";
|
||||||
|
|
||||||
const GLOBALLY_IDENTIFIABLES = [types.KeyTypes.GlobalReference, types.KeyTypes.AssetAdministrationShell, types.KeyTypes.ConceptDescription, types.KeyTypes.Identifiable, types.KeyTypes.Submodel]
|
const GLOBALLY_IDENTIFIABLES = [types.KeyTypes.GlobalReference, types.KeyTypes.AssetAdministrationShell, types.KeyTypes.ConceptDescription, types.KeyTypes.Identifiable, types.KeyTypes.Submodel]
|
||||||
|
|
||||||
@@ -40,6 +42,14 @@ export default class Traverser {
|
|||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static resolveRelationship(env: types.Environment, relationship: RelationshipElement): ResolvedRelationshipElement | null {
|
||||||
|
const first = Traverser.resolveReference(env, relationship.first);
|
||||||
|
const second = Traverser.resolveReference(env, relationship.second);
|
||||||
|
|
||||||
|
if (first === null || second === null) return null;
|
||||||
|
return { first, second };
|
||||||
|
}
|
||||||
|
|
||||||
public static traverseByShortIds(start: types.Class, shortIds: string[]): types.Class | null {
|
public static traverseByShortIds(start: types.Class, shortIds: string[]): types.Class | null {
|
||||||
let current: types.Class | null = start;
|
let current: types.Class | null = start;
|
||||||
for (const shortId of shortIds) {
|
for (const shortId of shortIds) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type { Request } from "types/requests";
|
|||||||
import type InterfaceConnectionObject from "interfaceConnectionObject";
|
import type InterfaceConnectionObject from "interfaceConnectionObject";
|
||||||
import Traverser from "./helper/traverser";
|
import Traverser from "./helper/traverser";
|
||||||
import type { AIMCMapper } from "./parser/AIMCMapper";
|
import type { AIMCMapper } from "./parser/AIMCMapper";
|
||||||
import { AssetInterfaceDescription } from "types/aidConf";
|
import { AssetInterfacesDescription } from "types/aidConf";
|
||||||
import AIDParser from "./parser/AIDParser";
|
import AIDParser from "./parser/AIDParser";
|
||||||
|
|
||||||
type AASRegistration = {
|
type AASRegistration = {
|
||||||
|
|||||||
+12
-10
@@ -1,15 +1,15 @@
|
|||||||
import * as aasCore from "@aas-core-works/aas-core3.0-typescript";
|
import * as aasCore from "@aas-core-works/aas-core3.0-typescript";
|
||||||
import type { AssetInterfaceDescription, EndpointMetadata, InterfaceDescription, InterfaceMetadata, InterfaceAction, InterfaceEvent, InterfaceProperty, InterfacePropertyForm } from "types/aidConf";
|
import type { AssetInterfacesDescription, EndpointMetadata, InterfaceDescription, InterfaceMetadata, InterfaceAction, InterfaceEvent, InterfaceProperty, InterfacePropertyForm } from "types/aidConf";
|
||||||
import { AvailableEndpoint, endpointAvailable } from "../types/common";
|
import { AvailableEndpoint, endpointAvailable } from "../types/common";
|
||||||
import Traverser from "../helper/traverser";
|
import Traverser from "../helper/traverser";
|
||||||
|
|
||||||
export default class AIDParser {
|
export default class AIDParser {
|
||||||
|
|
||||||
public static parse(env: aasCore.types.Environment): AssetInterfaceDescription | null {
|
public static parse(env: aasCore.types.Environment): AssetInterfacesDescription | null {
|
||||||
const sm = Traverser.findSMByIdShort(env, "AssetInterfaceDescription");
|
const sm = Traverser.findSMByIdShort(env, "AssetInterfaceDescription");
|
||||||
if (sm === null || sm.submodelElements === null) return null;
|
if (sm === null || sm.submodelElements === null) return null;
|
||||||
|
|
||||||
const parsed = {} as AssetInterfaceDescription;
|
const parsed = {} as AssetInterfacesDescription;
|
||||||
|
|
||||||
sm.submodelElements.forEach(e => {
|
sm.submodelElements.forEach(e => {
|
||||||
if (!aasCore.types.isSubmodelElementList(e) || !e.idShort || !e.value) return;
|
if (!aasCore.types.isSubmodelElementList(e) || !e.idShort || !e.value) return;
|
||||||
@@ -75,7 +75,7 @@ export default class AIDParser {
|
|||||||
|
|
||||||
const prop = Traverser.findElement(interfaceMeta, element => (element as any).idShort.toLocaleLowerCase() === "properties");
|
const prop = Traverser.findElement(interfaceMeta, element => (element as any).idShort.toLocaleLowerCase() === "properties");
|
||||||
if (prop === null || !aasCore.types.isSubmodelElementList(prop) || !prop.value) return null; // Mandatory
|
if (prop === null || !aasCore.types.isSubmodelElementList(prop) || !prop.value) return null; // Mandatory
|
||||||
for (const element of prop.value) {
|
for (const element of prop.overValueOrEmpty()) {
|
||||||
if (!aasCore.types.isSubmodelElementCollection(element)) continue;
|
if (!aasCore.types.isSubmodelElementCollection(element)) continue;
|
||||||
const parsedProp = AIDParser.parseInterfaceMetadataProperty(element, endpointProtocol);
|
const parsedProp = AIDParser.parseInterfaceMetadataProperty(element, endpointProtocol);
|
||||||
if (parsedProp === null) continue;
|
if (parsedProp === null) continue;
|
||||||
@@ -84,7 +84,7 @@ export default class AIDParser {
|
|||||||
|
|
||||||
const actions = Traverser.findElement(interfaceMeta, element => (element as any).idShort.toLocaleLowerCase() === "actions");
|
const actions = Traverser.findElement(interfaceMeta, element => (element as any).idShort.toLocaleLowerCase() === "actions");
|
||||||
if (actions === null || !aasCore.types.isSubmodelElementList(actions) || !actions.value) return null; // Mandatory
|
if (actions === null || !aasCore.types.isSubmodelElementList(actions) || !actions.value) return null; // Mandatory
|
||||||
for (const element of actions.value) {
|
for (const element of actions.overValueOrEmpty()) {
|
||||||
if (!aasCore.types.isSubmodelElementCollection(element)) continue;
|
if (!aasCore.types.isSubmodelElementCollection(element)) continue;
|
||||||
const parsedAction = AIDParser.parseInterfaceMetadataProperty(element, endpointProtocol);
|
const parsedAction = AIDParser.parseInterfaceMetadataProperty(element, endpointProtocol);
|
||||||
if (parsedAction === null) continue;
|
if (parsedAction === null) continue;
|
||||||
@@ -95,7 +95,7 @@ export default class AIDParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static parseInterfaceMetadataProperty(prop: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceProperty | null {
|
public static parseInterfaceMetadataProperty(prop: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceProperty | null {
|
||||||
if (!prop.value || prop.idShort?.toLocaleLowerCase() !== "properties") return null;
|
if (!aasCore.types.isSubmodelElementCollection(prop) || !prop.value || prop.idShort?.toLocaleLowerCase() !== "properties") return null;
|
||||||
|
|
||||||
const parsed = {} as InterfaceProperty;
|
const parsed = {} as InterfaceProperty;
|
||||||
|
|
||||||
@@ -106,19 +106,21 @@ export default class AIDParser {
|
|||||||
else parsed[key] = prop.value;
|
else parsed[key] = prop.value;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
|
const parsedForms = [] as InterfacePropertyForm[];
|
||||||
|
|
||||||
const forms = Traverser.findElement(prop, element => (element as any).idShort.toLocaleLowerCase() === "forms");
|
const forms = Traverser.findElement(prop, element => (element as any).idShort.toLocaleLowerCase() === "forms");
|
||||||
if (forms === null || !aasCore.types.isSubmodelElementList(forms) || !forms.value) return null; // Mandatory
|
if (forms === null || !aasCore.types.isSubmodelElementList(forms) || !forms.value) return null; // Mandatory
|
||||||
for (const element of forms.value) {
|
for (const element of forms.overValueOrEmpty()) {
|
||||||
if (!aasCore.types.isSubmodelElementCollection(element)) continue;
|
if (!aasCore.types.isSubmodelElementCollection(element)) continue;
|
||||||
const parsedForm = AIDParser.parseInterfaceMetadataPropertyForm(element, endpointProtocol);
|
const parsedForm = AIDParser.parseInterfaceMetadataPropertyForm(element, endpointProtocol);
|
||||||
if (parsedForm === null) continue;
|
if (parsedForm === null) continue;
|
||||||
parsed.forms.push(parsedForm);
|
parsedForms.push(parsedForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// Other values based on endpoint protocol
|
// Other values based on endpoint protocol
|
||||||
|
|
||||||
return parsed;
|
return { ...parsed, forms: parsedForms } as InterfaceProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static parseInterfaceMetadataPropertyForm(form: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfacePropertyForm | null {
|
private static parseInterfaceMetadataPropertyForm(form: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfacePropertyForm | null {
|
||||||
@@ -143,7 +145,7 @@ export default class AIDParser {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static parseInterfaceMetadataEvent(event: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceAction | null {
|
public static parseInterfaceMetadataEvent(event: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceEvent | null {
|
||||||
// TODO
|
// TODO
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,60 @@
|
|||||||
|
import { types } from "@aas-core-works/aas-core3.0-typescript";
|
||||||
|
import { ConnectionConfiguration, ElementMap } from "types/aimcConf";
|
||||||
|
import AIMCParser from "./AIMCParser";
|
||||||
|
import Traverser from "helper/traverser";
|
||||||
|
import AIDParser from "./AIDParser";
|
||||||
|
import { SubmodelElementCollection } from "@aas-core-works/aas-core3.0-typescript/dist/types/types";
|
||||||
|
|
||||||
export class AIMCMapper {
|
export class AIMCMapper {
|
||||||
|
|
||||||
|
private map: ElementMap = {};
|
||||||
|
|
||||||
|
public constructor(private readonly env: types.Environment) {
|
||||||
|
this.generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private generate(): void {
|
||||||
|
const aimc = AIMCParser.parse(this.env);
|
||||||
|
if (aimc === null) return;
|
||||||
|
|
||||||
|
for (const endpointConf of Object.values(aimc)) {
|
||||||
|
for (const entry of endpointConf) {
|
||||||
|
const ep = AIDParser.parseEndpointMetaData(entry.EndpointMetaDataReference);
|
||||||
|
if (ep === null) continue;
|
||||||
|
|
||||||
|
for (const mapping of entry.MappingConfiguration) {
|
||||||
|
//const ifm = AIDParser.parseInterfaceMetaData(mapping.InterfaceMetaDataReference);
|
||||||
|
//if (ifm === null) continue;
|
||||||
|
// Why do we need this? We already have the interface metadata reference in every ssm
|
||||||
|
|
||||||
|
for (const ssm of mapping.SourceSinkMappings) {
|
||||||
|
const resolved = Traverser.resolveRelationship(this.env, ssm);
|
||||||
|
if (resolved === null) continue;
|
||||||
|
|
||||||
|
const path = ssm.first.keys.join("/");
|
||||||
|
const parsedPropConf = AIDParser.parseInterfaceMetadataProperty(resolved.second as SubmodelElementCollection);
|
||||||
|
if (parsedPropConf === null) continue;
|
||||||
|
|
||||||
|
this.map[path] = {
|
||||||
|
...ep,
|
||||||
|
...parsedPropConf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMap(): ElementMap {
|
||||||
|
return this.map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(path: string[]): ConnectionConfiguration | undefined {
|
||||||
|
return this.map[path.join("/")];
|
||||||
|
}
|
||||||
|
|
||||||
|
public getByIdShort(idShort: string): ConnectionConfiguration[] {
|
||||||
|
return Object.keys(this.map).filter(e => e.endsWith(idShort)).map(e => this.map[e]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import * as aasCore from "@aas-core-works/aas-core3.0-typescript";
|
||||||
|
import Traverser from "helper/traverser";
|
||||||
|
import { AssetInterfacesMappingConfiguration, MappingConfEntry, MappingConfiguration } from "types/aimcConf";
|
||||||
|
import { endpointAvailable, ResolvedRelationshipElement } from "types/common";
|
||||||
|
|
||||||
|
export default class AIMCParser {
|
||||||
|
|
||||||
|
public static parse(env: aasCore.types.Environment): AssetInterfacesMappingConfiguration | null {
|
||||||
|
const sm = Traverser.findSMByIdShort(env, "AssetInterfaceMappingConfiguration");
|
||||||
|
if (sm === null || sm.submodelElements === null) return null;
|
||||||
|
|
||||||
|
const parsed = {} as AssetInterfacesMappingConfiguration;
|
||||||
|
|
||||||
|
sm.submodelElements.forEach(e => {
|
||||||
|
if (!aasCore.types.isSubmodelElementList(e) || !e.idShort || !e.value) return;
|
||||||
|
|
||||||
|
const endpointProto = endpointAvailable(e.idShort);
|
||||||
|
if (!endpointProto) return;
|
||||||
|
|
||||||
|
parsed[endpointProto] = e.value.map(element => {
|
||||||
|
if (!aasCore.types.isSubmodelElementCollection(element)) return null;
|
||||||
|
|
||||||
|
return AIMCParser.parseAIMCEntry(element, env);
|
||||||
|
}).filter(e => e !== null) as MappingConfEntry[];
|
||||||
|
});
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static parseAIMCEntry(entry: aasCore.types.SubmodelElementCollection, environment: aasCore.types.Environment): MappingConfEntry | null {
|
||||||
|
const ep = Traverser.findElement(entry, element => (element as any).idShort.toLocaleLowerCase() === "endpointmetadatareference");
|
||||||
|
const mc = Traverser.findElement(entry, element => (element as any).idShort.toLocaleLowerCase() === "mappingconfiguration");
|
||||||
|
if (ep === null || !aasCore.types.isReference(ep) || !ep.keys || !ep.keys[0] || !mc || !aasCore.types.isSubmodelElementList(mc) || !mc.value) return null;
|
||||||
|
|
||||||
|
const resolvedEp = Traverser.resolveReference(environment, ep);
|
||||||
|
if (resolvedEp === null || !aasCore.types.isSubmodelElementCollection(resolvedEp) || resolvedEp.idShort?.toLocaleLowerCase() !== "endpointmetadatareference") return null;
|
||||||
|
|
||||||
|
const parsedMc: (MappingConfiguration|null)[] = []
|
||||||
|
for (const conf of mc.overValueOrEmpty()) {
|
||||||
|
if (!aasCore.types.isSubmodelElementCollection(conf)) continue;
|
||||||
|
const parsed = AIMCParser.parseMappingConfiguration(conf, environment);
|
||||||
|
if (parsed === null) continue;
|
||||||
|
parsedMc.push(parsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
EndpointMetaDataReference: resolvedEp,
|
||||||
|
MappingConfiguration: parsedMc.filter(e => e !== null) as MappingConfiguration[]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static parseMappingConfiguration(conf: aasCore.types.SubmodelElementCollection, env: aasCore.types.Environment): MappingConfiguration | null {
|
||||||
|
if (!conf.value) return null;
|
||||||
|
|
||||||
|
const parsed = {
|
||||||
|
InterfaceMetaDataReference: null,
|
||||||
|
SourceSinkMappings: []
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const ifMetaRef = Traverser.findElement(conf, element => (element as any).idShort.toLocaleLowerCase() === "interfacemetadatareference");
|
||||||
|
if (!ifMetaRef || !aasCore.types.isReference(ifMetaRef) || !ifMetaRef.keys) return null;
|
||||||
|
const ifMeta = Traverser.resolveReference(env, ifMetaRef);
|
||||||
|
if (!ifMeta || !aasCore.types.isSubmodelElementCollection(ifMeta) || ifMeta.idShort?.toLocaleLowerCase() !== "interfacemetadata") return null;
|
||||||
|
parsed.InterfaceMetaDataReference = ifMeta;
|
||||||
|
|
||||||
|
const sourceSinkMappings = Traverser.findElement(conf, element => (element as any).idShort.toLocaleLowerCase() === "sourcesinkmappings");
|
||||||
|
if (!sourceSinkMappings || !aasCore.types.isSubmodelElementList(sourceSinkMappings) || !sourceSinkMappings.value) return null;
|
||||||
|
|
||||||
|
for (const ssm of sourceSinkMappings.overValueOrEmpty()) {
|
||||||
|
if (!aasCore.types.isRelationshipElement(ssm)) continue;
|
||||||
|
// No resolve, to allow for mapping
|
||||||
|
//const resolved = Traverser.resolveRelationship(env, ssm);
|
||||||
|
//if (resolved === null) continue;
|
||||||
|
|
||||||
|
parsed.SourceSinkMappings.push(ssm as ResolvedRelationshipElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed as MappingConfiguration;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { AvailableEndpoint } from "./common";
|
import { AvailableEndpoint } from "./common";
|
||||||
|
|
||||||
export type AssetInterfaceDescription = {
|
export type AssetInterfacesDescription = {
|
||||||
[key in AvailableEndpoint]: InterfaceDescription[];
|
[key in AvailableEndpoint]: InterfaceDescription[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import type { types } from "@aas-core-works/aas-core3.0-typescript";
|
import type { types } from "@aas-core-works/aas-core3.0-typescript";
|
||||||
import { AvailableEndpoint } from "./common";
|
import type { AvailableEndpoint } from "./common";
|
||||||
|
import type { EndpointMetadata, InterfaceProperty } from "./aidConf";
|
||||||
|
|
||||||
export type AssetInterfaceMappingConfiguration = Record<AvailableEndpoint, MappingConfEntry[]>;
|
export type AssetInterfacesMappingConfiguration = Record<AvailableEndpoint, MappingConfEntry[]>;
|
||||||
|
|
||||||
export type MappingConfEntry = {
|
export type MappingConfEntry = {
|
||||||
EndpointMetaDataReference: types.ReferenceElement;
|
EndpointMetaDataReference:types.SubmodelElementCollection;
|
||||||
MappingConfiguration: MappingConfiguration;
|
MappingConfiguration: MappingConfiguration[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MappingConfiguration = {
|
export type MappingConfiguration = {
|
||||||
InterfaceMetaDataReference: types.ReferenceElement;
|
InterfaceMetaDataReference: types.SubmodelElementCollection;
|
||||||
SourceSinkMappings: types.RelationshipElement[];
|
SourceSinkMappings: types.RelationshipElement[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ElementMap = Record<string, ConnectionConfiguration>;
|
||||||
|
|
||||||
|
export type ConnectionConfiguration = EndpointMetadata & InterfaceProperty; // Wenn Transformationen implementiert werden, dann hier anpassen
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import type { types } from "@aas-core-works/aas-core3.0-typescript";
|
||||||
|
|
||||||
export const availableEndpoints = ["HTTP", "MQTT", "Modbus"] as const;
|
export const availableEndpoints = ["HTTP", "MQTT", "Modbus"] as const;
|
||||||
export type AvailableEndpoint = typeof availableEndpoints[number];
|
export type AvailableEndpoint = typeof availableEndpoints[number];
|
||||||
|
|
||||||
@@ -6,3 +8,8 @@ export function endpointAvailable(endpoint: string): AvailableEndpoint | null {
|
|||||||
if (idx === -1) return null;
|
if (idx === -1) return null;
|
||||||
return availableEndpoints[idx];
|
return availableEndpoints[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ResolvedRelationshipElement = {
|
||||||
|
first: types.Class;
|
||||||
|
second: types.Class;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user