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.pixometer.handler;
15 import static org.openhab.binding.pixometer.internal.PixometerBindingConstants.*;
17 import java.io.ByteArrayInputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.nio.charset.StandardCharsets;
21 import java.util.Properties;
22 import java.util.concurrent.TimeUnit;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.openhab.binding.pixometer.internal.config.PixometerAccountConfiguration;
26 import org.openhab.core.io.net.http.HttpUtil;
27 import org.openhab.core.thing.Bridge;
28 import org.openhab.core.thing.ChannelUID;
29 import org.openhab.core.thing.ThingStatus;
30 import org.openhab.core.thing.ThingStatusDetail;
31 import org.openhab.core.thing.binding.BaseBridgeHandler;
32 import org.openhab.core.types.Command;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 import com.google.gson.JsonObject;
37 import com.google.gson.JsonParser;
40 * The {@link AccountHandler} is responsible for handling the api connection and authorization (including token
43 * @author Jerome Luckenbach - Initial contribution
46 public class AccountHandler extends BaseBridgeHandler {
48 private final Logger logger = LoggerFactory.getLogger(this.getClass());
49 private static final int TOKEN_MIN_DIFF_MS = (int) TimeUnit.DAYS.toMillis(2);
51 private @NonNullByDefault({}) String authToken;
52 private int refreshInterval;
53 private long tokenExpiryDate;
55 public AccountHandler(Bridge bridge) {
60 public void handleCommand(ChannelUID channelUID, Command command) {
61 // Nothing to handle here currently
65 public void initialize() {
66 logger.debug("Initialize Pixometer Accountservice");
68 PixometerAccountConfiguration config = getConfigAs(PixometerAccountConfiguration.class);
69 setRefreshInterval(config.refresh);
70 String user = config.user;
71 String password = config.password;
72 String scope = "read"; // Prepared for config value
74 // Check expiry date every Day and obtain new access token if difference is less then or equal to 2 days
75 scheduler.scheduleWithFixedDelay(() -> {
76 logger.debug("Checking if new access token is needed...");
78 long difference = getTokenExpiryDate() - System.nanoTime();
79 if (difference <= TOKEN_MIN_DIFF_MS) {
80 obtainAuthTokenAndExpiryDate(user, password, scope);
82 } catch (RuntimeException r) {
83 logger.debug("Could not check token expiry date for Thing {}: {}", getThing().getUID(), r.getMessage(),
86 }, 1, TimeUnit.DAYS.toMinutes(1), TimeUnit.MINUTES);
88 logger.debug("Refresh job scheduled to run every days. for '{}'", getThing().getUID());
92 public void updateStatus(ThingStatus status) {
93 super.updateStatus(status);
97 * Request auth token with read or write access.
98 * (Write access is prepared for a possible later usage for updating meters.)
100 * @param user The username to use
101 * @param password The corresponding password
102 * @param scope The granted scope on the api for the binding
104 private void obtainAuthTokenAndExpiryDate(String user, String password, String scope) {
106 String url = API_BASE_URL + "v1/access-token/";
107 Properties urlHeader = (Properties) new Properties().put("CONTENT-TYPE", "application/json");
109 JsonObject httpBody = new JsonObject();
110 httpBody.addProperty("username", user);
111 httpBody.addProperty("password", password);
112 httpBody.addProperty("scope", scope);
114 InputStream content = new ByteArrayInputStream(httpBody.toString().getBytes(StandardCharsets.UTF_8));
115 String urlResponse = HttpUtil.executeUrl("POST", url, urlHeader, content, "application/json", 2000);
116 JsonObject responseJson = (JsonObject) JsonParser.parseString(urlResponse);
118 if (responseJson.has(AUTH_TOKEN)) {
119 // Store the expire date for automatic token refresh
120 int expiresIn = Integer.parseInt(responseJson.get("expires_in").toString());
121 setTokenExpiryDate(TimeUnit.SECONDS.toNanos(expiresIn));
123 setAuthToken(responseJson.get(AUTH_TOKEN).toString().replace("\"", ""));
125 updateStatus(ThingStatus.ONLINE);
129 String errorMsg = String.format("Invalid Api Response ( %s )", responseJson);
131 throw new IOException(errorMsg);
132 } catch (IOException e) {
133 String errorMsg = String.format(
134 "Could not obtain auth token. Please check your configured account credentials. %s %s",
135 this.getThing().getUID(), e.getMessage());
137 logger.debug(errorMsg, e);
138 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorMsg);
143 * Getters and Setters
146 public String getAuthToken() {
150 private void setAuthToken(String authToken) {
151 this.authToken = authToken;
154 public int getRefreshInterval() {
155 return refreshInterval;
158 private void setRefreshInterval(int refreshInterval) {
159 this.refreshInterval = refreshInterval;
162 public long getTokenExpiryDate() {
163 return tokenExpiryDate;
166 private void setTokenExpiryDate(long expiresIn) {
167 this.tokenExpiryDate = System.nanoTime() + expiresIn;