]> git.basschouten.com Git - openhab-addons.git/blob
d4d8a6ba4c6e17865cf8e5b09bdd7b25090d3faf
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.airgradient.internal.communication;
14
15 import static org.openhab.binding.airgradient.internal.AirGradientBindingConstants.CONTENTTYPE_JSON;
16 import static org.openhab.binding.airgradient.internal.AirGradientBindingConstants.CONTENTTYPE_OPENMETRICS;
17 import static org.openhab.binding.airgradient.internal.AirGradientBindingConstants.CONTENTTYPE_TEXT;
18 import static org.openhab.binding.airgradient.internal.AirGradientBindingConstants.REQUEST_TIMEOUT;
19
20 import java.nio.charset.StandardCharsets;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.TimeUnit;
25 import java.util.concurrent.TimeoutException;
26
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.eclipse.jetty.client.HttpClient;
30 import org.eclipse.jetty.client.api.ContentResponse;
31 import org.eclipse.jetty.client.api.Request;
32 import org.eclipse.jetty.client.util.StringContentProvider;
33 import org.eclipse.jetty.http.HttpHeader;
34 import org.eclipse.jetty.http.HttpMethod;
35 import org.eclipse.jetty.http.HttpStatus;
36 import org.openhab.binding.airgradient.internal.config.AirGradientAPIConfiguration;
37 import org.openhab.binding.airgradient.internal.model.LedMode;
38 import org.openhab.binding.airgradient.internal.model.Measure;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import com.google.gson.Gson;
43
44 /**
45  * Helper for doing rest calls to the AirGradient API.
46  *
47  * @author Jørgen Austvik - Initial contribution
48  */
49 @NonNullByDefault
50 public class RemoteAPIController {
51
52     private final Logger logger = LoggerFactory.getLogger(RemoteAPIController.class);
53
54     private final HttpClient httpClient;
55     private final Gson gson;
56     private final AirGradientAPIConfiguration apiConfig;
57
58     public RemoteAPIController(HttpClient httpClient, Gson gson, AirGradientAPIConfiguration apiConfig) {
59         this.httpClient = httpClient;
60         this.gson = gson;
61         this.apiConfig = apiConfig;
62     }
63
64     /**
65      * Return list of measures from AirGradient API.
66      *
67      * @return list of measures
68      * @throws AirGradientCommunicationException if unable to communicate with sensor or API.
69      */
70     public List<Measure> getMeasures() throws AirGradientCommunicationException {
71         ContentResponse response = sendRequest(
72                 RESTHelper.generateRequest(httpClient, RESTHelper.generateMeasuresUrl(apiConfig)));
73         if (response != null) {
74             String contentType = response.getMediaType();
75             logger.debug("Got measurements with status {}: {} ({})", response.getStatus(),
76                     response.getContentAsString(), contentType);
77
78             if (HttpStatus.isSuccess(response.getStatus())) {
79                 String stringResponse = response.getContentAsString().trim();
80
81                 if (null != contentType) {
82                     switch (contentType) {
83                         case CONTENTTYPE_JSON:
84                             return JsonParserHelper.parseJson(gson, stringResponse);
85                         case CONTENTTYPE_TEXT:
86                             return PrometheusParserHelper.parsePrometheus(stringResponse);
87                         case CONTENTTYPE_OPENMETRICS:
88                             return PrometheusParserHelper.parsePrometheus(stringResponse);
89                         default:
90                             logger.debug("Unhandled content type returned: {}", contentType);
91                     }
92                 }
93             }
94         }
95
96         return Collections.emptyList();
97     }
98
99     public void setLedMode(String serialNo, String mode) throws AirGradientCommunicationException {
100         Request request = httpClient.newRequest(RESTHelper.generateGetLedsModeUrl(apiConfig, serialNo));
101         request.timeout(REQUEST_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
102         request.method(HttpMethod.PUT);
103         request.header(HttpHeader.CONTENT_TYPE, CONTENTTYPE_JSON);
104         LedMode ledMode = new LedMode();
105         ledMode.mode = mode;
106         String modeJson = gson.toJson(ledMode);
107         logger.debug("Setting LEDS mode for {}: {}", serialNo, modeJson);
108         request.content(new StringContentProvider(CONTENTTYPE_JSON, modeJson, StandardCharsets.UTF_8));
109         sendRequest(request);
110     }
111
112     public void calibrateCo2(String serialNo) throws AirGradientCommunicationException {
113         logger.debug("Triggering CO2 calibration for {}", serialNo);
114         sendRequest(RESTHelper.generateRequest(httpClient, RESTHelper.generateCalibrationCo2Url(apiConfig, serialNo),
115                 HttpMethod.POST));
116     }
117
118     private @Nullable ContentResponse sendRequest(@Nullable final Request request)
119             throws AirGradientCommunicationException {
120         if (request == null) {
121             throw new AirGradientCommunicationException("Unable to generate request");
122         }
123
124         @Nullable
125         ContentResponse response = null;
126         try {
127             response = request.send();
128             if (response != null) {
129                 logger.debug("Response from {}: {}", request.getURI(), response.getStatus());
130                 if (!HttpStatus.isSuccess(response.getStatus())) {
131                     throw new AirGradientCommunicationException("Returned status code: " + response.getStatus());
132                 }
133             } else {
134                 throw new AirGradientCommunicationException("No response");
135             }
136         } catch (InterruptedException | ExecutionException | TimeoutException e) {
137             String message = e.getMessage();
138             if (message == null) {
139                 message = "Communication error";
140             }
141             throw new AirGradientCommunicationException(message, e);
142         }
143
144         return response;
145     }
146 }