]> git.basschouten.com Git - openhab-addons.git/blob
2f49b5c56b0c7dbdf6bda0fc815d403a52bc7f23
[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.velux.internal.handler;
14
15 import org.eclipse.jdt.annotation.NonNullByDefault;
16 import org.openhab.binding.velux.internal.VeluxBindingConstants;
17 import org.openhab.binding.velux.internal.VeluxBindingProperties;
18 import org.openhab.binding.velux.internal.VeluxItemType;
19 import org.openhab.binding.velux.internal.handler.utils.ExtendedBaseThingHandler;
20 import org.openhab.binding.velux.internal.handler.utils.StateUtils;
21 import org.openhab.binding.velux.internal.handler.utils.ThingProperty;
22 import org.openhab.binding.velux.internal.utils.Localization;
23 import org.openhab.binding.velux.internal.utils.ManifestInformation;
24 import org.openhab.core.common.AbstractUID;
25 import org.openhab.core.thing.Channel;
26 import org.openhab.core.thing.ChannelUID;
27 import org.openhab.core.thing.Thing;
28 import org.openhab.core.thing.ThingStatus;
29 import org.openhab.core.thing.ThingStatusDetail;
30 import org.openhab.core.thing.ThingTypeUID;
31 import org.openhab.core.types.Command;
32 import org.openhab.core.types.RefreshType;
33 import org.openhab.core.types.State;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /***
38  * The class is responsible for representing the overall status of the Velux binding.
39  * <P>
40  * Beside the normal thing handling introduced by {@link ExtendedBaseThingHandler}, it provides a method:
41  * <ul>
42  * <li>{@link #updateBindingState} to enable other classes to modify the number of activated Velux bridges and
43  * Things.</LI>
44  * </UL>
45  *
46  * @author Guenther Schreiner - Initial contribution
47  */
48 @NonNullByDefault
49 public class VeluxBindingHandler extends ExtendedBaseThingHandler {
50     private final Logger logger = LoggerFactory.getLogger(VeluxBindingHandler.class);
51
52     /*
53      * ***************************
54      * ***** Private Objects *****
55      */
56     private Thing thing;
57     private Localization localization;
58     private Integer currentNumberOfBridges = 0;
59     private Integer currentNumberOfThings = 0;
60
61     /*
62      * ************************
63      * ***** Constructors *****
64      */
65
66     public VeluxBindingHandler(Thing thing, final Localization localization) {
67         super(thing);
68         this.thing = thing;
69         this.localization = localization;
70         logger.trace("VeluxBindingHandler(constructor) called.");
71     }
72
73     /*
74      * ***************************
75      * ***** Private Methods *****
76      */
77
78     /**
79      * Provide the ThingType for a given Channel.
80      * <P>
81      * Separated into this private method to deal with the deprecated method.
82      * </P>
83      *
84      * @param channelUID for type {@link ChannelUID}.
85      * @return thingTypeUID of type {@link ThingTypeUID}.
86      */
87     private ThingTypeUID thingTypeUIDOf(ChannelUID channelUID) {
88         String[] segments = channelUID.getAsString().split(AbstractUID.SEPARATOR);
89         if (segments.length > 1) {
90             return new ThingTypeUID(segments[0], segments[1]);
91         }
92         logger.warn("thingTypeUIDOf({}) failed.", channelUID);
93         return new ThingTypeUID(VeluxBindingConstants.BINDING_ID, VeluxBindingConstants.UNKNOWN_THING_TYPE_ID);
94     }
95
96     /**
97      * Returns a human-readable representation of the binding state. This should help especially unexperienced user to
98      * blossom up the introduction of the Velux binding.
99      *
100      * @return bindingInformation of type {@link String}.
101      */
102     private String bridgeCountToString() {
103         String information;
104         switch (currentNumberOfBridges) {
105             case 0:
106                 information = localization.getText("runtime.no-bridge");
107                 break;
108             case 1:
109                 information = localization.getText("runtime.one-bridge");
110                 break;
111             default:
112                 information = localization.getText("runtime.multiple-bridges");
113                 break;
114         }
115         return information;
116     }
117
118     /**
119      * Modifies all informations within openHAB to inform the user about the current state of this binding. That is:
120      * <UL>
121      * <LI>Update the properties about bundle version, number of bridges and things,</LI>
122      * <LI>Usability of the binding in respect to defined bridges within the ThingStatus, and</LI>
123      * <LI>Information of the binding state as channel value.</LI>
124      * </UL>
125      */
126     private void updateVisibleInformation() {
127         logger.trace("updateVisibleInformation(): updating properties.");
128         ThingProperty.setValue(thing, VeluxBindingProperties.PROPERTY_BINDING_BUNDLEVERSION,
129                 ManifestInformation.getBundleVersion());
130         ThingProperty.setValue(thing, VeluxBindingProperties.PROPERTY_BINDING_NOOFBRIDGES,
131                 currentNumberOfBridges.toString());
132         ThingProperty.setValue(thing, VeluxBindingProperties.PROPERTY_BINDING_NOOFTHINGS,
133                 currentNumberOfThings.toString());
134
135         // BaseThingHandler is sensitive during initialization phase. Therefore, to avoid (wrong) warnings about:
136         // "tried updating the thing status although the handler was already disposed."
137         if (this.isInitialized()) {
138             logger.trace("updateVisibleInformation(): updating thing status.");
139             if (currentNumberOfBridges < 1) {
140                 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING, bridgeCountToString());
141             } else {
142                 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, bridgeCountToString());
143             }
144             logger.trace("updateVisibleInformation(): updating all channels.");
145             for (Channel channel : thing.getChannels()) {
146                 handleCommand(channel.getUID(), RefreshType.REFRESH);
147             }
148         }
149     }
150
151     /*
152      * *******************************************************************
153      * ***** Objects and Methods for abstract class BaseThingHandler *****
154      */
155
156     @Override
157     public void initialize() {
158         logger.debug("initialize() called.");
159         logger.info("Initializing VeluxBindingHandler for '{}'.", getThing().getUID());
160         // The framework requires you to return from this method quickly.
161         // Setting the thing status to UNKNOWN temporarily and let the background task decide for the real status.
162         updateStatus(ThingStatus.UNKNOWN);
163         // Take care of unusual situations...
164         if (scheduler.isShutdown()) {
165             logger.warn("initialize(): scheduler is shutdown, aborting the initialization of this bridge.");
166             return;
167         }
168         logger.trace("initialize(): preparing background initialization task.");
169         // Background initialization...
170         scheduler.execute(() -> {
171             logger.trace("initialize.scheduled(): Setting ThingStatus to ONLINE.");
172             updateStatus(ThingStatus.ONLINE);
173             updateVisibleInformation();
174             logger.trace("initialize.scheduled(): done.");
175         });
176         logger.trace("initialize() done.");
177     }
178
179     @Override
180     public void handleCommand(ChannelUID channelUID, Command command) {
181         logger.trace("handleCommand({},{}) called.", channelUID.getAsString(), command);
182         /*
183          * ===========================================================
184          * Common part
185          */
186         String channelId = channelUID.getId();
187         State newState = null;
188         String itemName = channelUID.getAsString();
189         VeluxItemType itemType = VeluxItemType.getByThingAndChannel(thingTypeUIDOf(channelUID), channelUID.getId());
190
191         if (command instanceof RefreshType) {
192             /*
193              * ===========================================================
194              * Refresh part
195              */
196             logger.trace("handleCommand(): refreshing item {}.", itemName);
197             switch (itemType) {
198                 case BINDING_INFORMATION:
199                     newState = StateUtils.createState(bridgeCountToString());
200                     break;
201                 default:
202                     logger.trace("handleCommand(): cannot handle REFRESH on channel {} as it is of type {}.", itemName,
203                             channelId);
204             }
205             if (newState != null) {
206                 logger.debug("handleCommand(): updating {} ({}) to {}.", itemName, channelUID, newState);
207                 updateState(channelUID, newState);
208             } else {
209                 logger.info("handleCommand({},{}): updating of item {} failed.", channelUID.getAsString(), command,
210                         itemName);
211             }
212         } else {
213             /*
214              * ===========================================================
215              * Modification part
216              */
217             switch (channelId) {
218                 default:
219                     logger.warn("handleCommand() cannot handle command {} on channel {} (type {}).", command, itemName,
220                             itemType);
221             }
222         }
223         logger.trace("handleCommand() done.");
224     }
225
226     /*
227      * **********************************
228      * ***** (Other) Public Methods *****
229      */
230
231     /**
232      * Update the information about bridges and things.
233      * <P>
234      * Provided for instrumentation of factory class to update this set of information.
235      * </P>
236      *
237      * @param veluxBridgeCount describing the number of initialized bridges.
238      * @param veluxThingCount describing the number of initialized things (in addition to Thing of type
239      *            BindingInformation).
240      */
241     public void updateBindingState(Integer veluxBridgeCount, Integer veluxThingCount) {
242         currentNumberOfBridges = veluxBridgeCount;
243         currentNumberOfThings = veluxThingCount;
244         updateVisibleInformation();
245     }
246 }