]> git.basschouten.com Git - openhab-addons.git/blob
4f53e6bd3f93bf9e6bf9b7f16e1ddb3b56af1610
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.knx.internal.channel;
14
15 import static java.util.stream.Collectors.*;
16 import static org.openhab.binding.knx.internal.KNXBindingConstants.CONTROL_CHANNEL_TYPES;
17 import static org.openhab.binding.knx.internal.KNXBindingConstants.GA;
18
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Objects;
24 import java.util.Set;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.binding.knx.internal.client.InboundSpec;
29 import org.openhab.binding.knx.internal.client.OutboundSpec;
30 import org.openhab.binding.knx.internal.dpt.DPTUtil;
31 import org.openhab.core.config.core.Configuration;
32 import org.openhab.core.thing.Channel;
33 import org.openhab.core.thing.ChannelUID;
34 import org.openhab.core.types.Type;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import tuwien.auto.calimero.GroupAddress;
39
40 /**
41  * Meta-data abstraction for the KNX channel configurations.
42  *
43  * @author Simon Kaufmann - initial contribution and API
44  * @author Jan N. Klug - refactored from type definition to channel instance
45  *
46  */
47 @NonNullByDefault
48 public abstract class KNXChannel {
49     private final Logger logger = LoggerFactory.getLogger(KNXChannel.class);
50     private final Set<String> gaKeys;
51
52     private final Map<String, GroupAddressConfiguration> groupAddressConfigurations = new HashMap<>();
53     private final Set<GroupAddress> listenAddresses = new HashSet<>();
54     private final Set<GroupAddress> writeAddresses = new HashSet<>();
55     private final String channelType;
56     private final ChannelUID channelUID;
57     private final boolean isControl;
58     private final Class<? extends Type> preferredType;
59
60     KNXChannel(List<Class<? extends Type>> acceptedTypes, Channel channel) {
61         this(Set.of(GA), acceptedTypes, channel);
62     }
63
64     KNXChannel(Set<String> gaKeys, List<Class<? extends Type>> acceptedTypes, Channel channel) {
65         this.gaKeys = gaKeys;
66         this.preferredType = acceptedTypes.get(0);
67
68         // this is safe because we already checked the presence of the ChannelTypeUID before
69         this.channelType = Objects.requireNonNull(channel.getChannelTypeUID()).getId();
70         this.channelUID = channel.getUID();
71         this.isControl = CONTROL_CHANNEL_TYPES.contains(channelType);
72
73         // build map of ChannelConfigurations and GA lists
74         Configuration configuration = channel.getConfiguration();
75         gaKeys.forEach(key -> {
76             GroupAddressConfiguration groupAddressConfiguration = GroupAddressConfiguration
77                     .parse(configuration.get(key));
78             if (groupAddressConfiguration != null) {
79                 // check DPT configuration (if set) is compatible with item
80                 String dpt = groupAddressConfiguration.getDPT();
81                 if (dpt != null) {
82                     Set<Class<? extends Type>> types = DPTUtil.getAllowedTypes(dpt);
83                     if (acceptedTypes.stream().noneMatch(types::contains)) {
84                         logger.warn("Configured DPT '{}' is incompatible with accepted types '{}' for channel '{}'",
85                                 dpt, acceptedTypes, channelUID);
86                     }
87                 }
88                 groupAddressConfigurations.put(key, groupAddressConfiguration);
89                 // store address configuration for re-use
90                 listenAddresses.addAll(groupAddressConfiguration.getListenGAs());
91                 writeAddresses.add(groupAddressConfiguration.getMainGA());
92             }
93         });
94     }
95
96     public String getChannelType() {
97         return channelType;
98     }
99
100     public ChannelUID getChannelUID() {
101         return channelUID;
102     }
103
104     public boolean isControl() {
105         return isControl;
106     }
107
108     public Class<? extends Type> preferredType() {
109         return preferredType;
110     }
111
112     public final Set<GroupAddress> getAllGroupAddresses() {
113         return listenAddresses;
114     }
115
116     public final Set<GroupAddress> getWriteAddresses() {
117         return writeAddresses;
118     }
119
120     public final @Nullable OutboundSpec getCommandSpec(Type command) {
121         logger.trace("getCommandSpec checking keys '{}' for command '{}' ({})", gaKeys, command, command.getClass());
122         for (Map.Entry<String, GroupAddressConfiguration> entry : groupAddressConfigurations.entrySet()) {
123             String dpt = Objects.requireNonNullElse(entry.getValue().getDPT(), getDefaultDPT(entry.getKey()));
124             Set<Class<? extends Type>> expectedTypeClass = DPTUtil.getAllowedTypes(dpt);
125             if (expectedTypeClass.contains(command.getClass())) {
126                 logger.trace("getCommandSpec key '{}' has expectedTypeClass '{}', matching command '{}' and dpt '{}'",
127                         entry.getKey(), expectedTypeClass, command, dpt);
128                 return new WriteSpecImpl(entry.getValue(), dpt, command);
129             }
130         }
131         logger.trace("getCommandSpec no Spec found!");
132         return null;
133     }
134
135     public final List<InboundSpec> getReadSpec() {
136         return groupAddressConfigurations.entrySet().stream()
137                 .map(entry -> new ReadRequestSpecImpl(entry.getValue(), getDefaultDPT(entry.getKey())))
138                 .filter(spec -> !spec.getGroupAddresses().isEmpty()).collect(toList());
139     }
140
141     public final @Nullable InboundSpec getListenSpec(GroupAddress groupAddress) {
142         return groupAddressConfigurations.entrySet().stream()
143                 .map(entry -> new ListenSpecImpl(entry.getValue(), getDefaultDPT(entry.getKey())))
144                 .filter(spec -> spec.getGroupAddresses().contains(groupAddress)).findFirst().orElse(null);
145     }
146
147     public final @Nullable OutboundSpec getResponseSpec(GroupAddress groupAddress, Type value) {
148         return groupAddressConfigurations.entrySet().stream()
149                 .map(entry -> new ReadResponseSpecImpl(entry.getValue(), getDefaultDPT(entry.getKey()), value))
150                 .filter(spec -> spec.matchesDestination(groupAddress)).findFirst().orElse(null);
151     }
152
153     protected abstract String getDefaultDPT(String gaConfigKey);
154 }