More work on connector

This commit is contained in:
Daniel Kluge
2023-10-30 12:51:57 +01:00
parent 870fce9247
commit 523935a0d5
6 changed files with 131 additions and 30 deletions
+74 -19
View File
@@ -1,6 +1,7 @@
import * as mqtt from "mqtt";
import type { Property, Operation, OperationVariable, BasicEventElement } from "@aas-core-works/aas-core3.0-typescript/dist/types/types";
import InterfaceConnectionObject from "interfaceConnectionObject";
import type { types } from "@aas-core-works/aas-core3.0-typescript";
class MQTTConnector extends InterfaceConnectionObject<mqtt.IClientOptions> {
protected name: string = "MQTT Connector";
@@ -10,13 +11,17 @@ class MQTTConnector extends InterfaceConnectionObject<mqtt.IClientOptions> {
private client: mqtt.MqttClient|null = null;
private store: Record<string, any> = {};
private messageStore: Record<string, any> = {};
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) => {
// 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("#");
return this.client.connected;
@@ -27,35 +32,85 @@ class MQTTConnector extends InterfaceConnectionObject<mqtt.IClientOptions> {
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.");
}
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.");
}
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.");
}
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.");
}
public callActionAsync(action: Operation, args: OperationVariable[]): Promise<boolean> {
throw new Error("Method not implemented.");
}
public unsubscribeEvent(event: types.BasicEventElement): void {
// 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.");
}
+2 -2
View File
@@ -1,6 +1,6 @@
import MultiMessageBroker from "./multimessageBroker";
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");
@@ -8,4 +8,4 @@ const broker = new MultiMessageBroker();
broker.registerAAS({ aas, serverInterfaces: { serverInterface: HTTPInterfaceServer, config: { bindPort: 3000, bindAddress: "0.0.0.0" } } });
broker.prepare();
broker.start();
broker.start();
+19 -6
View File
@@ -1,4 +1,6 @@
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";
type ConnectionType = "ON_DEMAND" | "PERMANENT";
@@ -11,9 +13,14 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
protected abstract readonly connectionType: ConnectionType;
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(
protected readonly connectionParameter: ConfigInterface,
protected readonly endpointMetadata: EndpointMetadata,
protected readonly endpointMetadata: EndpointMetadata,
protected readonly mapper: AIMCMapper,
private readonly onResponseCallback: OnResponseCallback) {}
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 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;
}
}
+1 -1
View File
@@ -14,6 +14,6 @@ export type MappingConfiguration = {
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