]> git.basschouten.com Git - openhab-addons.git/blob
5b75c56bbd67becf063d054b020a2c7960eeaec7
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.HashSet;
20 import java.util.LinkedList;
21 import java.util.List;
22 import java.util.Objects;
23 import java.util.Optional;
24 import java.util.Set;
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
27
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.eclipse.jdt.annotation.Nullable;
30 import org.openhab.binding.knx.internal.KNXTypeMapper;
31 import org.openhab.binding.knx.internal.client.InboundSpec;
32 import org.openhab.binding.knx.internal.client.OutboundSpec;
33 import org.openhab.core.config.core.Configuration;
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 import tuwien.auto.calimero.KNXFormatException;
40
41 /**
42  * Meta-data abstraction for the KNX channel configurations.
43  *
44  * @author Simon Kaufmann - initial contribution and API.
45  *
46  */
47 @NonNullByDefault
48 public abstract class KNXChannelType {
49
50     private static final Pattern PATTERN = Pattern.compile(
51             "^((?<dpt>[0-9]{1,3}\\.[0-9]{3,4}):)?(?<read>\\<)?(?<mainGA>[0-9]{1,5}(/[0-9]{1,4}){0,2})(?<listenGAs>(\\+(\\<?[0-9]{1,5}(/[0-9]{1,4}){0,2}))*)$");
52
53     private static final Pattern PATTERN_LISTEN = Pattern
54             .compile("\\+((?<read>\\<)?(?<GA>[0-9]{1,5}(/[0-9]{1,4}){0,2}))");
55
56     private final Logger logger = LoggerFactory.getLogger(KNXChannelType.class);
57     private final Set<String> channelTypeIDs;
58
59     KNXChannelType(String... channelTypeIDs) {
60         this.channelTypeIDs = new HashSet<>(Arrays.asList(channelTypeIDs));
61     }
62
63     final Set<String> getChannelIDs() {
64         return channelTypeIDs;
65     }
66
67     @Nullable
68     protected final ChannelConfiguration parse(@Nullable String fancy) {
69         if (fancy == null) {
70             return null;
71         }
72         Matcher matcher = PATTERN.matcher(fancy.replace(" ", ""));
73
74         if (matcher.matches()) {
75             // Listen GAs
76             String input = matcher.group("listenGAs");
77             Matcher m2 = PATTERN_LISTEN.matcher(input);
78             List<GroupAddressConfiguration> listenGAs = new LinkedList<>();
79             while (m2.find()) {
80                 listenGAs.add(new GroupAddressConfiguration(m2.group("GA"), m2.group("read") != null));
81             }
82
83             // Main GA
84             GroupAddressConfiguration mainGA = new GroupAddressConfiguration(matcher.group("mainGA"),
85                     matcher.group("read") != null);
86
87             return new ChannelConfiguration(matcher.group("dpt"), mainGA, listenGAs);
88         }
89         return null;
90     }
91
92     protected abstract Set<String> getAllGAKeys();
93
94     public final Set<GroupAddress> getListenAddresses(Configuration channelConfiguration) {
95         Set<GroupAddress> ret = new HashSet<>();
96         for (String key : getAllGAKeys()) {
97             ChannelConfiguration conf = parse((String) channelConfiguration.get(key));
98             if (conf != null) {
99                 ret.addAll(conf.getListenGAs().stream().map(this::toGroupAddress).collect(toSet()));
100             }
101         }
102         return ret;
103     }
104
105     public final Set<GroupAddress> getReadAddresses(Configuration channelConfiguration) {
106         Set<GroupAddress> ret = new HashSet<>();
107         for (String key : getAllGAKeys()) {
108             ChannelConfiguration conf = parse((String) channelConfiguration.get(key));
109             if (conf != null) {
110                 ret.addAll(conf.getReadGAs().stream().map(this::toGroupAddress).collect(toSet()));
111             }
112         }
113         return ret;
114     }
115
116     public final Set<GroupAddress> getWriteAddresses(Configuration channelConfiguration) {
117         Set<GroupAddress> ret = new HashSet<>();
118         for (String key : getAllGAKeys()) {
119             ChannelConfiguration conf = parse((String) channelConfiguration.get(key));
120             if (conf != null) {
121                 GroupAddress ga = toGroupAddress(conf.getMainGA());
122                 if (ga != null) {
123                     ret.add(ga);
124                 }
125             }
126         }
127         return ret;
128     }
129
130     private @Nullable GroupAddress toGroupAddress(GroupAddressConfiguration ga) {
131         try {
132             return new GroupAddress(ga.getGA());
133         } catch (KNXFormatException e) {
134             logger.warn("Could not parse group address '{}'", ga.getGA());
135         }
136         return null;
137     }
138
139     protected final Set<GroupAddress> getAddresses(@Nullable Configuration configuration, Iterable<String> addresses)
140             throws KNXFormatException {
141         Set<GroupAddress> ret = new HashSet<>();
142         for (String address : addresses) {
143             if (configuration != null && configuration.get(address) != null) {
144                 ret.add(new GroupAddress((String) configuration.get(address)));
145             }
146         }
147         return ret;
148     }
149
150     protected final boolean isEquals(@Nullable Configuration configuration, String address, GroupAddress groupAddress)
151             throws KNXFormatException {
152         if (configuration != null && configuration.get(address) != null) {
153             return Objects.equals(new GroupAddress((String) configuration.get(address)), groupAddress);
154         }
155         return false;
156     }
157
158     protected final Set<String> asSet(String... values) {
159         return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(values)));
160     }
161
162     public final @Nullable OutboundSpec getCommandSpec(Configuration configuration, KNXTypeMapper typeHelper,
163             Type command) throws KNXFormatException {
164         logger.trace("getCommandSpec testing Keys '{}' for command '{}'", getAllGAKeys(), command);
165         for (String key : getAllGAKeys()) {
166             ChannelConfiguration config = parse((String) configuration.get(key));
167             if (config != null) {
168                 String dpt = config.getDPT();
169                 if (dpt == null) {
170                     dpt = getDefaultDPT(key);
171                 }
172                 Class<? extends Type> expectedTypeClass = typeHelper.toTypeClass(dpt);
173                 if (expectedTypeClass != null) {
174                     if (expectedTypeClass.isInstance(command)) {
175                         logger.trace(
176                                 "getCommandSpec key '{}' uses expectedTypeClass '{}' witch isInstance for command '{}' and dpt '{}'",
177                                 key, expectedTypeClass, command, dpt);
178                         return new WriteSpecImpl(config, dpt, command);
179                     }
180                 }
181             }
182         }
183         logger.trace("getCommandSpec no Spec found!");
184         return null;
185     }
186
187     public final List<InboundSpec> getReadSpec(Configuration configuration) throws KNXFormatException {
188         return getAllGAKeys().stream()
189                 .map(key -> new ReadRequestSpecImpl(parse((String) configuration.get(key)), getDefaultDPT(key)))
190                 .filter(spec -> !spec.getGroupAddresses().isEmpty()).collect(toList());
191     }
192
193     public final @Nullable InboundSpec getListenSpec(Configuration configuration, GroupAddress groupAddress) {
194         Optional<ListenSpecImpl> result = getAllGAKeys().stream()
195                 .map(key -> new ListenSpecImpl(parse((String) configuration.get(key)), getDefaultDPT(key)))
196                 .filter(spec -> !spec.getGroupAddresses().isEmpty())
197                 .filter(spec -> spec.getGroupAddresses().contains(groupAddress)).findFirst();
198         return result.isPresent() ? result.get() : null;
199     }
200
201     protected abstract String getDefaultDPT(String gaConfigKey);
202
203     public final @Nullable OutboundSpec getResponseSpec(Configuration configuration, GroupAddress groupAddress,
204             Type type) throws KNXFormatException {
205         Optional<ReadResponseSpecImpl> result = getAllGAKeys().stream()
206                 .map(key -> new ReadResponseSpecImpl(parse((String) configuration.get(key)), getDefaultDPT(key), type))
207                 .filter(spec -> groupAddress.equals(spec.getGroupAddress())).findFirst();
208         return result.isPresent() ? result.get() : null;
209     }
210
211     @Override
212     public String toString() {
213         return channelTypeIDs.toString();
214     }
215 }