Skip to content

Commit

Permalink
Merge pull request eclipse-thingweb#1129 from danielpeintner/issue-1128
Browse files Browse the repository at this point in the history
feat: support special AID treatment for ranges
  • Loading branch information
relu91 authored Oct 19, 2023
2 parents 8f5b158 + de60e48 commit c14d4dd
Show file tree
Hide file tree
Showing 3 changed files with 254 additions and 7 deletions.
98 changes: 92 additions & 6 deletions packages/td-tools/src/util/asset-interface-description.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,12 +340,22 @@ export class AssetInterfaceDescriptionUtil {
for (const v of iv.value) {
// Binding
if (v.idShort === "href") {
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
} else {
form.href = v.value;
if (v.value != null) {
const hrefValue: string = v.value;
if (isAbsoluteUrl(hrefValue)) {
form.href = hrefValue;
} else if (form.href && form.href.length > 0) {
// handle leading/trailing slashes
if (form.href.endsWith("/") && hrefValue.startsWith("/")) {
form.href = form.href + hrefValue.substring(1);
} else if (!form.href.endsWith("/") && !hrefValue.startsWith("/")) {
form.href = form.href + "/" + hrefValue;
} else {
form.href = form.href + hrefValue;
}
} else {
form.href = hrefValue;
}
}
} else if (typeof v.idShort === "string" && v.idShort.length > 0) {
// pick *any* value (and possibly override, e.g. contentType)
Expand Down Expand Up @@ -632,6 +642,39 @@ export class AssetInterfaceDescriptionUtil {
thing.properties[key].readOnly = interactionValue.value === "true";
} else if (interactionValue.idShort === "writeOnly") {
thing.properties[key].writeOnly = interactionValue.value === "true";
} else if (interactionValue.idShort === "min_max") {
// special treatment
if (thing.properties[key].type == null) {
thing.properties[key].type = "number";
}
if (interactionValue.min != null) {
thing.properties[key].minimum = Number(interactionValue.min);
}
if (interactionValue.max != null) {
thing.properties[key].maximum = Number(interactionValue.max);
}
} else if (interactionValue.idShort === "itemsRange") {
// special treatment
if (thing.properties[key].type == null) {
thing.properties[key].type = "array";
}
if (interactionValue.min != null) {
thing.properties[key].minItems = Number(interactionValue.min);
}
if (interactionValue.max != null) {
thing.properties[key].maxItems = Number(interactionValue.max);
}
} else if (interactionValue.idShort === "lengthRange") {
// special treatment
if (thing.properties[key].type == null) {
thing.properties[key].type = "string";
}
if (interactionValue.min != null) {
thing.properties[key].minLength = Number(interactionValue.min);
}
if (interactionValue.max != null) {
thing.properties[key].maxLength = Number(interactionValue.max);
}
} else if (interactionValue.idShort === "forms") {
// will be handled below
} else {
Expand Down Expand Up @@ -807,6 +850,49 @@ export class AssetInterfaceDescriptionUtil {
value: propertyValue.type,
modelType: "Property",
});
// special AID treatment
if (propertyValue.minimum != null || propertyValue.maximum != null) {
const minMax: { [k: string]: unknown } = {
idShort: "min_max",
valueType: "xs:integer",
modelType: "Range",
};
if (propertyValue.minimum != null) {
minMax.min = propertyValue.minimum.toString();
}
if (propertyValue.maximum != null) {
minMax.max = propertyValue.maximum.toString();
}
propertyValues.push(minMax);
}
if (propertyValue.minItems != null || propertyValue.maxItems != null) {
const itemsRange: { [k: string]: unknown } = {
idShort: "itemsRange",
valueType: "xs:integer",
modelType: "Range",
};
if (propertyValue.minItems != null) {
itemsRange.min = propertyValue.minItems.toString();
}
if (propertyValue.maxItems != null) {
itemsRange.max = propertyValue.maxItems.toString();
}
propertyValues.push(itemsRange);
}
if (propertyValue.minLength != null || propertyValue.maxLength != null) {
const lengthRange: { [k: string]: unknown } = {
idShort: "lengthRange",
valueType: "xs:integer",
modelType: "Range",
};
if (propertyValue.minLength != null) {
lengthRange.min = propertyValue.minLength.toString();
}
if (propertyValue.maxLength != null) {
lengthRange.max = propertyValue.maxLength.toString();
}
propertyValues.push(lengthRange);
}
}
// title
if (propertyValue.title != null) {
Expand Down
102 changes: 101 additions & 1 deletion packages/td-tools/test/AssetInterfaceDescriptionTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class AssetInterfaceDescriptionUtilTest {
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
// check property device_name
expect(tdObj).to.have.property("properties").to.have.property("device_name");
expect(tdObj)
.to.have.property("properties")
Expand Down Expand Up @@ -208,6 +208,39 @@ class AssetInterfaceDescriptionUtilTest {
.to.have.property("contentType")
.to.eql("application/octet-stream");
expect(tdObj.properties.device_name.forms[0]).not.to.have.property("security");

// check property soc
expect(tdObj).to.have.property("properties").to.have.property("soc");
expect(tdObj)
.to.have.property("properties")
.to.have.property("soc")
.to.have.property("type")
.that.equals("integer");
expect(tdObj).to.have.property("properties").to.have.property("soc").to.have.property("minimum").that.equals(0);
expect(tdObj)
.to.have.property("properties")
.to.have.property("soc")
.to.have.property("maximum")
.that.equals(100);
expect(tdObj)
.to.have.property("properties")
.to.have.property("soc")
.to.have.property("title")
.that.equals("Battery SoC scaled in %");
expect(tdObj)
.to.have.property("properties")
.to.have.property("soc")
.to.have.property("forms")
.to.be.an("array")
.to.have.lengthOf(1);
expect(tdObj.properties.soc.forms[0]).to.have.property("op").to.eql("readproperty");
expect(tdObj.properties.soc.forms[0])
.to.have.property("href")
.to.eql("modbus+tcp://192.168.178.146:502/40361?quantity=1");
expect(tdObj.properties.soc.forms[0]).to.have.property("modbus:function").to.eql("readHoldingRegisters");
expect(tdObj.properties.soc.forms[0]).to.have.property("modbus:type").to.eql("uint16be");
expect(tdObj.properties.soc.forms[0]).to.have.property("contentType").to.eql("application/octet-stream");
expect(tdObj.properties.device_name.forms[0]).not.to.have.property("security");
}

@test async "should correctly roundtrip inverterModbus from/to AID"() {
Expand Down Expand Up @@ -290,6 +323,7 @@ class AssetInterfaceDescriptionUtilTest {
.to.be.an("array")
.to.have.lengthOf.greaterThan(0);
let hasPropertyDeviceName = false;
let hasPropertySOC = false;
for (const propertyValue of interactionValues.value) {
if (propertyValue.idShort === "device_name") {
hasPropertyDeviceName = true;
Expand Down Expand Up @@ -350,9 +384,75 @@ class AssetInterfaceDescriptionUtilTest {
expect(hasType).to.equal(true);
expect(hasTitle).to.equal(true);
expect(hasForms).to.equal(true);
} else if (propertyValue.idShort === "soc") {
hasPropertySOC = true;
expect(propertyValue)
.to.have.property("value")
.to.be.an("array")
.to.have.lengthOf.greaterThan(0);
let hasType = false;
let hasTitle = false;
let hasMinMax = false;
let hasForms = false;
for (const propProperty of propertyValue.value) {
if (propProperty.idShort === "type") {
hasType = true;
expect(propProperty.value).to.equal("integer");
} else if (propProperty.idShort === "title") {
hasTitle = true;
expect(propProperty.value).to.equal("Battery SoC scaled in %");
} else if (propProperty.idShort === "min_max") {
hasMinMax = true;
expect(propProperty.min).to.equal("0");
expect(propProperty.max).to.equal("100");
} else if (propProperty.idShort === "forms") {
hasForms = true;
expect(propProperty)
.to.have.property("value")
.to.be.an("array")
.to.have.lengthOf.greaterThan(0);
let hasHref = false;
let hasOp = false;
let hasContentType = false;
let hasModbusFunction = false;
let hasModbusType = false;
for (const formEntry of propProperty.value) {
if (formEntry.idShort === "href") {
hasHref = true;
expect(formEntry.value).to.equal(
"modbus+tcp://192.168.178.146:502/40361?quantity=1"
);
} else if (formEntry.idShort === "op") {
hasOp = true;
expect(formEntry.value).to.equal("readproperty");
} else if (formEntry.idShort === "contentType") {
hasContentType = true;
expect(formEntry.value).to.equal("application/octet-stream");
} else if (formEntry.idShort === "modbus_function") {
// vs. "modbus:function"
hasModbusFunction = true;
expect(formEntry.value).to.equal("readHoldingRegisters");
} else if (formEntry.idShort === "modbus_type") {
// vs. "modbus:type"
hasModbusType = true;
expect(formEntry.value).to.equal("uint16be");
}
}
expect(hasHref).to.equal(true);
expect(hasOp).to.equal(true);
expect(hasContentType).to.equal(true);
expect(hasModbusFunction).to.equal(true);
expect(hasModbusType).to.equal(true);
}
}
expect(hasType).to.equal(true);
expect(hasTitle).to.equal(true);
expect(hasMinMax).to.equal(true);
expect(hasForms).to.equal(true);
}
}
expect(hasPropertyDeviceName).to.equal(true);
expect(hasPropertySOC).to.equal(true);
}
}
expect(hasProperties).to.equal(true);
Expand Down
Loading

0 comments on commit c14d4dd

Please sign in to comment.