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