]> git.basschouten.com Git - openhab-addons.git/blob
5b8e41bf28b3e78c50d3f9f465ca69733b2fe6e9
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.unifi.internal.handler;
14
15 import static org.openhab.core.thing.ThingStatus.OFFLINE;
16 import static org.openhab.core.thing.ThingStatus.ONLINE;
17 import static org.openhab.core.types.RefreshType.REFRESH;
18
19 import java.lang.reflect.ParameterizedType;
20 import java.util.Optional;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.unifi.internal.api.UniFiController;
25 import org.openhab.binding.unifi.internal.api.UniFiException;
26 import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
27 import org.openhab.core.thing.Bridge;
28 import org.openhab.core.thing.ChannelUID;
29 import org.openhab.core.thing.Thing;
30 import org.openhab.core.thing.ThingStatusDetail;
31 import org.openhab.core.thing.binding.BaseThingHandler;
32 import org.openhab.core.types.Command;
33 import org.openhab.core.types.State;
34 import org.openhab.core.types.UnDefType;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 /**
39  * @author Matthew Bowman - Initial contribution
40  *
41  * @param <E> entity - the UniFi entity class used by this thing handler
42  * @param <C> config - the UniFi config class used by this thing handler
43  */
44 @NonNullByDefault
45 public abstract class UniFiBaseThingHandler<E, C> extends BaseThingHandler {
46
47     private final Logger logger = LoggerFactory.getLogger(UniFiBaseThingHandler.class);
48
49     public UniFiBaseThingHandler(final Thing thing) {
50         super(thing);
51     }
52
53     @Override
54     @SuppressWarnings("unchecked")
55     public final void initialize() {
56         final Bridge bridge = getBridge();
57         if (bridge == null || bridge.getHandler() == null
58                 || !(bridge.getHandler() instanceof UniFiControllerThingHandler)) {
59             updateStatus(OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
60                     "@text/error.thing.offline.configuration_error");
61             return;
62         }
63         // mgb: derive the config class from the generic type
64         final Class<?> clazz = (Class<?>) (((ParameterizedType) getClass().getGenericSuperclass())
65                 .getActualTypeArguments()[1]);
66         final C config = (C) getConfigAs(clazz);
67         if (initialize(config)) {
68             if (bridge.getStatus() == OFFLINE) {
69                 updateStatus(OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "@text/error.thing.offline.bridge_offline");
70                 return;
71             } else {
72                 updateStatus(ONLINE);
73             }
74         }
75     }
76
77     /**
78      * Utility method to access the {@link UniFiController} instance associated with this thing.
79      *
80      * @return
81      */
82     @SuppressWarnings("null")
83     private final @Nullable UniFiController getController() {
84         final Bridge bridge = getBridge();
85         if (bridge != null && bridge.getHandler() != null
86                 && (bridge.getHandler() instanceof UniFiControllerThingHandler)) {
87             return ((UniFiControllerThingHandler) bridge.getHandler()).getController();
88         }
89         return null;
90     }
91
92     private @Nullable E getEntity() {
93         final UniFiController controller = getController();
94         return controller == null ? null : getEntity(controller.getCache());
95     }
96
97     @Override
98     public final void handleCommand(final ChannelUID channelUID, final Command command) {
99         logger.debug("Handling command = {} for channel = {}", command, channelUID);
100         // mgb: only handle commands if we're ONLINE
101         if (getThing().getStatus() == ONLINE) {
102             final E entity = getEntity();
103             final UniFiController controller = getController();
104
105             if (command == REFRESH) {
106                 updateState(entity, channelUID);
107             } else {
108                 if (entity != null && controller != null) {
109                     try {
110                         if (!handleCommand(controller, entity, channelUID, command)) {
111                             logger.info("Ignoring unsupported command = {} for channel = {}", command, channelUID);
112                         }
113                     } catch (final UniFiException e) {
114                         logger.info("Unexpected error handling command = {} for channel = {} : {}", command, channelUID,
115                                 e.getMessage());
116                     }
117                 } else {
118                     logger.info(
119                             "Could not handle command {} for channel = {} because no entity/controller data available.",
120                             command, channelUID);
121                 }
122             }
123         } else {
124             logger.info("Could not handle command {} for channel = {} because thing not online.", command, channelUID);
125         }
126     }
127
128     protected final void refresh() {
129         // mgb: only refresh if we're ONLINE
130         if (getThing().getStatus() == ONLINE) {
131             final E entity = getEntity();
132
133             getThing().getChannels().forEach(channel -> updateState(entity, channel.getUID()));
134         }
135     }
136
137     private void updateState(final E entity, final ChannelUID channelUID) {
138         final String channelId = channelUID.getId();
139         final State state = Optional.ofNullable(entity).map(e -> getChannelState(e, channelId))
140                 .orElseGet(() -> getDefaultState(channelId));
141
142         if (state != UnDefType.NULL) {
143             updateState(channelUID, state);
144         }
145     }
146
147     /**
148      * Additional sub class specific initialization.
149      * If initialization is unsuccessful it should set the thing status and return false.
150      * if it was successful it should return true
151      *
152      * @param config thing configuration
153      * @return true if initialization was successful
154      */
155     protected abstract boolean initialize(C config);
156
157     /**
158      * Returns the default state if no data available. Default implementation return {@link UnDefType#UNDEF}.
159      *
160      * @param channelId channel to update
161      * @return default state
162      */
163     protected State getDefaultState(final String channelId) {
164         return UnDefType.UNDEF;
165     }
166
167     /**
168      * Returns the cached UniFi entity object related to this thing.
169      *
170      * @param cache cache to get the cached entity from
171      * @return cached entry or null if not exists
172      */
173     protected abstract @Nullable E getEntity(UniFiControllerCache cache);
174
175     /**
176      * Returns the state to set for the given channel. If {@link UnDefType#NULL} is returned it means the channel should
177      * not be updated.
178      *
179      * @param entity UniFi entity object to get the state information from
180      * @param channelId Channel to update
181      * @return state to set or {@link UnDefType#NULL} if channel state should not be updated.
182      */
183     protected abstract State getChannelState(E entity, String channelId);
184
185     /**
186      * Send the given command to the UniFi controller.
187      *
188      * @param controller controller object to use to send the command to the UniFi controller
189      * @param entity data object of the thing to send command to
190      * @param channelUID channel the command is from
191      * @param command command to send
192      * @return true if command was send
193      * @throws UniFiException
194      */
195     protected abstract boolean handleCommand(UniFiController controller, E entity, ChannelUID channelUID,
196             Command command) throws UniFiException;
197 }