[knx] Correctly support state sub-types for DPTs (#16337)

Signed-off-by: Kai Kreuzer <kai@openhab.org>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Kai Kreuzer 2024-02-02 20:13:11 +01:00 committed by Ciprian Pascu
parent 712edea9fc
commit f25c6f17b8
2 changed files with 33 additions and 8 deletions

View File

@ -12,9 +12,8 @@
*/
package org.openhab.binding.knx.internal.channel;
import static java.util.stream.Collectors.*;
import static org.openhab.binding.knx.internal.KNXBindingConstants.CONTROL_CHANNEL_TYPES;
import static org.openhab.binding.knx.internal.KNXBindingConstants.GA;
import static java.util.stream.Collectors.toList;
import static org.openhab.binding.knx.internal.KNXBindingConstants.*;
import java.util.HashMap;
import java.util.HashSet;
@ -31,6 +30,7 @@ import org.openhab.binding.knx.internal.dpt.DPTUtil;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.types.State;
import org.openhab.core.types.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -121,11 +121,22 @@ public abstract class KNXChannel {
logger.trace("getCommandSpec checking keys '{}' for command '{}' ({})", gaKeys, command, command.getClass());
for (Map.Entry<String, GroupAddressConfiguration> entry : groupAddressConfigurations.entrySet()) {
String dpt = Objects.requireNonNullElse(entry.getValue().getDPT(), getDefaultDPT(entry.getKey()));
Set<Class<? extends Type>> expectedTypeClass = DPTUtil.getAllowedTypes(dpt);
if (expectedTypeClass.contains(command.getClass())) {
logger.trace("getCommandSpec key '{}' has expectedTypeClass '{}', matching command '{}' and dpt '{}'",
entry.getKey(), expectedTypeClass, command, dpt);
Set<Class<? extends Type>> expectedTypeClasses = DPTUtil.getAllowedTypes(dpt);
// find the first matching type that is assignable from the command
for (Class<? extends Type> expectedTypeClass : expectedTypeClasses) {
if (expectedTypeClass.equals(command.getClass())) {
logger.trace("getCommandSpec command class matches expected type class");
return new WriteSpecImpl(entry.getValue(), dpt, command);
} else if (command instanceof State state && State.class.isAssignableFrom(expectedTypeClass)) {
if (state.as(expectedTypeClass.asSubclass(State.class)) != null) {
logger.trace("getCommandSpec command class is a sub-class of the expected type class");
Class<? extends State> expectedTypeAsStateClass = expectedTypeClass.asSubclass(State.class);
State convertedState = state.as(expectedTypeAsStateClass);
if (convertedState != null) {
return new WriteSpecImpl(entry.getValue(), dpt, convertedState);
}
}
}
}
}
logger.trace("getCommandSpec no Spec found!");

View File

@ -24,6 +24,8 @@ import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.items.ColorItem;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.UnDefType;
@ -158,6 +160,18 @@ class KNXChannelTest {
assertTrue(writeAddresses.contains(new GroupAddress("7/1/9")));
}
@Test
void testSubTypeMapping() throws KNXFormatException {
Channel channel = Objects.requireNonNull(mock(Channel.class));
Configuration configuration = new Configuration(Map.of("key1", "1.001:1/2/3"));
when(channel.getChannelTypeUID()).thenReturn(new ChannelTypeUID("a:b:c"));
when(channel.getConfiguration()).thenReturn(configuration);
when(channel.getAcceptedItemType()).thenReturn(ColorItem.class.getName());
MyKNXChannel knxChannel = new MyKNXChannel(channel);
assertNotNull(knxChannel.getCommandSpec(new HSBType("0,100,100")));
assertEquals(knxChannel.getCommandSpec(new HSBType("0,100,100")).getDPT(), "1.001");
}
private static class MyKNXChannel extends KNXChannel {
public MyKNXChannel(Channel channel) {
super(Set.of("key1", "key2"), List.of(UnDefType.class), channel);