More work on connector
This commit is contained in:
Generated
+32
-1
@@ -11,11 +11,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aas-core-works/aas-core3.0-typescript": "^1.0.0-rc.3",
|
"@aas-core-works/aas-core3.0-typescript": "^1.0.0-rc.3",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"mqtt": "^5.1.2"
|
"mqtt": "^5.1.2",
|
||||||
|
"uuid": "^9.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.19",
|
"@types/express": "^4.17.19",
|
||||||
"@types/node": "^20.8.2",
|
"@types/node": "^20.8.2",
|
||||||
|
"@types/uuid": "^9.0.6",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2"
|
||||||
}
|
}
|
||||||
@@ -193,6 +195,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/uuid": {
|
||||||
|
"version": "9.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz",
|
||||||
|
"integrity": "sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/ws": {
|
"node_modules/@types/ws": {
|
||||||
"version": "8.5.7",
|
"version": "8.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.7.tgz",
|
||||||
@@ -1358,6 +1366,18 @@
|
|||||||
"node": ">= 0.4.0"
|
"node": ">= 0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uuid": {
|
||||||
|
"version": "9.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/v8-compile-cache-lib": {
|
"node_modules/v8-compile-cache-lib": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||||
@@ -1577,6 +1597,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/uuid": {
|
||||||
|
"version": "9.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz",
|
||||||
|
"integrity": "sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/ws": {
|
"@types/ws": {
|
||||||
"version": "8.5.7",
|
"version": "8.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.7.tgz",
|
||||||
@@ -2431,6 +2457,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
|
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
|
||||||
},
|
},
|
||||||
|
"uuid": {
|
||||||
|
"version": "9.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="
|
||||||
|
},
|
||||||
"v8-compile-cache-lib": {
|
"v8-compile-cache-lib": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||||
|
|||||||
+3
-1
@@ -12,12 +12,14 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.19",
|
"@types/express": "^4.17.19",
|
||||||
"@types/node": "^20.8.2",
|
"@types/node": "^20.8.2",
|
||||||
|
"@types/uuid": "^9.0.6",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aas-core-works/aas-core3.0-typescript": "^1.0.0-rc.3",
|
"@aas-core-works/aas-core3.0-typescript": "^1.0.0-rc.3",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"mqtt": "^5.1.2"
|
"mqtt": "^5.1.2",
|
||||||
|
"uuid": "^9.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as mqtt from "mqtt";
|
import * as mqtt from "mqtt";
|
||||||
import type { Property, Operation, OperationVariable, BasicEventElement } from "@aas-core-works/aas-core3.0-typescript/dist/types/types";
|
import type { Property, Operation, OperationVariable, BasicEventElement } from "@aas-core-works/aas-core3.0-typescript/dist/types/types";
|
||||||
import InterfaceConnectionObject from "interfaceConnectionObject";
|
import InterfaceConnectionObject from "interfaceConnectionObject";
|
||||||
|
import type { types } from "@aas-core-works/aas-core3.0-typescript";
|
||||||
|
|
||||||
class MQTTConnector extends InterfaceConnectionObject<mqtt.IClientOptions> {
|
class MQTTConnector extends InterfaceConnectionObject<mqtt.IClientOptions> {
|
||||||
protected name: string = "MQTT Connector";
|
protected name: string = "MQTT Connector";
|
||||||
@@ -10,13 +11,17 @@ class MQTTConnector extends InterfaceConnectionObject<mqtt.IClientOptions> {
|
|||||||
|
|
||||||
private client: mqtt.MqttClient|null = null;
|
private client: mqtt.MqttClient|null = null;
|
||||||
|
|
||||||
private store: Record<string, any> = {};
|
private messageStore: Record<string, any> = {};
|
||||||
|
|
||||||
public connect(): boolean {
|
public connect(): boolean {
|
||||||
if (!this.client) this.client = mqtt.connect(this.connectionParameter);
|
if (!this.client) this.client = mqtt.connect(this.endpointMetadata.base, this.connectionParameter);
|
||||||
this.client.on("message", (topic, message) => {
|
this.client.on("message", (topic, message) => {
|
||||||
// If json is expected you could parse it here
|
// If json is expected you could parse it here
|
||||||
this.store[topic] = message.toString("utf-8");
|
this.messageStore[topic] = message.toString("utf-8");
|
||||||
|
// Notify observers
|
||||||
|
if (this.observerStore[topic] !== undefined) {
|
||||||
|
this.observerStore[topic].forEach(cb => cb(message.toString("utf-8")));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
this.client.subscribe("#");
|
this.client.subscribe("#");
|
||||||
return this.client.connected;
|
return this.client.connected;
|
||||||
@@ -27,35 +32,85 @@ class MQTTConnector extends InterfaceConnectionObject<mqtt.IClientOptions> {
|
|||||||
this.client = null;
|
this.client = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readProperty(prop: Property): void {
|
public readProperty(prop: types.Property): any {
|
||||||
|
const cc = this.mapper.get(prop);
|
||||||
|
if (cc === undefined) return null;
|
||||||
|
|
||||||
|
const errorReturn = cc.default ?? null;
|
||||||
|
if (!this.client || !this.client.connected) return errorReturn;
|
||||||
|
|
||||||
|
const value = cc.forms.map(f => this.messageStore[f.href.substring(1)]).filter(v => v !== undefined)[0];
|
||||||
|
if (value === undefined) return errorReturn;
|
||||||
|
switch (cc.type) {
|
||||||
|
case "integer":
|
||||||
|
return Number.parseInt(value);
|
||||||
|
case "float":
|
||||||
|
return Number.parseFloat(value);
|
||||||
|
case "boolean":
|
||||||
|
return !!value;
|
||||||
|
case "string":
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public writeProperty(prop: types.Property, value: any): boolean {
|
||||||
|
const cc = this.mapper.get(prop);
|
||||||
|
if (cc === undefined || !this.client || !this.client.connected) return false;
|
||||||
|
|
||||||
|
const topic = cc.forms.map(f => f.href.substring(1))[0];
|
||||||
|
if (topic === undefined) return false;
|
||||||
|
|
||||||
|
this.client.publish(topic, value.toString());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public observeProperty(prop: types.Property, callback: (value: any) => void): boolean {
|
||||||
|
const cc = this.mapper.get(prop);
|
||||||
|
if (cc === undefined || !cc.observable || !this.client || !this.client.connected) return false;
|
||||||
|
|
||||||
|
cc.forms.map(f => f.href.substring(1)).forEach(topic => {
|
||||||
|
if (this.observerStore[topic] === undefined) this.observerStore[topic] = [callback];
|
||||||
|
else this.observerStore[topic].push(callback);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public callActionSync(action: types.Operation, args: OperationVariable[]): boolean {
|
||||||
|
// TODO
|
||||||
|
// Vorher mal ne ordentliche Mapping-Definition
|
||||||
|
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public writeProperty(prop: Property, value: any): void {
|
public callActionAsync(action: types.Operation, args: OperationVariable[]): string | null {
|
||||||
|
// TODO
|
||||||
|
// Vorher mal ne ordentliche Mapping-Definition
|
||||||
|
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public observeProperty(prop: Property, callback: (value: any) => void): boolean {
|
public readAsyncActionResponse(action: types.Operation): any {
|
||||||
|
// TODO
|
||||||
|
// Vorher mal ne ordentliche Mapping-Definition
|
||||||
|
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public callActionSync(action: Operation, args: OperationVariable[]) {
|
public subscribeEvent(event: types.BasicEventElement, callback: (event: BasicEventElement) => void): boolean {
|
||||||
|
// TODO
|
||||||
|
// Vorher mal ne ordentliche Mapping-Definition
|
||||||
|
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public callActionAsync(action: Operation, args: OperationVariable[]): Promise<boolean> {
|
public unsubscribeEvent(event: types.BasicEventElement): void {
|
||||||
throw new Error("Method not implemented.");
|
// TODO
|
||||||
}
|
// Vorher mal ne ordentliche Mapping-Definition
|
||||||
|
|
||||||
public readAsyncActionResponse(action: Operation): Promise<any> {
|
|
||||||
throw new Error("Method not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public subscribeEvent(callback: (event: BasicEventElement) => void): boolean {
|
|
||||||
throw new Error("Method not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsubscribeEvent(): void {
|
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import MultiMessageBroker from "./multimessageBroker";
|
import MultiMessageBroker from "./multimessageBroker";
|
||||||
import HTTPInterfaceServer from "./example_modules/httpInterfaceServer";
|
import HTTPInterfaceServer from "./example_modules/httpInterfaceServer";
|
||||||
import FileImporter from "helper/fileImporter";
|
import FileImporter from "./helper/fileImporter";
|
||||||
|
|
||||||
const aas = FileImporter.readAASByPath("../AID-AIMC-Full-Example-20230911T1608.json");
|
const aas = FileImporter.readAASByPath("../AID-AIMC-Full-Example-20230911T1608.json");
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import type { types } from "@aas-core-works/aas-core3.0-typescript";
|
import type { types } from "@aas-core-works/aas-core3.0-typescript";
|
||||||
|
import { AIMCMapper } from "parser/AIMCMapper";
|
||||||
|
import { v4 } from "uuid";
|
||||||
import type { EndpointMetadata } from "types/aidConf";
|
import type { EndpointMetadata } from "types/aidConf";
|
||||||
|
|
||||||
type ConnectionType = "ON_DEMAND" | "PERMANENT";
|
type ConnectionType = "ON_DEMAND" | "PERMANENT";
|
||||||
@@ -11,9 +13,14 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
|
|||||||
protected abstract readonly connectionType: ConnectionType;
|
protected abstract readonly connectionType: ConnectionType;
|
||||||
protected abstract readonly supportsSubscriptions: boolean;
|
protected abstract readonly supportsSubscriptions: boolean;
|
||||||
|
|
||||||
|
protected observerStore: Record<any, ((value: any) => void)[]> = {};
|
||||||
|
protected eventSubStore: Record<any, ((value: any) => void)[]> = {};
|
||||||
|
protected asyncActionStateStore: Record<any, {finished: boolean, result: any}> = {};
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected readonly connectionParameter: ConfigInterface,
|
protected readonly connectionParameter: ConfigInterface,
|
||||||
protected readonly endpointMetadata: EndpointMetadata,
|
protected readonly endpointMetadata: EndpointMetadata,
|
||||||
|
protected readonly mapper: AIMCMapper,
|
||||||
private readonly onResponseCallback: OnResponseCallback) {}
|
private readonly onResponseCallback: OnResponseCallback) {}
|
||||||
|
|
||||||
public abstract connect(): boolean;
|
public abstract connect(): boolean;
|
||||||
@@ -26,13 +33,19 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
|
|||||||
|
|
||||||
public abstract observeProperty(prop: types.Property, callback: (value: any) => void): boolean;
|
public abstract observeProperty(prop: types.Property, callback: (value: any) => void): boolean;
|
||||||
|
|
||||||
public abstract callActionSync(action: types.Operation, args: types.OperationVariable[]): any;
|
public abstract callActionSync(action: types.Operation, args: types.OperationVariable[]): boolean;
|
||||||
|
|
||||||
public abstract callActionAsync(action: types.Operation, args: types.OperationVariable[]): Promise<boolean>;
|
public abstract callActionAsync(action: types.Operation, args: types.OperationVariable[]): string | null;
|
||||||
|
|
||||||
public abstract readAsyncActionResponse(action: types.Operation): Promise<any>;
|
public abstract readAsyncActionResponse(action: types.Operation): any;
|
||||||
|
|
||||||
public abstract subscribeEvent(callback: (event: types.BasicEventElement) => void): boolean;
|
public abstract subscribeEvent(event: types.BasicEventElement, callback: (event: types.BasicEventElement) => void): boolean;
|
||||||
|
|
||||||
public abstract unsubscribeEvent(): void;
|
public abstract unsubscribeEvent(event: types.BasicEventElement): void;
|
||||||
|
|
||||||
|
protected generateAsyncHandle() {
|
||||||
|
const handle = v4();
|
||||||
|
this.asyncActionStateStore[handle] = {finished: false, result: null};
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,6 @@ export type MappingConfiguration = {
|
|||||||
SourceSinkMappings: types.RelationshipElement[];
|
SourceSinkMappings: types.RelationshipElement[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ElementMap = Record<string, ConnectionConfiguration>;
|
export type AIMCMap = Map<types.Class, ConnectionConfiguration>;
|
||||||
|
|
||||||
export type ConnectionConfiguration = EndpointMetadata & InterfaceProperty; // Wenn Transformationen implementiert werden, dann hier anpassen
|
export type ConnectionConfiguration = EndpointMetadata & InterfaceProperty; // Wenn Transformationen implementiert werden, dann hier anpassen
|
||||||
Reference in New Issue
Block a user