diff --git a/CODEOWNERS b/CODEOWNERS index d7365952a47..9f5136c9d11 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -101,6 +101,7 @@ /bundles/org.openhab.binding.haassohnpelletstove/ @chingon007 /bundles/org.openhab.binding.harmonyhub/ @digitaldan /bundles/org.openhab.binding.haywardomnilogic/ @matchews +/bundles/org.openhab.binding.hccrubbishcollection/ @cossey /bundles/org.openhab.binding.hdanywhere/ @kgoderis /bundles/org.openhab.binding.hdpowerview/ @beowulfe /bundles/org.openhab.binding.helios/ @kgoderis diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index a26ae4965a1..c6d486fce12 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -491,6 +491,11 @@ org.openhab.binding.haywardomnilogic ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.hccrubbishcollection + ${project.version} + org.openhab.addons.bundles org.openhab.binding.hdanywhere diff --git a/bundles/org.openhab.binding.hccrubbishcollection/NOTICE b/bundles/org.openhab.binding.hccrubbishcollection/NOTICE new file mode 100644 index 00000000000..38d625e3492 --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/NOTICE @@ -0,0 +1,13 @@ +This content is produced and maintained by the openHAB project. + +* Project home: https://www.openhab.org + +== Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License 2.0 which is available at +https://www.eclipse.org/legal/epl-2.0/. + +== Source Code + +https://github.com/openhab/openhab-addons diff --git a/bundles/org.openhab.binding.hccrubbishcollection/README.md b/bundles/org.openhab.binding.hccrubbishcollection/README.md new file mode 100644 index 00000000000..8a6b4c232f1 --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/README.md @@ -0,0 +1,46 @@ +# HCC Rubbish Collection Binding + +A Hamilton City Council (NZ) _"Fight the Landfill"_ binding. +This binding will keep track of your rubbish collection days and uses the [Fight the Landfill](https://www.fightthelandfill.co.nz/) website API to fetch the upcoming collection dates. + +## Supported Things + +A single supported thing called `collection`. + +## Thing Configuration + +The thing supports one setting labelled `address` which is your street number and name as it appears on Google. +*For Example: +1 Victoria Street* + +> Note: The above address example is not valid as it is a business address. + +*__If the address is not valid or rubbish collection service does not apply (for example, a business address) then a `CONFIGURATION_ERROR` will occur.__* + +## Channels + +| channel | type | description | +| ---------------- | ------ | -------------------------------------------------------------------- | +| day | Number | The upcoming rubbish collection day of the week (1=Monday, 7=Sunday) | +| general | Date | The next general household (red bin) collection day | +| recycling | Date | The next recycling (yellow bin, glass bin) colleciton day | +| collection-event | Event | Event trigger on the day of the rubbish | + +### Collection Event + +The collection event `collection-event` triggers on the day of rubbish collection. + +#### Events + +| event | description | +| --------- | ------------------------------- | +| GENERAL | General household rubbish event | +| RECYCLING | Recycling rubbish event | + +#### Configuration + +You can set an `offset` in minutes. +This can then trigger the collection event before or after the normal time of 12:00am on the day of the collection. + +*For Example: +If you want the event to trigger at 7pm the day before, to remind you to take out the bins, then set the `offset` to `-300` (5 hours x 60 minutes).* diff --git a/bundles/org.openhab.binding.hccrubbishcollection/pom.xml b/bundles/org.openhab.binding.hccrubbishcollection/pom.xml new file mode 100644 index 00000000000..8414b72aa77 --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/pom.xml @@ -0,0 +1,17 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.1.0-SNAPSHOT + + + org.openhab.binding.hccrubbishcollection + + openHAB Add-ons :: Bundles :: HCC Rubbish Collection Binding + + diff --git a/bundles/org.openhab.binding.hccrubbishcollection/src/main/feature/feature.xml b/bundles/org.openhab.binding.hccrubbishcollection/src/main/feature/feature.xml new file mode 100644 index 00000000000..b21a42aac3b --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.hccrubbishcollection/${project.version} + + diff --git a/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/API.java b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/API.java new file mode 100644 index 00000000000..c7ca5d86ad2 --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/API.java @@ -0,0 +1,200 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hccrubbishcollection.internal; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.openhab.core.thing.ThingStatusDetail; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +/** + * The {@link API} contains all code relating to accessing the online rubbish collection API. + * + * @author Stewart Cossey - Initial contribution + */ +@NonNullByDefault +public class API { + private static final int REQUEST_TIMEOUT = 10; + private static final String REQUEST_URL = "https://hccfightthelandfill.azure-api.net/get_Collection_Dates?address_string="; + private static final int HTTP_OK = 200; + + private final Logger logger = LoggerFactory.getLogger(API.class); + + private final HttpClient httpClient; + private final String address; + + private String errorDetailMessage = ""; + private ThingStatusDetail errorDetail = ThingStatusDetail.NONE; + + private @Nullable Integer collectionWeek = null; + private @Nullable Integer day = null; + private @Nullable ZonedDateTime recycling = null; + private @Nullable ZonedDateTime general = null; + + /** + * Create a new API class. + * + * @param httpClient The common http client provided from openHAB. + * @param address The address of the premises. + */ + public API(HttpClient httpClient, String address) { + this.httpClient = httpClient; + this.address = address; + } + + /** + * Connects to the web service and gets the data. + * + * @return boolean Success. + */ + public boolean update() { + try { + final String url = REQUEST_URL + URLEncoder.encode(address, StandardCharsets.UTF_8.toString()); + + logger.debug("Fetching data from URL {} (address hidden)", REQUEST_URL); + + ContentResponse response = httpClient.newRequest(url).timeout(REQUEST_TIMEOUT, TimeUnit.SECONDS).send(); + + if (response.getStatus() == HTTP_OK) { + String content = response.getContentAsString(); + // Return response is encapsulated in square brackets, remove to create valid json. + String cleanedContent = content.trim().substring(1, content.length() - 1); + logger.trace("Got cleaned content: {}", cleanedContent); + + JsonObject jsonResponse = JsonParser.parseString(cleanedContent).getAsJsonObject(); + + JsonElement dayElement = jsonResponse.get("CollectionDay"); + JsonElement collectionWeekElement = jsonResponse.get("CollectionWeek"); + JsonElement generalElement = jsonResponse.get("RedBin"); + JsonElement recyclingElement = jsonResponse.get("YellowBin"); + + // The elements are missing if the address is invalid or council does not service (due to address being + // a business) + if (generalElement == null || recyclingElement == null) { + logger.debug("RedBin or YellowBin object is missing. Invalid premises or address"); + + errorDetail = ThingStatusDetail.CONFIGURATION_ERROR; + errorDetailMessage = "Invalid address"; + return false; + } + + // Get API dates as LocalDateTime objects. + LocalDateTime localGeneralDate = LocalDateTime.parse(generalElement.getAsString()); + LocalDateTime localRecyclingDate = LocalDateTime.parse(recyclingElement.getAsString()); + + ZoneId zone = ZonedDateTime.now().getZone(); // Gets the local time zone. + + // Convert LocalDateTime objects to be compatible with openHAB + ZonedDateTime zonedGeneralDate = ZonedDateTime.of(localGeneralDate, zone); + ZonedDateTime zonedRecyclingDate = ZonedDateTime.of(localRecyclingDate, zone); + + errorDetail = ThingStatusDetail.NONE; // Sets to no error since we have successfully parsed response. + + // Set the local properties with values from API. + recycling = zonedRecyclingDate; + general = zonedGeneralDate; + + day = dayElement.getAsInt(); + collectionWeek = collectionWeekElement.getAsInt(); + + return true; + } else { + logger.error("Data fetch failed, got HTTP Code {}", response.getStatus()); + errorDetail = ThingStatusDetail.COMMUNICATION_ERROR; + errorDetailMessage = "HTTP Code " + response.getStatus(); + return false; + } + } catch (UnsupportedEncodingException ue) { + errorDetail = ThingStatusDetail.COMMUNICATION_ERROR; + errorDetailMessage = "Encoding not supported!"; + return false; + } catch (TimeoutException to) { + errorDetail = ThingStatusDetail.COMMUNICATION_ERROR; + errorDetailMessage = "Response Timeout (will try again soon)"; + return false; + } catch (InterruptedException | ExecutionException e) { + return false; + } + } + + /** + * Returns the last request status. + * + * @return ThingStatusDetail The openHAB error type. + */ + public ThingStatusDetail getErrorDetail() { + return errorDetail; + } + + /** + * Gets the error, if occurred. + * + * @return String The error message. + */ + public String getErrorDetailMessage() { + return errorDetailMessage; + } + + /** + * The collection week. + * + * @return Integer The week number. + */ + public @Nullable Integer getCollectionWeek() { + return collectionWeek; + } + + /** + * Gets the collection day of week. + * + * @return Integer The day of the week. 1 = Monday. + */ + public @Nullable Integer getDay() { + return day; + } + + /** + * The upcoming recycling collection date. + * + * @return ZonedDateTime + */ + public @Nullable ZonedDateTime getRecyclingDate() { + return recycling; + } + + /** + * The upcoming general rubbish collection date. + * + * @return ZonedDateTime + */ + public @Nullable ZonedDateTime getGeneralDate() { + return general; + } +} diff --git a/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionBindingConstants.java b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionBindingConstants.java new file mode 100644 index 00000000000..aac108ce87e --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionBindingConstants.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hccrubbishcollection.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link HCCRubbishCollectionBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Stewart Cossey - Initial contribution + */ +@NonNullByDefault +public class HCCRubbishCollectionBindingConstants { + + private static final String BINDING_ID = "hccrubbishcollection"; + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_COLLECTION = new ThingTypeUID(BINDING_ID, "collection"); + + // List of all Channel ids + public static final String CHANNEL_DAY = "day"; + public static final String CHANNEL_BIN_GENERAL = "general"; + public static final String CHANNEL_BIN_RECYCLING = "recycling"; + + public static final String TRIGGER_COLLECTION = "collection-event"; + public static final String EVENT_RECYCLING = "RECYCLING"; + public static final String EVENT_GENERAL = "GENERAL"; +} diff --git a/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionConfiguration.java b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionConfiguration.java new file mode 100644 index 00000000000..75af8d0db8f --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionConfiguration.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hccrubbishcollection.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link HCCRubbishCollectionConfiguration} class contains fields mapping thing configuration parameters. + * + * @author Stewart Cossey - Initial contribution + */ +@NonNullByDefault +public class HCCRubbishCollectionConfiguration { + public String address = ""; +} diff --git a/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionEventConfiguration.java b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionEventConfiguration.java new file mode 100644 index 00000000000..34e0c3bfe67 --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionEventConfiguration.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hccrubbishcollection.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link HCCRubbishCollectionEventConfiguration} class defines configuration for the collection event channel. + * + * @author Stewart Cossey - Initial contribution + */ +@NonNullByDefault +public class HCCRubbishCollectionEventConfiguration { + public int offset; +} diff --git a/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionHandler.java b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionHandler.java new file mode 100644 index 00000000000..3a640d46be6 --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionHandler.java @@ -0,0 +1,282 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hccrubbishcollection.internal; + +import static org.openhab.binding.hccrubbishcollection.internal.HCCRubbishCollectionBindingConstants.*; + +import java.time.ZonedDateTime; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link HCCRubbishCollectionHandler} is responsible for handling commands, + * updating the channels and polling the API. + * + * @author Stewart Cossey - Initial contribution + */ +@NonNullByDefault +public class HCCRubbishCollectionHandler extends BaseThingHandler { + private static final int DELAY_NETWORKERROR = 3; // On network error tries again in 3 minutes. + private static final int DELAY_UPDATE = 480; // Polls API every 8 hours. + + private final Logger logger = LoggerFactory.getLogger(HCCRubbishCollectionHandler.class); + + private final HttpClient httpClient; + private @Nullable API api; + + private @Nullable ScheduledFuture refreshScheduler; // The API refresh scheduler + private @Nullable ScheduledFuture collectionScheduler; // The Collection event trigger scheduler + + /** Object disposing flag */ + private boolean isDisposing = false; + + /** + * Create Handler. + * + * @param thing The thing type passed from the Handler Factory. + * @param httpClient The common http client provided from openHAB. + */ + public HCCRubbishCollectionHandler(Thing thing, HttpClient httpClient) { + super(thing); + + this.httpClient = httpClient; + } + + /** + * Handles a command coming from openHAB. + * Only RefreshType is supported as all channels are read only. + * + * @param channelUID The channel UID. + * @param command The command. + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + if (command instanceof RefreshType) { + updateNow(); + } + } + + /** + * Refreshes the data immediately. + */ + private void updateNow() { + if (isDisposing) { + return; + } + + logger.debug("Updating data immediately"); + stopUpdate(false); + startUpdate(0); + } + + @Override + public void initialize() { + final HCCRubbishCollectionConfiguration config = getConfigAs(HCCRubbishCollectionConfiguration.class); + + updateStatus(ThingStatus.UNKNOWN); + + api = new API(httpClient, config.address); + startUpdate(0); + } + + /** + * Gets the Rubbish collection data from the {@link API} and updates the + * channels with the data. + */ + private void updateData() { + logger.debug("Fetching new data"); + final API localApi = api; + if (localApi != null) { + if (isDisposing) { + return; + } + if (localApi.update()) { + if (isDisposing) { + return; + } + updateStatus(ThingStatus.ONLINE); // Updates Thing to online since API update was successful. + + Integer localDay = localApi.getDay(); + if (localDay != null) { + updateState(CHANNEL_DAY, new DecimalType(localDay)); + } + + ZonedDateTime localGeneralDate = localApi.getGeneralDate(); + if (localGeneralDate != null) { + updateState(CHANNEL_BIN_GENERAL, new DateTimeType(localGeneralDate)); + } + + ZonedDateTime localRecyclingDate = localApi.getRecyclingDate(); + if (localRecyclingDate != null) { + updateState(CHANNEL_BIN_RECYCLING, new DateTimeType(localRecyclingDate)); + } + + if (localGeneralDate != null && localRecyclingDate != null) { + setupCollectionEvent(localGeneralDate, localRecyclingDate); + } else { + logger.debug("Cannot setup Collection Event, one or both collection dates are null."); + } + } else { + if (localApi.getErrorDetail() != ThingStatusDetail.COMMUNICATION_ERROR) { + updateStatus(ThingStatus.OFFLINE, localApi.getErrorDetail(), localApi.getErrorDetailMessage()); + stopUpdate(false); + } else { + stopUpdate(true); + } + } + } else { + logger.error("API object is null, cannot update"); + } + } + + /** + * Calculates some values for the Collection Event before setting up the + * Collection trigger {@link #scheduleCollectionEvent}. + * + * @param generalDate The General Rubbish Collection Date and Time. + * @param recyclingDate The Recycling Collection Date and Time. + */ + private void setupCollectionEvent(ZonedDateTime generalDate, ZonedDateTime recyclingDate) { + logger.trace("Setup Collection Trigger"); + + String event; + ZonedDateTime dateTime; + if (generalDate.compareTo(recyclingDate) < 0) { + logger.trace("Using General Date {} for Event", generalDate); + dateTime = generalDate; + event = EVENT_GENERAL; + } else { + logger.trace("Using Recycling Date {} for Event", recyclingDate); + dateTime = recyclingDate; + event = EVENT_RECYCLING; + } + + logger.trace("Loading channel config"); + Channel collectionTriggerChannel = getThing().getChannel(TRIGGER_COLLECTION); + HCCRubbishCollectionEventConfiguration collectionEventConfig = (collectionTriggerChannel == null) ? null + : collectionTriggerChannel.getConfiguration().as(HCCRubbishCollectionEventConfiguration.class); + + long offset = 0; + if (collectionEventConfig != null) { + offset = (long) collectionEventConfig.offset; + } else { + logger.debug("Could not get event config, default offset of {} set", offset); + } + + ZonedDateTime offsettedDateTime = dateTime.plusMinutes(offset); + logger.trace("Event offset by {} minutes, new datetime {}", offset, offsettedDateTime); + scheduleCollectionEvent(offsettedDateTime, event); + } + + /** + * Sets up the collection event trigger. + * + * @param dateTime The Date and time to trigger the Collection Event. + * @param event The name of the Event to be triggered. + */ + private void scheduleCollectionEvent(ZonedDateTime dateTime, String event) { + stopScheduleCollectionEvent(); // Stop the currently scheduled event + + if (isDisposing) { + return; + } + + logger.trace("Setup Collection Trigger Scheduler"); + + logger.trace("Local Time {}", ZonedDateTime.now()); + long delay = dateTime.toEpochSecond() - ZonedDateTime.now().toEpochSecond(); + + logger.debug("Start collection scheduler, delay {} seconds ({} minutes)", delay, delay / 60); + if (delay > 0) { + collectionScheduler = scheduler.schedule(() -> { + if (isDisposing) { + return; + } + triggerChannel(TRIGGER_COLLECTION, event); + }, delay, TimeUnit.SECONDS); + } else { + logger.debug("Collection trigger delay already in past, ignoring"); + } + } + + /** + * Starts the data update scheduler. + * + * @param delay The start delay in minutes. 0 executes an immediate update. + */ + private void startUpdate(int delay) { + if (isDisposing) { + return; + } + logger.debug("Start refresh scheduler, delay {}", delay); + + refreshScheduler = scheduler.scheduleWithFixedDelay(this::updateData, delay, DELAY_UPDATE, TimeUnit.MINUTES); + } + + /** + * Stops the scheduler for the collection event trigger. + */ + private void stopScheduleCollectionEvent() { + ScheduledFuture localCollectionScheduler = collectionScheduler; + logger.debug("Stopping Collection Trigger Scheduler"); + if (localCollectionScheduler != null) { + localCollectionScheduler.cancel(true); + collectionScheduler = null; + } + } + + /** + * Stop the data update scheduler (stops updating data). If stopping due to a + * network error, then resets the update scheduler {@link #startUpdate(int)} + * with an initial delay to wait a short period then try again. + * + * @param networkError Set to true if a network error. False if terminating. + */ + private void stopUpdate(boolean networkError) { + final ScheduledFuture localRefreshScheduler = refreshScheduler; + logger.debug("Stopping updater scheduler, networkError = {}", networkError); + if (localRefreshScheduler != null) { + localRefreshScheduler.cancel(true); + refreshScheduler = null; + } + if (networkError) { + logger.debug("Waiting {} minutes to try again", DELAY_NETWORKERROR); + startUpdate(DELAY_NETWORKERROR); + } + } + + @Override + public void dispose() { + isDisposing = true; // Set true to exit any running functions + stopUpdate(false); + stopScheduleCollectionEvent(); + + super.dispose(); + } +} diff --git a/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionHandlerFactory.java b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionHandlerFactory.java new file mode 100644 index 00000000000..af35883c03a --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/src/main/java/org/openhab/binding/hccrubbishcollection/internal/HCCRubbishCollectionHandlerFactory.java @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hccrubbishcollection.internal; + +import static org.openhab.binding.hccrubbishcollection.internal.HCCRubbishCollectionBindingConstants.*; + +import java.util.Collections; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.openhab.core.io.net.http.HttpClientFactory; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * The {@link HCCRubbishCollectionHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Stewart Cossey - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.hccrubbishcollection", service = ThingHandlerFactory.class) +public class HCCRubbishCollectionHandlerFactory extends BaseThingHandlerFactory { + + private final HttpClient httpClient; + private static final Set SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_COLLECTION); + + @Activate + public HCCRubbishCollectionHandlerFactory(final @Reference HttpClientFactory httpClientFactory) { + this.httpClient = httpClientFactory.getCommonHttpClient(); + } + + @Override + public boolean supportsThingType(ThingTypeUID thingTypeUID) { + return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); + } + + @Override + protected @Nullable ThingHandler createHandler(Thing thing) { + ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + + if (THING_TYPE_COLLECTION.equals(thingTypeUID)) { + return new HCCRubbishCollectionHandler(thing, httpClient); + } + + return null; + } +} diff --git a/bundles/org.openhab.binding.hccrubbishcollection/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.hccrubbishcollection/src/main/resources/OH-INF/binding/binding.xml new file mode 100644 index 00000000000..c10961e0f11 --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/src/main/resources/OH-INF/binding/binding.xml @@ -0,0 +1,9 @@ + + + + HCC Rubbish Collection Binding + Get the rubbish collection dates for Hamilton City Council (New Zealand). + + diff --git a/bundles/org.openhab.binding.hccrubbishcollection/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.hccrubbishcollection/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 00000000000..fed9d344e42 --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,72 @@ + + + + + + Rubbish collection days for Hamilton City Council (NZ). + + + + + + The next collection date of the recycling (yellow bin and green bin). + + + + The next collection date of the general rubbish (red bin). + + + + + + + + The street address to get rubbish collection dates for. + + + + + + + Number + + The rubbish collection Day of the Week + + + + + + + + + + + + + + DateTime + + + + + trigger + + Event for the day when collection occurs. + + + + + + + + + + Moves the event forward or backward (in minutes). + 0 + + + + diff --git a/bundles/pom.xml b/bundles/pom.xml index 4320e099313..091bbaf5fac 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -133,6 +133,7 @@ org.openhab.binding.haassohnpelletstove org.openhab.binding.harmonyhub org.openhab.binding.haywardomnilogic + org.openhab.binding.hccrubbishcollection org.openhab.binding.hdanywhere org.openhab.binding.hdpowerview org.openhab.binding.helios