Draw the rest of the f-ing owl 🦉

This commit is contained in:
Daniel Kluge
2023-12-06 16:15:54 +01:00
parent 64279a6efa
commit 76ec6e4c9d
13 changed files with 1981 additions and 132 deletions
+5 -5
View File
@@ -198,7 +198,7 @@ export default class HTTPInterfaceServer extends AbstractInterfaceServer<Config>
const prop = Traverser.getElementByIdPath(this.aas, sm, idShortPath);
if (prop === null || !AASCoreTypes.isProperty(prop)) return res.status(404).end();
const request: Types.RequestTypes.Request = req.method === "GET" ? { type: "READ", target: prop } : { type: "WRITE", target: prop, extraData: { value: req.body } };
const request: Types.RequestTypes.Request = req.method === "GET" ? { type: "readProperty", target: prop } : { type: "writeProperty", target: prop, extraData: { value: req.body } };
const value = this.onRequestCallback(request);
@@ -215,7 +215,7 @@ export default class HTTPInterfaceServer extends AbstractInterfaceServer<Config>
// TODO
// Parameter?
const success = this.onRequestCallback({ type: "CALL", target: op, extraData: { args: req.body } });
const success = this.onRequestCallback({ type: "invokeAction", target: op, extraData: { args: req.body, async: false } });
return res.send(success ? 204 : 500).end();
}
@@ -226,7 +226,7 @@ export default class HTTPInterfaceServer extends AbstractInterfaceServer<Config>
// TODO
// Invoke operation and get handle
const request: Types.RequestTypes.Request = { type: "CALL-ASYNC", target: op, extraData: { args: req.body } };
const request: Types.RequestTypes.Request = { type: "invokeAction", target: op, extraData: { args: req.body, async: true } };
const handle = this.onRequestCallback(request);
@@ -241,7 +241,7 @@ export default class HTTPInterfaceServer extends AbstractInterfaceServer<Config>
case "operation-status": {
if (req.method !== "GET") return res.status(405).end();
const state = this.onRequestCallback({ type: "GET-OP-STATE", target: handle });
const state = this.onRequestCallback({ type: "xAsyncActionState", target: handle });
if (state === undefined) return res.status(404).end();
@@ -253,7 +253,7 @@ export default class HTTPInterfaceServer extends AbstractInterfaceServer<Config>
case "operation-result": {
if (req.method !== "GET") return res.status(405).end();
const result = this.onRequestCallback({ type: "GET-OP-RESULT", target: handle });
const result = this.onRequestCallback({ type: "xAsyncActionResult", target: handle });
if (result === null) return res.status(404).end();
return res.json({
+71 -35
View File
@@ -1,6 +1,7 @@
import * as mqtt from "mqtt";
import { AbstractConnectionObject } from "aas-multimessagebroker";
import type { AASCoreTypes } from "aas-multimessagebroker";
import { AASCoreTypes, Types } from "aas-multimessagebroker";
import { MMBEvent } from "aas-multimessagebroker/dist/types/requests";
/**
* This is an example module for the asset connection object.
@@ -70,7 +71,10 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
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.observerStore[topic].forEach(sub => sub.cb({ type: "event", value: message.toString("utf-8"), target: sub.target}));
}
if (this.eventSubStore[topic] !== undefined) {
this.eventSubStore[topic].forEach(sub => sub.cb({ type: "event", value: message.toString("utf-8"), target: sub.target}));
}
});
this.client.subscribe("#");
@@ -87,6 +91,10 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
this.client = null;
}
private assertConnected(): void {
if (!this.client || !this.client.connected) throw new Error("Not connected");
}
/**
* Read a property value from the asset.
*
@@ -98,16 +106,13 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @override
* @public
*/
public readProperty(prop: AASCoreTypes.Property): any {
const cc = this.mapper.get(prop);
if (cc === undefined) return null;
const errorReturn = cc.default ?? null;
public readProperty(_target: AASCoreTypes.Property, mapping: Types.RequestTypes.ConnectionConfiguration): any {
const errorReturn = mapping.default ?? null;
if (!this.client || !this.client.connected) return errorReturn;
const value = this.messageStore[cc.forms.href.substring(1)];
const value = this.messageStore[mapping.forms[0].href.substring(1)];
if (value === undefined) return errorReturn;
switch (cc.type) {
switch (mapping.type) {
case "integer":
return Number.parseInt(value);
case "float":
@@ -129,11 +134,10 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @override
* @public
*/
public writeProperty(prop: AASCoreTypes.Property, value: any): boolean {
const cc = this.mapper.get(prop);
if (cc === undefined || !this.client || !this.client.connected) return false;
public writeProperty(_target: AASCoreTypes.Property, mapping: Types.RequestTypes.ConnectionConfiguration, value: any): boolean {
if (!this.client || !this.client.connected) return false;
const topic = cc.forms.href.substring(1);
const topic = mapping.forms[0].href.substring(1);
if (topic === undefined) return false;
this.client.publish(topic, value.toString());
@@ -149,17 +153,22 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @override
* @public
*/
public observeProperty(prop: AASCoreTypes.Property, callback: (value: any) => void): boolean {
const cc = this.mapper.get(prop);
if (cc === undefined || !cc.observable || !this.client || !this.client.connected) return false;
public observeProperty(target: AASCoreTypes.Property, mapping: Types.RequestTypes.ConnectionConfiguration, cb: (value: Types.RequestTypes.MMBEvent) => void): boolean {
if (!mapping.observable || !this.client || !this.client.connected) return false;
const topic = cc.forms.href.substring(1);
if (this.observerStore[topic] === undefined) this.observerStore[topic] = [callback];
else this.observerStore[topic].push(callback);
const topic = mapping.forms[0].href.substring(1);
if (this.observerStore[topic] === undefined) this.observerStore[topic] = [{ target, cb }];
else this.observerStore[topic].push({ target, cb });
return true;
}
public unobserveProperty(target: AASCoreTypes.Property, mapping: Types.RequestTypes.ConnectionConfiguration): void {
const topic = mapping.forms[0].href.substring(1);
this.observerStore[topic];
//! TODO
}
/**
* Calls an action synchronously.
* @param action Action
@@ -168,13 +177,22 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @returns Return value of action.
* @override
* @public
* @alpha
* @beta
*/
public callActionSync(action: AASCoreTypes.Operation, args: Record<string, any>): any {
// TODO
// Vorher mal ne ordentliche Mapping-Definition
public callActionSync(_target: AASCoreTypes.Operation, mapping: Types.RequestTypes.ConnectionConfiguration, args: Record<string, any>): any {
this.assertConnected();
throw new Error("Method not implemented.");
const form: Types.AIDTypes.InterfaceFormMQTTAction = mapping.forms[0];
const topic = form.href.substring(1);
if (topic === undefined || !mapping.forms) throw new Error("Mapping invalid.");
const message = JSON.stringify(args);
this.execute(form.mqv_controlPacketValue ?? "PUBLISH", topic, message);
// There is currently no way to get the result of an action
// Not because we cannot wait but because we don't know where the result is sent!
return;
}
/**
@@ -187,11 +205,17 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @public
* @alpha
*/
public callActionAsync(action: AASCoreTypes.Operation, args: Record<string, any>): string | null {
// TODO
// Vorher mal ne ordentliche Mapping-Definition
public callActionAsync(_target: AASCoreTypes.Operation, mapping: Types.RequestTypes.ConnectionConfiguration, args: Record<string, any>): string {
this.assertConnected();
throw new Error("Method not implemented.");
const form: Types.AIDTypes.InterfaceFormMQTTAction = mapping.forms[0];
const topic = form.href.substring(1);
if (topic === undefined || !mapping.forms) throw new Error("Mapping invalid.");
const message = JSON.stringify(args);
this.execute(form.mqv_controlPacketValue ?? "PUBLISH", topic, message);
return this.generateAsyncHandle();
}
/**
@@ -203,11 +227,14 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @public
* @alpha
*/
public subscribeEvent(event: AASCoreTypes.BasicEventElement, callback: (event: AASCoreTypes.BasicEventElement) => void): boolean {
// TODO
// Vorher mal ne ordentliche Mapping-Definition
public subscribeEvent(target: AASCoreTypes.Class, mapping: Types.RequestTypes.ConnectionConfiguration, cb: (event: Types.RequestTypes.MMBEvent) => void): boolean {
if (!mapping.observable || !this.client || !this.client.connected) return false;
throw new Error("Method not implemented.");
const topic = mapping.forms[0].href.substring(1);
if (this.eventSubStore[topic] === undefined) this.eventSubStore[topic] = [{ target, cb }];
else this.eventSubStore[topic].push({ target, cb });
return true;
}
/**
@@ -217,11 +244,20 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @public
* @alpha
*/
public unsubscribeEvent(event: AASCoreTypes.BasicEventElement): void {
public unsubscribeEvent(event: AASCoreTypes.Class, mapping: Types.RequestTypes.ConnectionConfiguration): void {
// TODO
// Vorher mal ne ordentliche Mapping-Definition
// How do we know which event to unsubscribe from?
}
throw new Error("Method not implemented.");
private execute(packetType: "PUBLISH" | "SUBSCRIBE" | "UNSUBSCRIBE", topic: string, message?: string) {
this.assertConnected();
if (this.client){
switch (packetType) {
case "PUBLISH": return this.client.publish(topic, message ?? "1");
case "SUBSCRIBE": return this.client.subscribe(topic);
case "UNSUBSCRIBE": return this.client.unsubscribe(topic);
}
}
}
}