]> git.basschouten.com Git - openhab-addons.git/blob
ba4f1f8b4144d834780d8f5ef59558b26a658394
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.mqtt.homeassistant.internal;
14
15 import java.util.List;
16 import java.util.Map;
17 import java.util.TreeMap;
18 import java.util.concurrent.CompletableFuture;
19 import java.util.concurrent.ScheduledExecutorService;
20 import java.util.stream.Collectors;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
25 import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
26 import org.openhab.binding.mqtt.generic.utils.FutureCollector;
27 import org.openhab.binding.mqtt.generic.values.Value;
28 import org.openhab.binding.mqtt.homeassistant.generic.internal.MqttBindingConstants;
29 import org.openhab.binding.mqtt.homeassistant.internal.CFactory.ComponentConfiguration;
30 import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
31 import org.openhab.core.thing.ChannelGroupUID;
32 import org.openhab.core.thing.type.ChannelDefinition;
33 import org.openhab.core.thing.type.ChannelGroupDefinition;
34 import org.openhab.core.thing.type.ChannelGroupType;
35 import org.openhab.core.thing.type.ChannelGroupTypeBuilder;
36 import org.openhab.core.thing.type.ChannelGroupTypeUID;
37
38 /**
39  * A HomeAssistant component is comparable to an ESH channel group.
40  * It has a name and consists of multiple channels.
41  *
42  * @author David Graeff - Initial contribution
43  * @param <C> Config class derived from {@link BaseChannelConfiguration}
44  */
45 @NonNullByDefault
46 public abstract class AbstractComponent<C extends BaseChannelConfiguration> {
47     // Component location fields
48     private final ComponentConfiguration componentConfiguration;
49     protected final ChannelGroupTypeUID channelGroupTypeUID;
50     protected final ChannelGroupUID channelGroupUID;
51     protected final HaID haID;
52
53     // Channels and configuration
54     protected final Map<String, CChannel> channels = new TreeMap<>();
55     // The hash code ({@link String#hashCode()}) of the configuration string
56     // Used to determine if a component has changed.
57     protected final int configHash;
58     protected final String channelConfigurationJson;
59     protected final C channelConfiguration;
60
61     protected boolean configSeen;
62
63     /**
64      * Provide a thingUID and HomeAssistant topic ID to determine the ESH channel group UID and type.
65      *
66      * @param thing A ThingUID
67      * @param haID A HomeAssistant topic ID
68      * @param configJson The configuration string
69      * @param gson A Gson instance
70      */
71     public AbstractComponent(CFactory.ComponentConfiguration componentConfiguration, Class<C> clazz) {
72         this.componentConfiguration = componentConfiguration;
73
74         this.channelConfigurationJson = componentConfiguration.getConfigJSON();
75         this.channelConfiguration = componentConfiguration.getConfig(clazz);
76         this.configHash = channelConfigurationJson.hashCode();
77
78         this.haID = componentConfiguration.getHaID();
79
80         String groupId = this.haID.getGroupId(channelConfiguration.unique_id);
81
82         this.channelGroupTypeUID = new ChannelGroupTypeUID(MqttBindingConstants.BINDING_ID, groupId);
83         this.channelGroupUID = new ChannelGroupUID(componentConfiguration.getThingUID(), groupId);
84
85         this.configSeen = false;
86
87         String availability_topic = this.channelConfiguration.availability_topic;
88         if (availability_topic != null) {
89             componentConfiguration.getTracker().addAvailabilityTopic(availability_topic,
90                     this.channelConfiguration.payload_available, this.channelConfiguration.payload_not_available);
91         }
92     }
93
94     protected CChannel.Builder buildChannel(String channelID, Value valueState, String label,
95             ChannelStateUpdateListener channelStateUpdateListener) {
96         return new CChannel.Builder(this, componentConfiguration, channelID, valueState, label,
97                 channelStateUpdateListener);
98     }
99
100     public void setConfigSeen() {
101         this.configSeen = true;
102     }
103
104     /**
105      * Subscribes to all state channels of the component and adds all channels to the provided channel type provider.
106      *
107      * @param connection The connection
108      * @param channelStateUpdateListener A listener
109      * @return A future that completes as soon as all subscriptions have been performed. Completes exceptionally on
110      *         errors.
111      */
112     public CompletableFuture<@Nullable Void> start(MqttBrokerConnection connection, ScheduledExecutorService scheduler,
113             int timeout) {
114         return channels.values().parallelStream().map(v -> v.start(connection, scheduler, timeout))
115                 .collect(FutureCollector.allOf());
116     }
117
118     /**
119      * Unsubscribes from all state channels of the component.
120      *
121      * @return A future that completes as soon as all subscriptions removals have been performed. Completes
122      *         exceptionally on errors.
123      */
124     public CompletableFuture<@Nullable Void> stop() {
125         return channels.values().parallelStream().map(CChannel::stop).collect(FutureCollector.allOf());
126     }
127
128     /**
129      * Add all channel types to the channel type provider.
130      *
131      * @param channelTypeProvider The channel type provider
132      */
133     public void addChannelTypes(MqttChannelTypeProvider channelTypeProvider) {
134         channelTypeProvider.setChannelGroupType(groupTypeUID(), type());
135         channels.values().forEach(v -> v.addChannelTypes(channelTypeProvider));
136     }
137
138     /**
139      * Removes all channels from the channel type provider.
140      * Call this if the corresponding Thing handler gets disposed.
141      *
142      * @param channelTypeProvider The channel type provider
143      */
144     public void removeChannelTypes(MqttChannelTypeProvider channelTypeProvider) {
145         channels.values().forEach(v -> v.removeChannelTypes(channelTypeProvider));
146         channelTypeProvider.removeChannelGroupType(groupTypeUID());
147     }
148
149     /**
150      * Each HomeAssistant component corresponds to an ESH Channel Group Type.
151      */
152     public ChannelGroupTypeUID groupTypeUID() {
153         return channelGroupTypeUID;
154     }
155
156     /**
157      * The unique id of this component within the ESH framework.
158      */
159     public ChannelGroupUID uid() {
160         return channelGroupUID;
161     }
162
163     /**
164      * Component (Channel Group) name.
165      */
166     public String name() {
167         return channelConfiguration.name;
168     }
169
170     /**
171      * Each component consists of multiple ESH Channels.
172      */
173     public Map<String, CChannel> channelTypes() {
174         return channels;
175     }
176
177     /**
178      * Return a components channel. A HomeAssistant MQTT component consists of multiple functions
179      * and those are mapped to one or more ESH channels. The channel IDs are constants within the
180      * derived Component, like the {@link ComponentSwitch#switchChannelID}.
181      *
182      * @param channelID The channel ID
183      * @return A components channel
184      */
185     public @Nullable CChannel channel(String channelID) {
186         return channels.get(channelID);
187     }
188
189     /**
190      * @return Returns the configuration hash value for easy comparison.
191      */
192     public int getConfigHash() {
193         return configHash;
194     }
195
196     /**
197      * Return the channel group type.
198      */
199     public ChannelGroupType type() {
200         final List<ChannelDefinition> channelDefinitions = channels.values().stream().map(CChannel::type)
201                 .collect(Collectors.toList());
202         return ChannelGroupTypeBuilder.instance(channelGroupTypeUID, name()).withChannelDefinitions(channelDefinitions)
203                 .build();
204     }
205
206     /**
207      * Resets all channel states to state UNDEF. Call this method after the connection
208      * to the MQTT broker got lost.
209      */
210     public void resetState() {
211         channels.values().forEach(CChannel::resetState);
212     }
213
214     /**
215      * Return the channel group definition for this component.
216      */
217     public ChannelGroupDefinition getGroupDefinition() {
218         return new ChannelGroupDefinition(channelGroupUID.getId(), groupTypeUID(), name(), null);
219     }
220 }