[knx] Fix decoding of DPT 242.600 and add tests (#14875)
* [knx] Fix decoding of DPT 242.600 and add tests Correct handling of parameter Y for DPT 242.600. Add back to back tests of DPT 232.600 and 242.600, testing color conversion from raw bytes to HSB and back to Calimero color representation as String. Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
This commit is contained in:
parent
6e2dddfe73
commit
0437595678
|
@ -39,12 +39,12 @@ import tuwien.auto.calimero.serial.spi.SerialCom;
|
|||
* The {@link SerialTransportAdapter} provides org.openhab.core.io.transport.serial
|
||||
* services to the Calimero library.
|
||||
*
|
||||
* @ServiceProvider annotation (biz.aQute.bnd.annotation) automatically creates the file
|
||||
* /META-INF/services/tuwien.auto.calimero.serial.spi.SerialCom
|
||||
* to register SerialTransportAdapter to the service loader.
|
||||
* Additional attributes for SerialTansportAdapter can be specified as well, e.g.
|
||||
* attribute = { "position=1" }
|
||||
* and will be part of MANIFEST.MF
|
||||
* {@literal @}ServiceProvider annotation (biz.aQute.bnd.annotation) automatically creates the file
|
||||
* /META-INF/services/tuwien.auto.calimero.serial.spi.SerialCom
|
||||
* to register SerialTransportAdapter to the service loader.
|
||||
* Additional attributes for SerialTansportAdapter can be specified as well, e.g.
|
||||
* attribute = { "position=1" }
|
||||
* and will be part of MANIFEST.MF
|
||||
*
|
||||
* @author Holger Friedrich - Initial contribution
|
||||
*/
|
||||
|
|
|
@ -73,9 +73,10 @@ public class ValueDecoder {
|
|||
// RGBW: "100 27 25 12 %", value range: 0-100, invalid values: "-"
|
||||
private static final Pattern RGBW_PATTERN = Pattern
|
||||
.compile("(?:(?<r>[\\d,.]+)|-)\\s(?:(?<g>[\\d,.]+)|-)\\s(?:(?<b>[\\d,.]+)|-)\\s(?:(?<w>[\\d,.]+)|-)\\s%");
|
||||
// xyY: "(0,123 0,123) 56 %", value range 0-1 for xy (comma as decimal point), 0-100 for Y, invalid values omitted
|
||||
private static final Pattern XYY_PATTERN = Pattern
|
||||
.compile("(?:\\((?<x>\\d+(?:,\\d+)?) (?<y>\\d+(?:,\\d+)?)\\))?\\s*(?:(?<Y>\\d+(?:,\\d+)?)\\s%)?");
|
||||
// xyY: "(0,123 0,123) 56 %", value range 0-1 for xy (comma or point as decimal point), 0-100 for Y, invalid values
|
||||
// omitted
|
||||
public static final Pattern XYY_PATTERN = Pattern
|
||||
.compile("(?:\\((?<x>\\d+(?:[,.]\\d+)?) (?<y>\\d+(?:[,.]\\d+)?)\\))?\\s*(?:(?<Y>\\d+(?:[,.]\\d+)?)\\s%)?");
|
||||
|
||||
/**
|
||||
* convert the raw value received to the corresponding openHAB value
|
||||
|
@ -311,7 +312,7 @@ public class ValueDecoder {
|
|||
return ColorUtil.xyToHsb(new double[] { x, y });
|
||||
} else {
|
||||
double pY = Double.parseDouble(stringY.replace(",", "."));
|
||||
return ColorUtil.xyToHsb(new double[] { x, y, pY });
|
||||
return ColorUtil.xyToHsb(new double[] { x, y, pY / 100.0 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,9 @@ package org.openhab.binding.knx.internal.dpt;
|
|||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
@ -402,13 +403,79 @@ class DPTTest {
|
|||
Assertions.assertNotNull(value);
|
||||
}
|
||||
|
||||
private static Stream<String> rgbValueProvider() {
|
||||
return Stream.of("r:0 g:0 b:0", "r:255 g:255 b:255");
|
||||
private static Stream<byte[]> rgbValueProvider() {
|
||||
// Returning all combinations is too much. Implementation tries to catch rounding errors
|
||||
// but is still deterministic to get reproducible test results.
|
||||
return IntStream.range(0, 3 * 256)
|
||||
.mapToObj(i -> new byte[] { (byte) (i & 0xff), (byte) ((i / 2) & 0xff), (byte) ((i / 3) & 0xff) });
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("rgbValueProvider")
|
||||
public void rgbTest(String value) {
|
||||
Assertions.assertNotNull(ValueDecoder.decode("232.600", value.getBytes(StandardCharsets.UTF_8), HSBType.class));
|
||||
public void dpt232BackToBackTest(byte[] value) {
|
||||
backToBackTest232(value, "232.600");
|
||||
backToBackTest232(value, "232.60000");
|
||||
}
|
||||
|
||||
private void backToBackTest232(byte[] value, String dpt) {
|
||||
// decode will apply transformation from raw bytes to String internally
|
||||
HSBType hsb = (HSBType) ValueDecoder.decode(dpt, value, HSBType.class);
|
||||
Assertions.assertNotNull(hsb);
|
||||
|
||||
// encoding will return a String in notation defined by Calimero: "r:xxx g:xxx b:xxx"
|
||||
String result = ValueEncoder.encode(hsb, dpt);
|
||||
|
||||
// for back to back test, compare String representation
|
||||
Assertions.assertEquals("r:" + (value[0] & 0xff) + " g:" + (value[1] & 0xff) + " b:" + (value[2] & 0xff),
|
||||
result);
|
||||
}
|
||||
|
||||
private static Stream<byte[]> xyYValueProvider() {
|
||||
// Returning all combinations is too much. Implementation tries to catch rounding errors
|
||||
// but is still deterministic to get reproducible test results.
|
||||
//
|
||||
// Cannot run make use of full numeric range, as colors cannot be represented in CIE space and
|
||||
// back conversion would return different results.
|
||||
// Use x: 0.1 .. 0.3, y: 0.3 .. 0.5 to be inside the triangle which can be converted without loss
|
||||
return IntStream.range(77, 115).mapToObj(i -> new byte[] { (byte) ((i / 2) & 0xff), (byte) ((i) & 0xff),
|
||||
(byte) (i & 0xff), (byte) ((i / 3) & 0xff), (byte) (((i - 50) * 3) & 0xff), 3 });
|
||||
// last byte has value 3: c+b valid
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("xyYValueProvider")
|
||||
public void dpt242BackToBackTest(byte[] value) {
|
||||
final String dpt = "242.600";
|
||||
|
||||
// decode will apply transformation from raw bytes to String internally
|
||||
HSBType hsb = (HSBType) ValueDecoder.decode(dpt, value, HSBType.class);
|
||||
Assertions.assertNotNull(hsb);
|
||||
|
||||
// encoding will return a String in notation defined by Calimero: "(x,xxxx y,yyyy) YY,Y %"
|
||||
String result = ValueEncoder.encode(hsb, dpt);
|
||||
|
||||
// for back to back test, compare numerical values to allow tolerances
|
||||
double dx = (((value[0] & 0xff) << 8) | (value[1] & 0xff)) / 65535.0;
|
||||
double dy = (((value[2] & 0xff) << 8) | (value[3] & 0xff)) / 65535.0;
|
||||
double dY = ((double) (value[4] & 0xff)) * 100.0 / 255.0;
|
||||
|
||||
Matcher matcher = ValueDecoder.XYY_PATTERN.matcher(result);
|
||||
Assertions.assertTrue(matcher.matches());
|
||||
String stringx = matcher.group("x");
|
||||
String stringy = matcher.group("y");
|
||||
String stringY = matcher.group("Y");
|
||||
Assertions.assertNotNull(stringx);
|
||||
Assertions.assertNotNull(stringy);
|
||||
Assertions.assertNotNull(stringY);
|
||||
double rx = Double.parseDouble(stringx.replace(',', '.'));
|
||||
double ry = Double.parseDouble(stringy.replace(',', '.'));
|
||||
double rY = Double.parseDouble(stringY.replace(',', '.'));
|
||||
|
||||
final double tolerance = 0.001;
|
||||
if ((Math.abs(dx - rx) > tolerance) || (Math.abs(dy - ry) > tolerance)
|
||||
|| (Math.abs(dY - rY) > tolerance * 100)) {
|
||||
// print failures in a useful format
|
||||
Assertions.assertEquals(String.format("(%.4f %.4f) %.1f %%", dx, dy, dY), result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue