Skip to content

Commit 63b31c6

Browse files
refactor(td-tools): AID idShort does not allow ":" and used "_" instead (#1113)
1 parent 7a99bf9 commit 63b31c6

File tree

3 files changed

+168
-16
lines changed

3 files changed

+168
-16
lines changed

packages/td-tools/src/util/asset-interface-description.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -348,13 +348,14 @@ export class AssetInterfaceDescriptionUtil {
348348
form.href = v.value;
349349
}
350350
} else if (typeof v.idShort === "string" && v.idShort.length > 0) {
351-
// TODO is this still relevant?
352351
// pick *any* value (and possibly override, e.g. contentType)
353-
// TODO Should we add all value's (e.g., dataMapping might be empty array) ?
354-
// if (typeof v.value === "string" ||typeof v.value === "number" || typeof v.value === "boolean") {
355352
if (v.value != null) {
356-
form[v.idShort] = v.value;
353+
// Note: AID does not allow idShort to contain values with colon (i.e., ":") --> "_" used instead
354+
// --> THIS MAY LEAD TO PROBLEMS BUT THAT'S HOW IT IS SPECIFIED
355+
const tdTerm = (v.idShort as string).replace("_", ":");
356+
form[tdTerm] = v.value;
357357
// use valueType to convert the string value
358+
// TODO Should we add/support all value's (e.g., dataMapping might be empty array) ?
358359
if (
359360
v.valueType != null &&
360361
v.valueType.dataObjectType != null &&
@@ -364,7 +365,7 @@ export class AssetInterfaceDescriptionUtil {
364365
// XSD schemaTypes, https://www.w3.org/TR/xmlschema-2/#built-in-datatypes
365366
switch (v.valueType.dataObjectType.name) {
366367
case "boolean":
367-
form[v.idShort] = form[v.idShort] === "true";
368+
form[tdTerm] = form[v.value] === "true";
368369
break;
369370
case "float":
370371
case "double":
@@ -382,7 +383,7 @@ export class AssetInterfaceDescriptionUtil {
382383
case "unsignedShort":
383384
case "unsignedByte":
384385
case "positiveInteger":
385-
form[v.idShort] = Number(form[v.idShort]);
386+
form[tdTerm] = Number(form[v.value]);
386387
break;
387388
// TODO handle more XSD types ?
388389
}
@@ -836,8 +837,13 @@ export class AssetInterfaceDescriptionUtil {
836837
// --> pick the first one that matches protocol (other means in future?)
837838

838839
// walk over string values like: "href", "contentType", "htv:methodName", ...
839-
for (const formTerm in formElementPicked) {
840+
for (let formTerm in formElementPicked) {
840841
const formValue = formElementPicked[formTerm];
842+
843+
// Note: AID does not allow idShort to contain values with colon (i.e., ":") --> "_" used instead
844+
// TODO are there more characters we need to deal with?
845+
formTerm = formTerm.replace(":", "_");
846+
841847
if (typeof formValue === "string") {
842848
propertyForm.push({
843849
idShort: formTerm,

packages/td-tools/test/AssetInterfaceDescriptionTest.ts

Lines changed: 153 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,157 @@ class AssetInterfaceDescriptionUtilTest {
210210
expect(tdObj.properties.device_name.forms[0]).not.to.have.property("security");
211211
}
212212

213+
@test async "should correctly roundtrip inverterModbus from/to AID"() {
214+
const aasInput = (await fs.readFile("test/util/inverterModbus.json")).toString();
215+
const td = this.assetInterfaceDescriptionUtil.transformAAS2TD(aasInput);
216+
217+
const aidOutput = this.assetInterfaceDescriptionUtil.transformTD2SM(td);
218+
219+
const smObj = JSON.parse(aidOutput);
220+
expect(smObj).to.have.property("idShort").that.equals("AssetInterfacesDescription");
221+
expect(smObj).to.have.property("submodelElements").to.be.an("array").to.have.lengthOf.greaterThan(0);
222+
const smInterface = smObj.submodelElements[0];
223+
expect(smInterface).to.have.property("value").to.be.an("array").to.have.lengthOf.greaterThan(0);
224+
let hasThingTitle = false;
225+
let hasEndpointMetadata = false;
226+
for (const smValue of smInterface.value) {
227+
if (smValue.idShort === "title") {
228+
hasThingTitle = true;
229+
expect(smValue).to.have.property("value").to.equal("Inverter GEN44");
230+
} else if (smValue.idShort === "EndpointMetadata") {
231+
hasEndpointMetadata = true;
232+
const endpointMetadata = smValue;
233+
expect(endpointMetadata).to.have.property("value").to.be.an("array").to.have.lengthOf.greaterThan(0);
234+
let hasSecurity = false;
235+
let hasSecurityDefinitions = false;
236+
for (const endpointMetadataValue of endpointMetadata.value) {
237+
if (endpointMetadataValue.idShort === "security") {
238+
hasSecurity = true;
239+
expect(endpointMetadataValue)
240+
.to.have.property("value")
241+
.to.be.an("array")
242+
.to.have.lengthOf.greaterThan(0);
243+
expect(endpointMetadataValue.value[0].value).to.equal("nosec_sc");
244+
} else if (endpointMetadataValue.idShort === "securityDefinitions") {
245+
hasSecurityDefinitions = true;
246+
expect(endpointMetadataValue)
247+
.to.have.property("value")
248+
.to.be.an("array")
249+
.to.have.lengthOf.greaterThan(0);
250+
let hasBasicSC = false;
251+
for (const securityDefinitionValue of endpointMetadataValue.value) {
252+
if (securityDefinitionValue.idShort === "nosec_sc") {
253+
hasBasicSC = true;
254+
expect(securityDefinitionValue)
255+
.to.have.property("value")
256+
.to.be.an("array")
257+
.to.have.lengthOf.greaterThan(0);
258+
let hasBasic = false;
259+
for (const sec of securityDefinitionValue.value) {
260+
if (sec.idShort === "scheme") {
261+
hasBasic = true;
262+
expect(sec.value).to.equal("nosec");
263+
}
264+
}
265+
expect(hasBasic).to.equal(true);
266+
}
267+
}
268+
expect(hasBasicSC).to.equal(true);
269+
}
270+
}
271+
expect(hasSecurity).to.equal(true);
272+
expect(hasSecurityDefinitions).to.equal(true);
273+
}
274+
}
275+
expect(hasThingTitle, "No thing title").to.equal(true);
276+
expect(hasEndpointMetadata, "No EndpointMetadata").to.equal(true);
277+
278+
// InterfaceMetadata with properties etc
279+
let hasInterfaceMetadata = false;
280+
for (const smValue of smInterface.value) {
281+
if (smValue.idShort === "InterfaceMetadata") {
282+
hasInterfaceMetadata = true;
283+
expect(smValue).to.have.property("value").to.be.an("array").to.have.lengthOf.greaterThan(0);
284+
let hasProperties = false;
285+
for (const interactionValues of smValue.value) {
286+
if (interactionValues.idShort === "properties") {
287+
hasProperties = true;
288+
expect(interactionValues)
289+
.to.have.property("value")
290+
.to.be.an("array")
291+
.to.have.lengthOf.greaterThan(0);
292+
let hasPropertyDeviceName = false;
293+
for (const propertyValue of interactionValues.value) {
294+
if (propertyValue.idShort === "device_name") {
295+
hasPropertyDeviceName = true;
296+
expect(propertyValue)
297+
.to.have.property("value")
298+
.to.be.an("array")
299+
.to.have.lengthOf.greaterThan(0);
300+
let hasType = false;
301+
let hasTitle = false;
302+
let hasForms = false;
303+
for (const propProperty of propertyValue.value) {
304+
if (propProperty.idShort === "type") {
305+
hasType = true;
306+
expect(propProperty.value).to.equal("string");
307+
} else if (propProperty.idShort === "title") {
308+
hasTitle = true;
309+
expect(propProperty.value).to.equal("Device name");
310+
} else if (propProperty.idShort === "forms") {
311+
hasForms = true;
312+
expect(propProperty)
313+
.to.have.property("value")
314+
.to.be.an("array")
315+
.to.have.lengthOf.greaterThan(0);
316+
let hasHref = false;
317+
let hasOp = false;
318+
let hasContentType = false;
319+
let hasModbusFunction = false;
320+
let hasModbusType = false;
321+
for (const formEntry of propProperty.value) {
322+
if (formEntry.idShort === "href") {
323+
hasHref = true;
324+
expect(formEntry.value).to.equal(
325+
"modbus+tcp://192.168.178.146:502/1/40020?quantity=16"
326+
);
327+
} else if (formEntry.idShort === "op") {
328+
hasOp = true;
329+
expect(formEntry.value).to.equal("readproperty");
330+
} else if (formEntry.idShort === "contentType") {
331+
hasContentType = true;
332+
expect(formEntry.value).to.equal("application/octet-stream");
333+
} else if (formEntry.idShort === "modbus_function") {
334+
// vs. "modbus:function"
335+
hasModbusFunction = true;
336+
expect(formEntry.value).to.equal("readHoldingRegisters");
337+
} else if (formEntry.idShort === "modbus_type") {
338+
// vs. "modbus:type"
339+
hasModbusType = true;
340+
expect(formEntry.value).to.equal("string");
341+
}
342+
}
343+
expect(hasHref).to.equal(true);
344+
expect(hasOp).to.equal(true);
345+
expect(hasContentType).to.equal(true);
346+
expect(hasModbusFunction).to.equal(true);
347+
expect(hasModbusType).to.equal(true);
348+
}
349+
}
350+
expect(hasType).to.equal(true);
351+
expect(hasTitle).to.equal(true);
352+
expect(hasForms).to.equal(true);
353+
}
354+
}
355+
expect(hasPropertyDeviceName).to.equal(true);
356+
}
357+
}
358+
expect(hasProperties).to.equal(true);
359+
}
360+
}
361+
expect(hasInterfaceMetadata, "No InterfaceMetadata").to.equal(true);
362+
}
363+
213364
td1Base = "https://www.example.com/";
214365
td1: ThingDescription = {
215366
"@context": "https://www.w3.org/2022/wot/td/v1.1",
@@ -242,7 +393,7 @@ class AssetInterfaceDescriptionUtilTest {
242393
},
243394
};
244395

245-
@test async "should correctly transform sample TD into JSON submodel"() {
396+
@test async "should correctly transform sample TD into AID submodel"() {
246397
const sm = this.assetInterfaceDescriptionUtil.transformTD2SM(JSON.stringify(this.td1), ["https"]);
247398

248399
const smObj = JSON.parse(sm);
@@ -358,7 +509,6 @@ class AssetInterfaceDescriptionUtilTest {
358509
let hasHref = false;
359510
let hasContentType = false;
360511
let hasHtvMethodName = false;
361-
// let hasOp = false;
362512
for (const formEntry of propProperty.value) {
363513
if (formEntry.idShort === "href") {
364514
hasHref = true;
@@ -369,18 +519,14 @@ class AssetInterfaceDescriptionUtilTest {
369519
} else if (formEntry.idShort === "contentType") {
370520
hasContentType = true;
371521
expect(formEntry.value).to.equal("application/json");
372-
} else if (formEntry.idShort === "htv:methodName") {
522+
} else if (formEntry.idShort === "htv_methodName") {
373523
hasHtvMethodName = true;
374524
expect(formEntry.value).to.equal("GET");
375-
// } else if (formEntry.idShort === "op") {
376-
// hasOp = true;
377-
// expect(formEntry.value).to.have.members(["readproperty"]);
378525
}
379526
}
380527
expect(hasHref).to.equal(true);
381528
expect(hasContentType).to.equal(true);
382529
expect(hasHtvMethodName).to.equal(true);
383-
// expect(hasOp).to.equal(true);
384530
}
385531
}
386532
expect(hasType).to.equal(true);

packages/td-tools/test/util/inverterModbus.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,13 @@
117117
"modelType": "Property"
118118
},
119119
{
120-
"idShort": "modbus:function",
120+
"idShort": "modbus_function",
121121
"valueType": "xs:string",
122122
"value": "readHoldingRegisters",
123123
"modelType": "Property"
124124
},
125125
{
126-
"idShort": "modbus:type",
126+
"idShort": "modbus_type",
127127
"valueType": "xs:string",
128128
"value": "string",
129129
"modelType": "Property"

0 commit comments

Comments
 (0)