2 * Copyright (c) 2010-2024 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.*;
16 import static org.openhab.core.types.RefreshType.REFRESH;
18 import java.lang.reflect.ParameterizedType;
19 import java.util.Optional;
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;
38 * @author Matthew Bowman - Initial contribution
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
44 public abstract class UniFiBaseThingHandler<E, C> extends BaseThingHandler {
46 private final Logger logger = LoggerFactory.getLogger(UniFiBaseThingHandler.class);
48 public UniFiBaseThingHandler(final Thing thing) {
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");
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");
78 * Utility method to access the {@link UniFiController} instance associated with this thing.
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();
93 public E getEntity() {
94 final UniFiController controller = getController();
95 return controller == null ? null : getEntity(controller.getCache());
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();
106 if (command == REFRESH) {
107 updateState(entity, channelUID);
109 if (entity != null && controller != null) {
111 if (!handleCommand(controller, entity, channelUID, command)) {
112 logger.info("Ignoring unsupported command = {} for channel = {}", command, channelUID);
114 } catch (final UniFiException e) {
115 logger.info("Unexpected error handling command = {} for channel = {} : {}", command, channelUID,
120 "Could not handle command {} for channel = {} because no entity/controller data available.",
121 command, channelUID);
125 logger.info("Could not handle command {} for channel = {} because thing not online.", command, channelUID);
129 protected final void refresh() {
130 // mgb: only refresh if we're ONLINE
131 if (getThing().getStatus() == ONLINE) {
132 final @Nullable E entity = getEntity();
134 getThing().getChannels().forEach(channel -> updateState(entity, channel.getUID()));
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));
143 if (state != UnDefType.NULL) {
144 updateState(channelUID, state);
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
153 * @param config thing configuration
154 * @return true if initialization was successful
156 protected abstract boolean initialize(C config);
159 * Returns the default state if no data available. Default implementation return {@link UnDefType#UNDEF}.
161 * @param channelId channel to update
162 * @return default state
164 protected State getDefaultState(final String channelId) {
165 return UnDefType.UNDEF;
169 * Returns the cached UniFi entity object related to this thing.
171 * @param cache cache to get the cached entity from
172 * @return cached entry or null if not exists
174 protected abstract @Nullable E getEntity(UniFiControllerCache cache);
177 * Returns the state to set for the given channel. If {@link UnDefType#NULL} is returned it means the channel should
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.
184 protected abstract State getChannelState(E entity, String channelId);
187 * Send the given command to the UniFi controller.
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
196 protected abstract boolean handleCommand(UniFiController controller, E entity, ChannelUID channelUID,
197 Command command) throws UniFiException;