2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.unifi.internal.handler;
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;
19 import java.lang.reflect.ParameterizedType;
20 import java.util.Optional;
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;
39 * @author Matthew Bowman - Initial contribution
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
45 public abstract class UniFiBaseThingHandler<E, C> extends BaseThingHandler {
47 private final Logger logger = LoggerFactory.getLogger(UniFiBaseThingHandler.class);
49 public UniFiBaseThingHandler(final Thing thing) {
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");
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");
78 * Utility method to access the {@link UniFiController} instance associated with this thing.
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();
92 private @Nullable E getEntity() {
93 final UniFiController controller = getController();
94 return controller == null ? null : getEntity(controller.getCache());
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();
105 if (command == REFRESH) {
106 updateState(entity, channelUID);
108 if (entity != null && controller != null) {
110 if (!handleCommand(controller, entity, channelUID, command)) {
111 logger.info("Ignoring unsupported command = {} for channel = {}", command, channelUID);
113 } catch (final UniFiException e) {
114 logger.info("Unexpected error handling command = {} for channel = {} : {}", command, channelUID,
119 "Could not handle command {} for channel = {} because no entity/controller data available.",
120 command, channelUID);
124 logger.info("Could not handle command {} for channel = {} because thing not online.", command, channelUID);
128 protected final void refresh() {
129 // mgb: only refresh if we're ONLINE
130 if (getThing().getStatus() == ONLINE) {
131 final E entity = getEntity();
133 getThing().getChannels().forEach(channel -> updateState(entity, channel.getUID()));
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));
142 if (state != UnDefType.NULL) {
143 updateState(channelUID, state);
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
152 * @param config thing configuration
153 * @return true if initialization was successful
155 protected abstract boolean initialize(C config);
158 * Returns the default state if no data available. Default implementation return {@link UnDefType#UNDEF}.
160 * @param channelId channel to update
161 * @return default state
163 protected State getDefaultState(final String channelId) {
164 return UnDefType.UNDEF;
168 * Returns the cached UniFi entity object related to this thing.
170 * @param cache cache to get the cached entity from
171 * @return cached entry or null if not exists
173 protected abstract @Nullable E getEntity(UniFiControllerCache cache);
176 * Returns the state to set for the given channel. If {@link UnDefType#NULL} is returned it means the channel should
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.
183 protected abstract State getChannelState(E entity, String channelId);
186 * Send the given command to the UniFi controller.
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
195 protected abstract boolean handleCommand(UniFiController controller, E entity, ChannelUID channelUID,
196 Command command) throws UniFiException;