[knx] Fix IOOB exception with missing DPT in number channels (#15730)

* Fix IOOB exception with missing DPT in number channels

Also improves test messages for DPT unit tests

Signed-off-by: Jan N. Klug <github@klug.nrw>
Co-authored-by: Holger Friedrich <mail@holger-friedrich.de>
This commit is contained in:
J-N-K 2023-12-06 07:53:16 +01:00 committed by GitHub
parent 58a8580a97
commit c44c9dc67e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 21 additions and 9 deletions

View File

@ -63,8 +63,8 @@ public class DPTUnits {
* *
* @return stream of all unit strings * @return stream of all unit strings
*/ */
static Stream<String> getAllUnitStrings() { static Stream<Map.Entry<String, String>> getAllUnitStrings() {
return DPT_UNIT_MAP.values().stream(); return DPT_UNIT_MAP.entrySet().stream();
} }
static { static {

View File

@ -120,13 +120,16 @@ public class DeviceThingHandler extends BaseThingHandler implements GroupAddress
for (Channel channel : getThing().getChannels()) { for (Channel channel : getThing().getChannels()) {
KNXChannel knxChannel = KNXChannelFactory.createKnxChannel(channel); KNXChannel knxChannel = KNXChannelFactory.createKnxChannel(channel);
knxChannels.put(channel.getUID(), knxChannel);
groupAddresses.addAll(knxChannel.getAllGroupAddresses());
if (knxChannel.getChannelType().startsWith("number")) { if (knxChannel.getChannelType().startsWith("number")) {
// check if we need to update the accepted item-type // check if we need to update the accepted item-type
List<InboundSpec> inboundSpecs = knxChannel.getAllGroupAddresses().stream() List<InboundSpec> inboundSpecs = knxChannel.getAllGroupAddresses().stream()
.map(knxChannel::getListenSpec).filter(Objects::nonNull).map(Objects::requireNonNull).toList(); .map(knxChannel::getListenSpec).filter(Objects::nonNull).map(Objects::requireNonNull).toList();
if (inboundSpecs.isEmpty()) {
logger.warn("Skipping {}: group address / DPT not according to Group Address Notation",
channel.getUID());
continue;
}
String dpt = inboundSpecs.get(0).getDPT(); // there can be only one DPT on number channels String dpt = inboundSpecs.get(0).getDPT(); // there can be only one DPT on number channels
Unit<?> unit = UnitUtils.parseUnit(DPTUnits.getUnitForDpt(dpt)); Unit<?> unit = UnitUtils.parseUnit(DPTUnits.getUnitForDpt(dpt));
@ -149,6 +152,10 @@ public class DeviceThingHandler extends BaseThingHandler implements GroupAddress
modified = true; modified = true;
} }
} }
// add channels only if they could be successfully processed
knxChannels.put(channel.getUID(), knxChannel);
groupAddresses.addAll(knxChannel.getAllGroupAddresses());
} }
if (modified) { if (modified) {

View File

@ -14,6 +14,7 @@ package org.openhab.binding.knx.internal.dpt;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -386,16 +387,20 @@ class DPTTest {
assertNotEquals(DPTXlator64BitSigned.DPT_REACTIVE_ENERGY.getUnit(), Units.VAR_HOUR.toString()); assertNotEquals(DPTXlator64BitSigned.DPT_REACTIVE_ENERGY.getUnit(), Units.VAR_HOUR.toString());
} }
private static Stream<String> unitProvider() { private static Stream<Map.Entry<String, String>> unitProvider() {
return DPTUnits.getAllUnitStrings(); return DPTUnits.getAllUnitStrings();
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("unitProvider") @MethodSource("unitProvider")
public void unitsValid(String unit) { public void unitsValid(Map.Entry<String, String> unit) {
String valueStr = "1 " + unit; String valueStr = "1 " + unit.getValue();
QuantityType<?> value = new QuantityType<>(valueStr); try {
Assertions.assertNotNull(value); QuantityType<?> value = new QuantityType<>(valueStr);
Assertions.assertNotNull(value, "Failed to parse " + unit + "(result null)");
} catch (Exception e) {
fail("Failed to parse " + unit + ": " + e.getMessage());
}
} }
private static Stream<byte[]> rgbValueProvider() { private static Stream<byte[]> rgbValueProvider() {