/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
<artifactId>org.openhab.binding.haywardomnilogic</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.openhab.addons.bundles</groupId>
+ <artifactId>org.openhab.binding.hccrubbishcollection</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.hdanywhere</artifactId>
--- /dev/null
+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
--- /dev/null
+# 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).*
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.openhab.addons.bundles</groupId>
+ <artifactId>org.openhab.addons.reactor.bundles</artifactId>
+ <version>3.1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>org.openhab.binding.hccrubbishcollection</artifactId>
+
+ <name>openHAB Add-ons :: Bundles :: HCC Rubbish Collection Binding</name>
+
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<features name="org.openhab.binding.hccrubbishcollection-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
+ <repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
+
+ <feature name="openhab-binding-hccrubbishcollection" description="HCC Rubbish Collection Binding" version="${project.version}">
+ <feature>openhab-runtime-base</feature>
+ <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.hccrubbishcollection/${project.version}</bundle>
+ </feature>
+</features>
--- /dev/null
+/**
+ * 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;
+ }
+}
--- /dev/null
+/**
+ * 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";
+}
--- /dev/null
+/**
+ * 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 = "";
+}
--- /dev/null
+/**
+ * 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;
+}
--- /dev/null
+/**
+ * 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();
+ }
+}
--- /dev/null
+/**
+ * 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<ThingTypeUID> 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;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<binding:binding id="hccrubbishcollection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
+ xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
+
+ <name>HCC Rubbish Collection Binding</name>
+ <description>Get the rubbish collection dates for Hamilton City Council (New Zealand).</description>
+
+</binding:binding>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="hccrubbishcollection"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
+ xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
+
+ <thing-type id="collection">
+ <label>HCC NZ Rubbish Collection</label>
+ <description>Rubbish collection days for Hamilton City Council (NZ).</description>
+
+ <channels>
+ <channel id="day" typeId="day"/>
+ <channel id="recycling" typeId="bin">
+ <label>Recycling Bin Collection Date</label>
+ <description>The next collection date of the recycling (yellow bin and green bin).</description>
+ </channel>
+ <channel id="general" typeId="bin">
+ <label>General Bin Collection Date</label>
+ <description>The next collection date of the general rubbish (red bin).</description>
+ </channel>
+ <channel id="collection-event" typeId="collection-event"/>
+ </channels>
+
+ <config-description>
+ <parameter name="address" type="text" required="true">
+ <label>Address</label>
+ <description>The street address to get rubbish collection dates for.</description>
+ </parameter>
+ </config-description>
+
+ </thing-type>
+
+ <channel-type id="day">
+ <item-type>Number</item-type>
+ <label>Collection Day</label>
+ <description>The rubbish collection Day of the Week</description>
+ <state readOnly="true">
+ <options>
+ <option value="1">Monday</option>
+ <option value="2">Tuesday</option>
+ <option value="3">Wednesday</option>
+ <option value="4">Thursday</option>
+ <option value="5">Friday</option>
+ <option value="6">Saturday</option>
+ <option value="7">Sunday</option>
+ </options>
+ </state>
+ </channel-type>
+ <channel-type id="bin">
+ <item-type>DateTime</item-type>
+ <label>Collection Date</label>
+ <state pattern="%1$tY-%1$tm-%1$td" readOnly="true"></state>
+ </channel-type>
+ <channel-type id="collection-event">
+ <kind>trigger</kind>
+ <label>Collection Event</label>
+ <description>Event for the day when collection occurs.</description>
+ <event>
+ <options>
+ <option value="RECYCLING">RECYCLING</option>
+ <option value="GENERAL">GENERAL</option>
+ </options>
+ </event>
+ <config-description>
+ <parameter name="offset" type="integer" min="-2880" max="2880" unit="min">
+ <label>Offset</label>
+ <description>Moves the event forward or backward (in minutes).</description>
+ <default>0</default>
+ </parameter>
+ </config-description>
+ </channel-type>
+</thing:thing-descriptions>
<module>org.openhab.binding.haassohnpelletstove</module>
<module>org.openhab.binding.harmonyhub</module>
<module>org.openhab.binding.haywardomnilogic</module>
+ <module>org.openhab.binding.hccrubbishcollection</module>
<module>org.openhab.binding.hdanywhere</module>
<module>org.openhab.binding.hdpowerview</module>
<module>org.openhab.binding.helios</module>