From 4ccd0b6b615f19cc9c5c5683409f07ac5b3cae95 Mon Sep 17 00:00:00 2001 From: danielpeintner Date: Tue, 26 Sep 2023 11:59:52 +0200 Subject: [PATCH 1/2] fix: issue with absolute URL --- .../src/util/asset-interface-description.ts | 5 +- .../test/AssetInterfaceDescriptionTest.ts | 45 +++++ .../td-tools/test/util/inverterModbus.json | 167 ++++++++++++++++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 packages/td-tools/test/util/inverterModbus.json diff --git a/packages/td-tools/src/util/asset-interface-description.ts b/packages/td-tools/src/util/asset-interface-description.ts index b851af209..480118203 100644 --- a/packages/td-tools/src/util/asset-interface-description.ts +++ b/packages/td-tools/src/util/asset-interface-description.ts @@ -21,6 +21,7 @@ import * as TDParser from "../td-parser"; import debug from "debug"; import { ThingDescription } from "wot-typescript-definitions"; import { FormElementBase, PropertyElement } from "wot-thing-model-types"; +import isAbsoluteUrl = require("is-absolute-url"); const namespace = "node-wot:td-tools:asset-interface-description-util"; const logDebug = debug(`${namespace}:debug`); const logInfo = debug(`${namespace}:info`); @@ -339,7 +340,9 @@ export class AssetInterfaceDescriptionUtil { for (const v of iv.value) { // Binding if (v.idShort === "href") { - if (form.href && form.href.length > 0) { + if (isAbsoluteUrl(v.value)) { + form.href = v.value; + } else if (form.href && form.href.length > 0) { form.href = form.href + v.value; // TODO handle leading/trailing slashes } else { form.href = v.value; diff --git a/packages/td-tools/test/AssetInterfaceDescriptionTest.ts b/packages/td-tools/test/AssetInterfaceDescriptionTest.ts index 3c582d087..7863cacc9 100644 --- a/packages/td-tools/test/AssetInterfaceDescriptionTest.ts +++ b/packages/td-tools/test/AssetInterfaceDescriptionTest.ts @@ -165,6 +165,51 @@ class AssetInterfaceDescriptionUtilTest { expect(td4Obj).to.not.have.property("properties"); } + @test async "should correctly transform inverterModbus into a TD"() { + const modelAID = (await fs.readFile("test/util/inverterModbus.json")).toString(); + const td = this.assetInterfaceDescriptionUtil.transformAAS2TD(modelAID, `{"title": "bla"}`); + + const tdObj = JSON.parse(td); + expect(tdObj).to.have.property("@context").that.equals("https://www.w3.org/2022/wot/td/v1.1"); + expect(tdObj).to.have.property("title").that.equals("Inverter GEN44"); // should come form AAS + + expect(tdObj).to.have.property("securityDefinitions").to.be.an("object"); + + expect(tdObj).to.have.property("security").to.be.an("array").to.have.lengthOf(1); + expect(tdObj.securityDefinitions[tdObj.security[0]]).to.have.property("scheme").that.equals("nosec"); + + // check device_name property + expect(tdObj).to.have.property("properties").to.have.property("device_name"); + expect(tdObj) + .to.have.property("properties") + .to.have.property("device_name") + .to.have.property("type") + .that.equals("string"); + expect(tdObj) + .to.have.property("properties") + .to.have.property("device_name") + .to.have.property("title") + .that.equals("Device name"); + expect(tdObj) + .to.have.property("properties") + .to.have.property("device_name") + .to.have.property("forms") + .to.be.an("array") + .to.have.lengthOf(1); + expect(tdObj.properties.device_name.forms[0]).to.have.property("op").to.eql("readproperty"); + expect(tdObj.properties.device_name.forms[0]) + .to.have.property("href") + .to.eql("modbus+tcp://192.168.178.146:502/1/40020?quantity=16"); + expect(tdObj.properties.device_name.forms[0]) + .to.have.property("modbus:function") + .to.eql("readHoldingRegisters"); + expect(tdObj.properties.device_name.forms[0]).to.have.property("modbus:type").to.eql("string"); + expect(tdObj.properties.device_name.forms[0]) + .to.have.property("contentType") + .to.eql("application/octet-stream"); + expect(tdObj.properties.device_name.forms[0]).not.to.have.property("security"); + } + td1Base = "https://www.example.com/"; td1: ThingDescription = { "@context": "https://www.w3.org/2022/wot/td/v1.1", diff --git a/packages/td-tools/test/util/inverterModbus.json b/packages/td-tools/test/util/inverterModbus.json new file mode 100644 index 000000000..c9f976b0b --- /dev/null +++ b/packages/td-tools/test/util/inverterModbus.json @@ -0,0 +1,167 @@ +{ + "assetAdministrationShells": [ + { + "idShort": "SampleAAS", + "id": "https://example.com/ids/aas/7474_9002_6022_1115", + "assetInformation": { "assetKind": "Type" }, + "submodels": [ + { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "uri:dev:inverter" + } + ] + } + ], + "modelType": "AssetAdministrationShell" + } + ], + "submodels": [ + { + "idShort": "AssetInterfacesDescription", + "id": "uri:dev:inverter", + "kind": "Instance", + "description": [ + { + "language": "en", + "text": "Inverter GEN44" + } + ], + "submodelElements": [ + { + "idShort": "InterfaceMODBUS+TCP", + "value": [ + { + "idShort": "title", + "valueType": "xs:string", + "value": "Inverter GEN44", + "modelType": "Property" + }, + { + "idShort": "EndpointMetadata", + "value": [ + { + "idShort": "base", + "valueType": "xs:anyURI", + "value": "modbus+tcp://192.168.178.146:502/", + "modelType": "Property" + }, + { + "idShort": "security", + "value": [ + { + "valueType": "xs:string", + "value": "nosec_sc", + "modelType": "Property" + } + ], + "modelType": "SubmodelElementCollection" + }, + { + "idShort": "securityDefinitions", + "value": [ + { + "idShort": "nosec_sc", + "value": [ + { + "idShort": "scheme", + "valueType": "xs:string", + "value": "nosec", + "modelType": "Property" + } + ], + "modelType": "SubmodelElementCollection" + } + ], + "modelType": "SubmodelElementCollection" + } + ], + "modelType": "SubmodelElementCollection" + }, + { + "idShort": "InterfaceMetadata", + "value": [ + { + "idShort": "Properties", + "value": [ + { + "idShort": "device_name", + "value": [ + { + "idShort": "type", + "valueType": "xs:string", + "value": "string", + "modelType": "Property" + }, + { + "idShort": "title", + "valueType": "xs:string", + "value": "Device name", + "modelType": "Property" + }, + { + "idShort": "forms", + "value": [ + { + "idShort": "op", + "valueType": "xs:string", + "value": "readproperty", + "modelType": "Property" + }, + { + "idShort": "href", + "valueType": "xs:string", + "value": "modbus+tcp://192.168.178.146:502/1/40020?quantity=16", + "modelType": "Property" + }, + { + "idShort": "modbus:function", + "valueType": "xs:string", + "value": "readHoldingRegisters", + "modelType": "Property" + }, + { + "idShort": "modbus:type", + "valueType": "xs:string", + "value": "string", + "modelType": "Property" + }, + { + "idShort": "contentType", + "valueType": "xs:string", + "value": "application/octet-stream", + "modelType": "Property" + } + ], + "modelType": "SubmodelElementCollection" + } + ], + "modelType": "SubmodelElementCollection" + } + ], + "modelType": "SubmodelElementCollection" + }, + { + "idShort": "Actions", + "value": [], + "modelType": "SubmodelElementCollection" + }, + { + "idShort": "Events", + "value": [], + "modelType": "SubmodelElementCollection" + } + ], + "modelType": "SubmodelElementCollection" + } + ], + "modelType": "SubmodelElementCollection" + } + ], + "modelType": "Submodel" + } + ], + "conceptDescriptions": [] +} From c3cf7256e6b78c730188fb782f3004de3dd44580 Mon Sep 17 00:00:00 2001 From: danielpeintner Date: Thu, 28 Sep 2023 10:36:36 +0200 Subject: [PATCH 2/2] refactor: add additional null check --- packages/td-tools/src/util/asset-interface-description.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/td-tools/src/util/asset-interface-description.ts b/packages/td-tools/src/util/asset-interface-description.ts index 480118203..ee8acf82b 100644 --- a/packages/td-tools/src/util/asset-interface-description.ts +++ b/packages/td-tools/src/util/asset-interface-description.ts @@ -340,7 +340,7 @@ export class AssetInterfaceDescriptionUtil { for (const v of iv.value) { // Binding if (v.idShort === "href") { - if (isAbsoluteUrl(v.value)) { + if (v.value != null && isAbsoluteUrl(v.value)) { form.href = v.value; } else if (form.href && form.href.length > 0) { form.href = form.href + v.value; // TODO handle leading/trailing slashes