2 * Copyright (c) 2010-2023 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.velux.internal.bridge;
15 import java.util.Collections;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.openhab.binding.velux.internal.bridge.common.BridgeAPI;
20 import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol;
21 import org.openhab.binding.velux.internal.bridge.common.Login;
22 import org.openhab.binding.velux.internal.bridge.common.Logout;
23 import org.openhab.binding.velux.internal.handler.VeluxBridgeHandler;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * 2nd Level I/O interface towards the <B>Velux</B> bridge.
29 * It provides methods for pre- and post-communication
30 * as well as a common method for the real communication.
31 * The following class access methods exist:
33 * <LI>{@link VeluxBridge#bridgeLogin} for pre-communication,</LI>
34 * <LI>{@link VeluxBridge#bridgeLogout} for post-communication,</LI>
35 * <LI>{@link VeluxBridge#bridgeCommunicate} as method for the common communication.</LI>
38 * Each protocol-specific implementation provides a publicly visible
39 * set of supported protocols as variable {@link #supportedProtocols}.
40 * As root of several inheritance levels it predefines an
41 * interfacing method {@link VeluxBridge#bridgeAPI} which
42 * has to be implemented by any kind of protocol-specific
43 * communication returning the appropriate base (1st) level
44 * communication method as well as any other gateway
45 * interaction with {@link #bridgeDirectCommunicate}.
47 * @author Guenther Schreiner - Initial contribution.
50 public abstract class VeluxBridge {
51 private final Logger logger = LoggerFactory.getLogger(VeluxBridge.class);
54 * ***************************
55 * ***** Private Objects *****
58 private final String emptyAuthenticationToken = "";
60 // Type definitions, variables
63 * Support protocols for the concrete implementation.
65 * For protocol-specific implementations this value has to be adapted along the inheritance i.e.
66 * with the protocol-specific class values.
68 public Set<String> supportedProtocols = Collections.emptySet();
70 /** BridgeCommunicationProtocol authentication token for Velux Bridge. */
71 protected String authenticationToken = emptyAuthenticationToken;
74 * Handler to access global bridge instance methods
77 protected VeluxBridgeHandler bridgeInstance;
80 * ************************
81 * ***** Constructors *****
87 * Initializes the binding-wide instance for dealing with common informations and
88 * the Velux bridge connectivity settings by preparing the configuration settings with help
89 * by VeluxBridgeConfiguration.
91 * @param bridgeInstance refers to the binding-wide instance for dealing for common informations
92 * like existing actuators and predefined scenes.
94 public VeluxBridge(VeluxBridgeHandler bridgeInstance) {
95 logger.trace("VeluxBridge(constructor,bridgeInstance={}) called.", bridgeInstance);
96 this.bridgeInstance = bridgeInstance;
97 logger.trace("VeluxBridge(constructor) done.");
100 // Destructor methods
105 * Deinitializes the binding-wide instance.
108 public void shutdown() {
109 logger.trace("shutdown() called.");
112 // Class access methods
115 * Determines whether the binding is already authenticated against the bridge so that
116 * any other communication can occur without an additional care about authentication.
118 * This method automatically decides on availability of the stored authentication
119 * information {@link VeluxBridge#authenticationToken} whether a (re-)authentication is possible.
121 * @return true if the bridge is authenticated; false otherwise.
123 private boolean isAuthenticated() {
124 boolean success = (authenticationToken.length() > 0);
125 logger.trace("isAuthenticated() returns {}.", success);
130 * Declares the binding as unauthenticated against the bridge so that the next
131 * communication will take care about (re-)authentication.
133 protected void resetAuthentication() {
134 logger.trace("resetAuthentication() called.");
135 authenticationToken = emptyAuthenticationToken;
140 * Prepare an authorization request and communicate it with the <b>Velux</b> veluxBridge.
141 * If login is successful, the returned authorization token will be stored within this class
142 * for any further communication via {@link#bridgeCommunicate} up
143 * to an authorization with method {@link VeluxBridge#bridgeLogout}.
145 * @return true if the login was successful, and false otherwise.
147 public synchronized boolean bridgeLogin() {
148 logger.trace("bridgeLogin() called.");
150 Login bcp = bridgeAPI().login();
151 bcp.setPassword(bridgeInstance.veluxBridgeConfiguration().password);
152 if (bridgeCommunicate(bcp, false)) {
153 logger.trace("bridgeLogin(): communication succeeded.");
154 if (bcp.isCommunicationSuccessful()) {
155 logger.trace("bridgeLogin(): storing authentication token for further access.");
156 authenticationToken = bcp.getAuthToken();
164 * Prepare an authenticated deauthorization request and communicate it with the <b>Velux</b> veluxBridge.
165 * The authorization token stored in this class will be destroyed, so that the
166 * next communication has to start with {@link VeluxBridge#bridgeLogin}.
168 * @return true if the logout was successful, and false otherwise.
170 public synchronized boolean bridgeLogout() {
171 logger.trace("bridgeLogout() called: emptying authentication token.");
172 authenticationToken = "";
174 Logout bcp = bridgeAPI().logout();
175 if (bridgeCommunicate(bcp, false)) {
176 logger.trace("bridgeLogout(): communication succeeded.");
177 if (bcp.isCommunicationSuccessful()) {
178 logger.trace("bridgeLogout(): logout successful.");
186 * Initializes a client/server communication towards <b>Velux</b> veluxBridge
187 * based on the Basic I/O interface {@link VeluxBridge} and parameters
188 * passed as arguments (see below) and provided by VeluxBridgeConfiguration.
190 * @param communication the intended communication,
191 * that is request and response interactions as well as appropriate URL definition.
192 * @param useAuthentication whether to use authenticated communication.
193 * @return true if communication was successful, and false otherwise.
195 private synchronized boolean bridgeCommunicate(BridgeCommunicationProtocol communication,
196 boolean useAuthentication) {
197 logger.trace("bridgeCommunicate({},{}authenticated) called.", communication.name(),
198 useAuthentication ? "" : "un");
200 if (!isAuthenticated()) {
201 if (useAuthentication) {
202 logger.trace("bridgeCommunicate(): no auth token available, aborting.");
205 logger.trace("bridgeCommunicate(): no auth token available, continuing.");
208 return bridgeDirectCommunicate(communication, useAuthentication);
212 * Initializes a client/server communication towards <b>Velux</b> Bridge
213 * based on the Basic I/O interface {@link VeluxBridge} and parameters
214 * passed as arguments (see below) and provided by VeluxBridgeConfiguration.
215 * This method automatically decides to invoke a login communication before the
216 * intended request if there has not been an authentication before.
218 * @param communication the intended communication, that is request and response interactions as well as appropriate
220 * @return true if communication was successful, and false otherwise.
222 public synchronized boolean bridgeCommunicate(BridgeCommunicationProtocol communication) {
223 logger.trace("bridgeCommunicate({}) called.", communication.name());
224 if (!isAuthenticated()) {
227 return bridgeCommunicate(communication, true);
231 * Returns the timestamp in milliseconds since Unix epoch
232 * of last communication.
234 * If possible, it should be overwritten by protocol specific implementation.
237 * @return timestamp (default zero).
239 public long lastCommunication() {
240 logger.trace("lastCommunication() returns zero.");
245 * Returns the timestamp in milliseconds since Unix epoch
246 * of last successful communication.
248 * If possible, it should be overwritten by protocol specific implementation.
251 * @return timestamp (default zero).
253 public long lastSuccessfulCommunication() {
254 logger.trace("lastSuccessfulCommunication() returns zero.");
259 * Provides information about the base-level communication method and
260 * any kind of available gateway interaction.
262 * For protocol-specific implementations this method has to be overwritten along the inheritance i.e.
263 * with the protocol-specific class implementations.
265 * @return bridgeAPI of type {@link org.openhab.binding.velux.internal.bridge.common.BridgeAPI BridgeAPI}.
267 public abstract BridgeAPI bridgeAPI();
270 * Initializes a client/server communication towards <b>Velux</b> veluxBridge
271 * based on the protocol-specific implementations with common parameters
272 * passed as arguments (see below) and provided by VeluxBridgeConfiguration.
274 * For protocol-specific implementations this method has to be overwritten along the inheritance i.e.
275 * with the protocol-specific class implementations.
277 * @param communication Structure of interface type {@link BridgeCommunicationProtocol} describing the
278 * intended communication.
279 * @param useAuthentication boolean flag to decide whether to use authenticated communication.
280 * @return <b>success</b> of type boolean which signals the success of the communication.
282 protected abstract boolean bridgeDirectCommunicate(BridgeCommunicationProtocol communication,
283 boolean useAuthentication);
286 * Check is the last communication was a good one
288 * @return true if the last communication was a good one
290 public boolean lastCommunicationOk() {
291 return lastCommunication() != 0 && lastSuccessfulCommunication() == lastCommunication();