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.airquality.internal.api;
15 import java.io.IOException;
16 import java.util.concurrent.TimeUnit;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.openhab.binding.airquality.internal.AirQualityException;
20 import org.openhab.binding.airquality.internal.api.dto.AirQualityData;
21 import org.openhab.binding.airquality.internal.api.dto.AirQualityResponse;
22 import org.openhab.binding.airquality.internal.api.dto.AirQualityResponse.ResponseStatus;
23 import org.openhab.core.io.net.http.HttpUtil;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
27 import com.google.gson.Gson;
28 import com.google.gson.JsonSyntaxException;
31 * The {@link ApiBridge} is the interface between handlers
32 * and the actual web service
34 * @author Gaƫl L'hopital - Initial contribution
37 public class ApiBridge {
38 private static final Gson GSON = new Gson();
39 private static final String URL = "http://api.waqi.info/feed/%query%/?token=%apiKey%";
40 private static final int REQUEST_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30);
42 private final Logger logger = LoggerFactory.getLogger(ApiBridge.class);
43 private final String apiKey;
45 public ApiBridge(String apiKey) {
50 * Build request URL from configuration data
52 * @return a valid URL for the aqicn.org service
53 * @throws AirQualityException
55 private String buildRequestURL(String key, int stationId, String location) {
56 String geoStr = stationId != 0 ? String.format("@%d", stationId)
57 : String.format("geo:%s",
58 location.replace(" ", "").replace(",", ";").replace("\"", "").replace("'", "").trim());
60 return URL.replace("%apiKey%", key).replace("%query%", geoStr);
64 * Request new air quality data to the aqicn.org service
66 * @return an air quality data object mapping the JSON response
67 * @throws AirQualityException
69 public AirQualityData getData(int stationId, String location, int retryCounter) throws AirQualityException {
70 String urlStr = buildRequestURL(apiKey, stationId, location);
71 logger.debug("URL = {}", urlStr);
74 String response = HttpUtil.executeUrl("GET", urlStr, null, null, null, REQUEST_TIMEOUT_MS);
75 logger.debug("aqiResponse = {}", response);
76 AirQualityResponse result = GSON.fromJson(response, AirQualityResponse.class);
77 if (result != null && result.getStatus() == ResponseStatus.OK) {
78 return result.getData();
79 } else if (retryCounter == 0) {
80 logger.debug("Error in aqicn.org, retrying once");
81 return getData(stationId, location, retryCounter + 1);
83 throw new AirQualityException("Error in aqicn.org response: Missing data sub-object");
84 } catch (IOException | JsonSyntaxException e) {
85 throw new AirQualityException("Communication error", e);