2 * Copyright (c) 2010-2021 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.hccrubbishcollection.internal;
15 import java.io.UnsupportedEncodingException;
16 import java.net.URLEncoder;
17 import java.nio.charset.StandardCharsets;
18 import java.time.LocalDateTime;
19 import java.time.ZoneId;
20 import java.time.ZonedDateTime;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.TimeoutException;
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.eclipse.jetty.client.HttpClient;
28 import org.eclipse.jetty.client.api.ContentResponse;
29 import org.openhab.core.thing.ThingStatusDetail;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
33 import com.google.gson.JsonElement;
34 import com.google.gson.JsonObject;
35 import com.google.gson.JsonParser;
38 * The {@link API} contains all code relating to accessing the online rubbish collection API.
40 * @author Stewart Cossey - Initial contribution
44 private static final int REQUEST_TIMEOUT = 10;
45 private static final String REQUEST_URL = "https://hccfightthelandfill.azure-api.net/get_Collection_Dates?address_string=";
46 private static final int HTTP_OK = 200;
48 private final Logger logger = LoggerFactory.getLogger(API.class);
50 private final HttpClient httpClient;
51 private final String address;
53 private String errorDetailMessage = "";
54 private ThingStatusDetail errorDetail = ThingStatusDetail.NONE;
56 private @Nullable Integer collectionWeek = null;
57 private @Nullable Integer day = null;
58 private @Nullable ZonedDateTime recycling = null;
59 private @Nullable ZonedDateTime general = null;
62 * Create a new API class.
64 * @param httpClient The common http client provided from openHAB.
65 * @param address The address of the premises.
67 public API(HttpClient httpClient, String address) {
68 this.httpClient = httpClient;
69 this.address = address;
73 * Connects to the web service and gets the data.
75 * @return boolean Success.
77 public boolean update() {
79 final String url = REQUEST_URL + URLEncoder.encode(address, StandardCharsets.UTF_8.toString());
81 logger.debug("Fetching data from URL {} (address hidden)", REQUEST_URL);
83 ContentResponse response = httpClient.newRequest(url).timeout(REQUEST_TIMEOUT, TimeUnit.SECONDS).send();
85 if (response.getStatus() == HTTP_OK) {
86 String content = response.getContentAsString();
87 // Return response is encapsulated in square brackets, remove to create valid json.
88 String cleanedContent = content.trim().substring(1, content.length() - 1);
89 logger.trace("Got cleaned content: {}", cleanedContent);
91 JsonObject jsonResponse = JsonParser.parseString(cleanedContent).getAsJsonObject();
93 JsonElement dayElement = jsonResponse.get("CollectionDay");
94 JsonElement collectionWeekElement = jsonResponse.get("CollectionWeek");
95 JsonElement generalElement = jsonResponse.get("RedBin");
96 JsonElement recyclingElement = jsonResponse.get("YellowBin");
98 // The elements are missing if the address is invalid or council does not service (due to address being
100 if (generalElement == null || recyclingElement == null) {
101 logger.debug("RedBin or YellowBin object is missing. Invalid premises or address");
103 errorDetail = ThingStatusDetail.CONFIGURATION_ERROR;
104 errorDetailMessage = "Invalid address";
108 // Get API dates as LocalDateTime objects.
109 LocalDateTime localGeneralDate = LocalDateTime.parse(generalElement.getAsString());
110 LocalDateTime localRecyclingDate = LocalDateTime.parse(recyclingElement.getAsString());
112 ZoneId zone = ZonedDateTime.now().getZone(); // Gets the local time zone.
114 // Convert LocalDateTime objects to be compatible with openHAB
115 ZonedDateTime zonedGeneralDate = ZonedDateTime.of(localGeneralDate, zone);
116 ZonedDateTime zonedRecyclingDate = ZonedDateTime.of(localRecyclingDate, zone);
118 errorDetail = ThingStatusDetail.NONE; // Sets to no error since we have successfully parsed response.
120 // Set the local properties with values from API.
121 recycling = zonedRecyclingDate;
122 general = zonedGeneralDate;
124 day = dayElement.getAsInt();
125 collectionWeek = collectionWeekElement.getAsInt();
129 logger.error("Data fetch failed, got HTTP Code {}", response.getStatus());
130 errorDetail = ThingStatusDetail.COMMUNICATION_ERROR;
131 errorDetailMessage = "HTTP Code " + response.getStatus();
134 } catch (UnsupportedEncodingException ue) {
135 errorDetail = ThingStatusDetail.COMMUNICATION_ERROR;
136 errorDetailMessage = "Encoding not supported!";
138 } catch (TimeoutException to) {
139 errorDetail = ThingStatusDetail.COMMUNICATION_ERROR;
140 errorDetailMessage = "Response Timeout (will try again soon)";
142 } catch (InterruptedException | ExecutionException e) {
148 * Returns the last request status.
150 * @return ThingStatusDetail The openHAB error type.
152 public ThingStatusDetail getErrorDetail() {
157 * Gets the error, if occurred.
159 * @return String The error message.
161 public String getErrorDetailMessage() {
162 return errorDetailMessage;
166 * The collection week.
168 * @return Integer The week number.
170 public @Nullable Integer getCollectionWeek() {
171 return collectionWeek;
175 * Gets the collection day of week.
177 * @return Integer The day of the week. 1 = Monday.
179 public @Nullable Integer getDay() {
184 * The upcoming recycling collection date.
186 * @return ZonedDateTime
188 public @Nullable ZonedDateTime getRecyclingDate() {
193 * The upcoming general rubbish collection date.
195 * @return ZonedDateTime
197 public @Nullable ZonedDateTime getGeneralDate() {