]> git.basschouten.com Git - openhab-addons.git/blob
f39e85b9c395ba718a5252d5c7d23bf46a5a4da5
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.openuv.internal.handler;
14
15 import java.io.IOException;
16 import java.time.Duration;
17 import java.time.LocalDate;
18 import java.time.LocalDateTime;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.Properties;
22 import java.util.concurrent.ScheduledFuture;
23 import java.util.concurrent.TimeUnit;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.openhab.binding.openuv.internal.OpenUVException;
28 import org.openhab.binding.openuv.internal.config.BridgeConfiguration;
29 import org.openhab.binding.openuv.internal.discovery.OpenUVDiscoveryService;
30 import org.openhab.binding.openuv.internal.json.OpenUVResponse;
31 import org.openhab.binding.openuv.internal.json.OpenUVResult;
32 import org.openhab.core.i18n.LocationProvider;
33 import org.openhab.core.io.net.http.HttpUtil;
34 import org.openhab.core.library.types.PointType;
35 import org.openhab.core.thing.Bridge;
36 import org.openhab.core.thing.ChannelUID;
37 import org.openhab.core.thing.ThingStatus;
38 import org.openhab.core.thing.ThingStatusDetail;
39 import org.openhab.core.thing.binding.BaseBridgeHandler;
40 import org.openhab.core.thing.binding.ThingHandlerService;
41 import org.openhab.core.types.Command;
42 import org.openhab.core.types.RefreshType;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 import com.google.gson.Gson;
47
48 /**
49  * {@link OpenUVBridgeHandler} is the handler for OpenUV API and connects it
50  * to the webservice.
51  *
52  * @author GaĆ«l L'hopital - Initial contribution
53  *
54  */
55 @NonNullByDefault
56 public class OpenUVBridgeHandler extends BaseBridgeHandler {
57     private static final String QUERY_URL = "https://api.openuv.io/api/v1/uv?lat=%s&lng=%s&alt=%s";
58     private static final int REQUEST_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30);
59
60     private final Logger logger = LoggerFactory.getLogger(OpenUVBridgeHandler.class);
61     private final Properties header = new Properties();
62     private final Gson gson;
63     private final LocationProvider locationProvider;
64
65     private @Nullable ScheduledFuture<?> reconnectJob;
66
67     public OpenUVBridgeHandler(Bridge bridge, LocationProvider locationProvider, Gson gson) {
68         super(bridge);
69         this.gson = gson;
70         this.locationProvider = locationProvider;
71     }
72
73     @Override
74     public void initialize() {
75         logger.debug("Initializing OpenUV API bridge handler.");
76         BridgeConfiguration config = getConfigAs(BridgeConfiguration.class);
77         if (config.apikey.isEmpty()) {
78             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
79                     "@text/offline.config-error-unknown-apikey");
80             return;
81         }
82         header.put("x-access-token", config.apikey);
83         initiateConnexion();
84     }
85
86     @Override
87     public void dispose() {
88         ScheduledFuture<?> job = this.reconnectJob;
89         if (job != null && !job.isCancelled()) {
90             job.cancel(true);
91         }
92         reconnectJob = null;
93     }
94
95     @Override
96     public void handleCommand(ChannelUID channelUID, Command command) {
97         if (command instanceof RefreshType) {
98             initiateConnexion();
99             return;
100         }
101         logger.debug("The OpenUV bridge only handles Refresh command and not '{}'", command);
102     }
103
104     private void initiateConnexion() {
105         // Just checking if the provided api key is a valid one by making a fake call
106         getUVData("0", "0", "0");
107     }
108
109     public @Nullable OpenUVResult getUVData(String latitude, String longitude, String altitude) {
110         try {
111             String jsonData = HttpUtil.executeUrl("GET", String.format(QUERY_URL, latitude, longitude, altitude),
112                     header, null, null, REQUEST_TIMEOUT_MS);
113             OpenUVResponse uvResponse = gson.fromJson(jsonData, OpenUVResponse.class);
114             if (uvResponse != null) {
115                 String error = uvResponse.getError();
116                 if (error == null) {
117                     updateStatus(ThingStatus.ONLINE);
118                     return uvResponse.getResult();
119                 }
120                 throw new OpenUVException(error);
121             }
122         } catch (IOException e) {
123             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
124         } catch (OpenUVException e) {
125             if (e.isQuotaError()) {
126                 LocalDate today = LocalDate.now();
127                 LocalDate tomorrow = today.plusDays(1);
128                 LocalDateTime tomorrowMidnight = tomorrow.atStartOfDay().plusMinutes(2);
129
130                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, String
131                         .format("@text/offline.comm-error-quota-exceeded [ \"%s\" ]", tomorrowMidnight.toString()));
132
133                 reconnectJob = scheduler.schedule(this::initiateConnexion,
134                         Duration.between(LocalDateTime.now(), tomorrowMidnight).toMinutes(), TimeUnit.MINUTES);
135             } else {
136                 updateStatus(ThingStatus.OFFLINE,
137                         e.isApiKeyError() ? ThingStatusDetail.CONFIGURATION_ERROR : ThingStatusDetail.NONE,
138                         e.getMessage());
139             }
140         }
141         return null;
142     }
143
144     @Override
145     public Collection<Class<? extends ThingHandlerService>> getServices() {
146         return Collections.singleton(OpenUVDiscoveryService.class);
147     }
148
149     public @Nullable PointType getLocation() {
150         return locationProvider.getLocation();
151     }
152 }