]> git.basschouten.com Git - openhab-addons.git/blob
85d0def5547f566856a65cc814c734c67588ce7e
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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         // The framework requires you to return from this method quickly.
160         // Setting the thing status to UNKNOWN temporarily and let the background task decide for the real status.
161         updateStatus(ThingStatus.UNKNOWN);
162         // Take care of unusual situations...
163         if (scheduler.isShutdown()) {
164             logger.warn("initialize(): scheduler is shutdown, aborting the initialization of this bridge.");
165             return;
166         }
167         logger.trace("initialize(): preparing background initialization task.");
168         // Background initialization...
169         scheduler.execute(() -> {
170             logger.trace("initialize.scheduled(): Setting ThingStatus to ONLINE.");
171             updateStatus(ThingStatus.ONLINE);
172             updateVisibleInformation();
173             logger.debug("Velux Binding Info Element '{}' is initialized.", getThing().getUID());
174         });
175         logger.trace("initialize() done.");
176     }
177
178     @Override
179     public void handleCommand(ChannelUID channelUID, Command command) {
180         logger.trace("handleCommand({},{}) called.", channelUID.getAsString(), command);
181         /*
182          * ===========================================================
183          * Common part
184          */
185         String channelId = channelUID.getId();
186         State newState = null;
187         String itemName = channelUID.getAsString();
188         VeluxItemType itemType = VeluxItemType.getByThingAndChannel(thingTypeUIDOf(channelUID), channelUID.getId());
189
190         if (command instanceof RefreshType) {
191             /*
192              * ===========================================================
193              * Refresh part
194              */
195             logger.trace("handleCommand(): refreshing item {}.", itemName);
196             switch (itemType) {
197                 case BINDING_INFORMATION:
198                     newState = StateUtils.createState(bridgeCountToString());
199                     break;
200                 default:
201                     logger.trace("handleCommand(): cannot handle REFRESH on channel {} as it is of type {}.", itemName,
202                             channelId);
203             }
204             if (newState != null) {
205                 logger.debug("handleCommand(): updating {} ({}) to {}.", itemName, channelUID, newState);
206                 updateState(channelUID, newState);
207             } else {
208                 logger.info("handleCommand({},{}): updating of item {} failed.", channelUID.getAsString(), command,
209                         itemName);
210             }
211         } else {
212             /*
213              * ===========================================================
214              * Modification part
215              */
216             switch (channelId) {
217                 default:
218                     logger.warn("handleCommand() cannot handle command {} on channel {} (type {}).", command, itemName,
219                             itemType);
220             }
221         }
222         logger.trace("handleCommand() done.");
223     }
224
225     /*
226      * **********************************
227      * ***** (Other) Public Methods *****
228      */
229
230     /**
231      * Update the information about bridges and things.
232      * <P>
233      * Provided for instrumentation of factory class to update this set of information.
234      * </P>
235      *
236      * @param veluxBridgeCount describing the number of initialized bridges.
237      * @param veluxThingCount describing the number of initialized things (in addition to Thing of type
238      *            BindingInformation).
239      */
240     public void updateBindingState(Integer veluxBridgeCount, Integer veluxThingCount) {
241         currentNumberOfBridges = veluxBridgeCount;
242         currentNumberOfThings = veluxThingCount;
243         updateVisibleInformation();
244     }
245 }