Created mapper
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
|
||||
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]
|
||||
|
||||
@@ -40,6 +42,14 @@ export default class Traverser {
|
||||
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 {
|
||||
let current: types.Class | null = start;
|
||||
for (const shortId of shortIds) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { Request } from "types/requests";
|
||||
import type InterfaceConnectionObject from "interfaceConnectionObject";
|
||||
import Traverser from "./helper/traverser";
|
||||
import type { AIMCMapper } from "./parser/AIMCMapper";
|
||||
import { AssetInterfaceDescription } from "types/aidConf";
|
||||
import { AssetInterfacesDescription } from "types/aidConf";
|
||||
import AIDParser from "./parser/AIDParser";
|
||||
|
||||
type AASRegistration = {
|
||||
|
||||
+12
-10
@@ -1,15 +1,15 @@
|
||||
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 Traverser from "../helper/traverser";
|
||||
|
||||
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");
|
||||
if (sm === null || sm.submodelElements === null) return null;
|
||||
|
||||
const parsed = {} as AssetInterfaceDescription;
|
||||
const parsed = {} as AssetInterfacesDescription;
|
||||
|
||||
sm.submodelElements.forEach(e => {
|
||||
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");
|
||||
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;
|
||||
const parsedProp = AIDParser.parseInterfaceMetadataProperty(element, endpointProtocol);
|
||||
if (parsedProp === null) continue;
|
||||
@@ -84,7 +84,7 @@ export default class AIDParser {
|
||||
|
||||
const actions = Traverser.findElement(interfaceMeta, element => (element as any).idShort.toLocaleLowerCase() === "actions");
|
||||
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;
|
||||
const parsedAction = AIDParser.parseInterfaceMetadataProperty(element, endpointProtocol);
|
||||
if (parsedAction === null) continue;
|
||||
@@ -95,7 +95,7 @@ export default class AIDParser {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -106,19 +106,21 @@ export default class AIDParser {
|
||||
else parsed[key] = prop.value;
|
||||
} */
|
||||
|
||||
const parsedForms = [] as InterfacePropertyForm[];
|
||||
|
||||
const forms = Traverser.findElement(prop, element => (element as any).idShort.toLocaleLowerCase() === "forms");
|
||||
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;
|
||||
const parsedForm = AIDParser.parseInterfaceMetadataPropertyForm(element, endpointProtocol);
|
||||
if (parsedForm === null) continue;
|
||||
parsed.forms.push(parsedForm);
|
||||
parsedForms.push(parsedForm);
|
||||
}
|
||||
|
||||
// TODO
|
||||
// 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 {
|
||||
@@ -143,7 +145,7 @@ export default class AIDParser {
|
||||
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
|
||||
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 {
|
||||
|
||||
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";
|
||||
|
||||
export type AssetInterfaceDescription = {
|
||||
export type AssetInterfacesDescription = {
|
||||
[key in AvailableEndpoint]: InterfaceDescription[];
|
||||
};
|
||||
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
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 = {
|
||||
EndpointMetaDataReference: types.ReferenceElement;
|
||||
MappingConfiguration: MappingConfiguration;
|
||||
EndpointMetaDataReference:types.SubmodelElementCollection;
|
||||
MappingConfiguration: MappingConfiguration[];
|
||||
}
|
||||
|
||||
export type MappingConfiguration = {
|
||||
InterfaceMetaDataReference: types.ReferenceElement;
|
||||
InterfaceMetaDataReference: types.SubmodelElementCollection;
|
||||
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 type AvailableEndpoint = typeof availableEndpoints[number];
|
||||
|
||||
@@ -5,4 +7,9 @@ export function endpointAvailable(endpoint: string): AvailableEndpoint | null {
|
||||
const idx = availableEndpoints.map(e => e.toLocaleLowerCase()).findIndex(e => e === endpoint.toLocaleLowerCase());
|
||||
if (idx === -1) return null;
|
||||
return availableEndpoints[idx];
|
||||
}
|
||||
|
||||
export type ResolvedRelationshipElement = {
|
||||
first: types.Class;
|
||||
second: types.Class;
|
||||
}
|
||||
Reference in New Issue
Block a user