2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.knx.internal.channel;
15 import static org.hamcrest.MatcherAssert.assertThat;
16 import static org.hamcrest.Matchers.*;
17 import static org.junit.jupiter.api.Assertions.*;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.when;
21 import java.util.List;
23 import java.util.Objects;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.junit.jupiter.api.Test;
29 import org.openhab.binding.knx.internal.KNXBindingConstants;
30 import org.openhab.binding.knx.internal.client.OutboundSpec;
31 import org.openhab.binding.knx.internal.dpt.ValueEncoder;
32 import org.openhab.core.config.core.Configuration;
33 import org.openhab.core.library.items.ColorItem;
34 import org.openhab.core.library.types.HSBType;
35 import org.openhab.core.library.types.PercentType;
36 import org.openhab.core.thing.Channel;
37 import org.openhab.core.thing.type.ChannelTypeUID;
38 import org.openhab.core.types.Command;
39 import org.openhab.core.types.UnDefType;
41 import tuwien.auto.calimero.GroupAddress;
42 import tuwien.auto.calimero.KNXFormatException;
46 * @author Simon Kaufmann - Initial contribution
50 class KNXChannelTest {
53 public void invalidFails() {
54 GroupAddressConfiguration res = GroupAddressConfiguration.parse("5.001:<1/3/22+0/3/22+<0/8/15");
59 void testParseWithDptMultipleWithRead() throws KNXFormatException {
60 GroupAddressConfiguration res = GroupAddressConfiguration.parse("5.001:<1/3/22+0/3/22+<0/7/15");
67 assertEquals("5.001", res.getDPT());
68 assertEquals(new GroupAddress("1/3/22"), res.getMainGA());
69 assertTrue(res.getReadGAs().contains(res.getMainGA()));
70 assertEquals(3, res.getListenGAs().size());
71 assertEquals(2, res.getReadGAs().size());
75 void testParseWithDptMultipleWithoutRead() throws KNXFormatException {
76 GroupAddressConfiguration res = GroupAddressConfiguration.parse("5.001:1/3/22+0/3/22+0/7/15");
83 assertEquals("5.001", res.getDPT());
84 assertEquals(new GroupAddress("1/3/22"), res.getMainGA());
85 assertFalse(res.getReadGAs().contains(res.getMainGA()));
86 assertEquals(3, res.getListenGAs().size());
87 assertEquals(0, res.getReadGAs().size());
91 void testParseWithoutDptSingleWithoutRead() throws KNXFormatException {
92 GroupAddressConfiguration res = GroupAddressConfiguration.parse("1/3/22");
99 assertNull(res.getDPT());
100 assertEquals(new GroupAddress("1/3/22"), res.getMainGA());
101 assertFalse(res.getReadGAs().contains(res.getMainGA()));
102 assertEquals(1, res.getListenGAs().size());
103 assertEquals(0, res.getReadGAs().size());
107 void testParseWithoutDptSingleWithRead() throws KNXFormatException {
108 GroupAddressConfiguration res = GroupAddressConfiguration.parse("<1/3/22");
115 assertNull(res.getDPT());
116 assertEquals(new GroupAddress("1/3/22"), res.getMainGA());
117 assertTrue(res.getReadGAs().contains(res.getMainGA()));
118 assertEquals(1, res.getListenGAs().size());
119 assertEquals(1, res.getReadGAs().size());
123 void testParseTwoLevel() throws KNXFormatException {
124 GroupAddressConfiguration res = GroupAddressConfiguration.parse("5.001:<3/1024+<4/1025");
131 assertEquals(new GroupAddress("3/1024"), res.getMainGA());
132 assertTrue(res.getReadGAs().contains(res.getMainGA()));
133 assertEquals(2, res.getListenGAs().size());
134 assertEquals(2, res.getReadGAs().size());
138 void testParseFreeLevel() throws KNXFormatException {
139 GroupAddressConfiguration res = GroupAddressConfiguration.parse("5.001:<4610+<4611");
146 assertEquals(new GroupAddress("4610"), res.getMainGA());
147 assertEquals(2, res.getListenGAs().size());
148 assertEquals(2, res.getReadGAs().size());
152 public void testChannelGaParsing() throws KNXFormatException {
153 Channel channel = Objects.requireNonNull(mock(Channel.class));
154 Configuration configuration = new Configuration(
155 Map.of("key1", "5.001:<1/2/3+4/5/6+1/5/6", "key2", "1.001:7/1/9+1/1/2"));
156 when(channel.getChannelTypeUID()).thenReturn(new ChannelTypeUID("a:b:c"));
157 when(channel.getConfiguration()).thenReturn(configuration);
158 when(channel.getAcceptedItemType()).thenReturn("none");
160 MyKNXChannel knxChannel = new MyKNXChannel(channel);
162 Set<GroupAddress> listenAddresses = knxChannel.getAllGroupAddresses();
163 assertEquals(5, listenAddresses.size());
164 // we don't check the content since parsing has been checked before and the quantity is correct
165 Set<GroupAddress> writeAddresses = knxChannel.getWriteAddresses();
166 assertEquals(2, writeAddresses.size());
167 assertTrue(writeAddresses.contains(new GroupAddress("1/2/3")));
168 assertTrue(writeAddresses.contains(new GroupAddress("7/1/9")));
172 void testSubTypeMapping() throws KNXFormatException {
173 Channel channel = Objects.requireNonNull(mock(Channel.class));
174 Configuration configuration = new Configuration(Map.of("key1", "1.001:1/2/3"));
175 when(channel.getChannelTypeUID()).thenReturn(new ChannelTypeUID("a:b:c"));
176 when(channel.getConfiguration()).thenReturn(configuration);
177 when(channel.getAcceptedItemType()).thenReturn(ColorItem.class.getName());
178 MyKNXChannel knxChannel = new MyKNXChannel(channel);
179 assertNotNull(knxChannel.getCommandSpec(new HSBType("0,100,100")));
181 OutboundSpec outboundSpec = knxChannel.getCommandSpec(new HSBType("0,100,100"));
182 assertNotNull(outboundSpec);
183 assertEquals(outboundSpec.getDPT(), "1.001");
187 void test5001PercentType() throws KNXFormatException {
188 Configuration configuration = new Configuration(Map.of("switch", "1.001:1/2/1", "position", "5.001:1/2/2"));
189 Channel channel = Objects.requireNonNull(mock(Channel.class));
190 when(channel.getChannelTypeUID())
191 .thenReturn(new ChannelTypeUID(KNXBindingConstants.BINDING_ID, KNXBindingConstants.CHANNEL_DIMMER));
192 when(channel.getConfiguration()).thenReturn(configuration);
194 KNXChannel knxChannel = KNXChannelFactory.createKnxChannel(channel);
195 assertThat(knxChannel, instanceOf(TypeDimmer.class));
197 Command command = new PercentType("100");
199 OutboundSpec outboundSpec = knxChannel.getCommandSpec(command);
200 assertNotNull(outboundSpec);
202 String mappedValue = ValueEncoder.encode(outboundSpec.getValue(), outboundSpec.getDPT());
203 assertThat(mappedValue, is("100"));
204 assertThat(outboundSpec.getValue(), is(instanceOf(PercentType.class)));
207 private static class MyKNXChannel extends KNXChannel {
208 public MyKNXChannel(Channel channel) {
209 super(Set.of("key1", "key2"), List.of(UnDefType.class), channel);
213 protected String getDefaultDPT(String gaConfigKey) {