diff --git a/CODEOWNERS b/CODEOWNERS
index 454ca798a43fb..c89961092dc97 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -9,6 +9,7 @@
/bundles/org.openhab.automation.jythonscripting/ @openhab/add-ons-maintainers
/bundles/org.openhab.automation.pidcontroller/ @fwolter
/bundles/org.openhab.binding.adorne/ @theiding
+/bundles/org.openhab.binding.ahawastecollection/ @soenkekueper
/bundles/org.openhab.binding.airq/ @aurelio1
/bundles/org.openhab.binding.airquality/ @kubawolanin
/bundles/org.openhab.binding.airvisualnode/ @3cky
diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml
index 10205adc0c26b..a26ae4965a197 100644
--- a/bom/openhab-addons/pom.xml
+++ b/bom/openhab-addons/pom.xml
@@ -36,6 +36,11 @@
org.openhab.binding.adorne${project.version}
+
+ org.openhab.addons.bundles
+ org.openhab.binding.ahawastecollection
+ ${project.version}
+ org.openhab.addons.bundlesorg.openhab.binding.airq
diff --git a/bundles/org.openhab.binding.ahawastecollection/NOTICE b/bundles/org.openhab.binding.ahawastecollection/NOTICE
new file mode 100644
index 0000000000000..810b7b7e4f792
--- /dev/null
+++ b/bundles/org.openhab.binding.ahawastecollection/NOTICE
@@ -0,0 +1,21 @@
+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
+
+
+== Third-party Content
+
+jsoup
+* License: MIT License
+* Project: https://jsoup.org/
+* Source: https://github.com/jhy/jsoup
diff --git a/bundles/org.openhab.binding.ahawastecollection/README.md b/bundles/org.openhab.binding.ahawastecollection/README.md
new file mode 100644
index 0000000000000..a78b2a1998bda
--- /dev/null
+++ b/bundles/org.openhab.binding.ahawastecollection/README.md
@@ -0,0 +1,139 @@
+# aha Waste Collection Binding
+
+This binding provides information about the upcoming waste collection dates for places, that are served by aha, the waste collection company for the region of Hannover. The values are retrieved from the online aha waste collection schedule available at: [aha Abfuhrkalender](https://www.aha-region.de/abholtermine/abfuhrkalender).
+
+## Supported Things
+
+- **collectionSchedule:** Represents the connection to the **aha Waste Collection Schedule** with four channels for the different waste types.
+
+## Discovery
+
+Discovery is not possible, due some form input values from the website above are required.
+
+## Thing Configuration
+
+For configuration of the **collectionSchedule** thing, you need the form inputs from the aha collections schedule web page. Follow the steps below to get the required configuration parameters from the form input values.
+
+
+1. Open [aha Abfuhrkalender](https://www.aha-region.de/abholtermine/abfuhrkalender) in your favorite brower with developer-console.
+2. Open the developer console and switch to network tab (for example press F12 in chrome / edge / firefox).
+3. Fill in the form: Select your commune, Street and house number and hit "Suchen".
+4. Select the first request to https://www.aha-region.de/abholtermine/abfuhrkalender (see first screenshot below)
+5. Check the form data at the end of the request for the form values (see second screenshot below)
+5. Fill in the values from the form input in thing configuration (see examples below)
+
+![Chrome Developer Console Top](doc/images/ChromeDevconsoleTop.png "Chrome Developer Console showing request URL")
+
+*Check if you've selected the correct request, that contains the form data*
+
+![Chrome Developer Console Bottom](doc/images/ChromeDevconsoleBottom.png "Chrome Developer Console showing form inputs")
+
+*Grab the values for the configuration parameters from the form data section at the end of the request*
+
+**collectionSchedule** parameters:
+
+| Property | Default | Required | Description |
+|-|-|-|-|
+| `commune` | | Yes | The selected commune, taken from the form field `gemeinde`. |
+| `street` | | Yes | The selected street, taken from the form field `strasse`. This value must look like 67269@Rosmarinweg+/+Kirchhorst@Kirchhorst |
+| `houseNumber` | | Yes | The selected house number, taken from the form field `hausnr`. |
+| `houseNumberAddon` | | No | The selected house number addon, taken from the form field `hausnraddon`, may be empty. |
+| `collectionPlace` | | Yes | Form value for the collection place, taken from the form field `ladeort`. This value must look like 67269-0010+ |
+
+## Channels
+
+The thing **aha Waste Collection Schedule** provides four channels for the upcoming day of waste collection for the different waste types.
+
+
+| channel | type | description |
+|----------|--------|------------------------------|
+| generalWaste | DateTime | Next collection day for general waste |
+| leightweightPackaging | DateTime | Next collection day for leightweight packaging |
+| bioWaste | DateTime | Next collection day for bio waste |
+| paper | DateTime | Next collection day for paper |
+
+
+## Full Example
+
+wasteCollection.things
+
+```
+Thing ahawastecollection:collectionSchedule:wasteCollectionSchedule "aha Abfuhrkalender" [ commune="Isernhagen", street="67269@Rosmarinweg+/+Kirchhorst@Kirchhorst", houseNumber="10", houseNumberAddon="", collectionPlace="67269-0010+" ]
+```
+
+wasteCollection.items
+
+```
+DateTime collectionDay_generalWaste "Next general waste collection" {channel="ahawastecollection:collectionSchedule:wasteCollectionSchedule:generalWaste"}
+DateTime collectionDay_leightweightPackaging "Next lightweight packaging collection" {channel="ahawastecollection:collectionSchedule:wasteCollectionSchedule:leightweightPackaging"}
+DateTime collectionDay_bioWaste "Next bio waste collection" {channel="ahawastecollection:collectionSchedule:wasteCollectionSchedule:bioWaste"}
+DateTime collectionDay_paper "Next paper collection" {channel="ahawastecollection:collectionSchedule:wasteCollectionSchedule:paper"}
+```
+
+
+Example for rule that sends an notification with collected waste types on day before collection
+
+```
+triggers:
+ - id: "1"
+ configuration:
+ time: 18:00
+ type: timer.TimeOfDayTrigger
+conditions: []
+actions:
+ - inputs: {}
+ id: "2"
+ configuration:
+ type: application/javascript
+ script: >-
+ // Determine next day with time 00:00:00
+ var today = items['LokaleZeit_DatumundZeit'];
+
+ var tomorrow = today
+ .getZonedDateTime()
+ .plusDays(1)
+ .withHour(0)
+ .withMinute(0)
+ .withSecond(0)
+ .withNano(0);
+
+ // Get next collection dates from items
+ var biomuellDate = items['collectionDay_bioWaste'].getZonedDateTime();
+ var leichtverpackungDate = items['collectionDay_leightweightPackaging'].getZonedDateTime();
+ var papierDate = items['collectionDay_paper'].getZonedDateTime();
+ var restmuellDate = items['collectionDay_generalWaste'].getZonedDateTime();
+
+
+ // Check which waste types are collected on the next day
+ var biomuellCollection = biomuellDate.equals(tomorrow);
+ var leichtverpackungCollection = leichtverpackungDate.equals(tomorrow);
+ var papierCollection = papierDate.equals(tomorrow);
+ var restmuellCollection = restmuellDate.equals(tomorrow);
+
+ // Transfer booleans to waste type names
+ var toBeCollected = [];
+
+ if (biomuellCollection) {
+ toBeCollected.push('bio waste');
+ }
+
+ if (leichtverpackungCollection) {
+ toBeCollected.push('leihtweight packaging');
+ }
+
+ if (papierCollection) {
+ toBeCollected.push('paper');
+ }
+
+ if (restmuellCollection) {
+ toBeCollected.push('general waste');
+ }
+
+
+ // Send message (or something else) if at least one waste type is collected
+ if (toBeCollected.length > 0) {
+ var message = "Tomorrow the following waste will be collected:\n" + toBeCollected.join(', ');
+ events.sendCommand('SignalSmartHome_Eingabewert', message);
+ }
+ type: script.ScriptAction
+```
diff --git a/bundles/org.openhab.binding.ahawastecollection/doc/images/ChromeDevconsoleBottom.png b/bundles/org.openhab.binding.ahawastecollection/doc/images/ChromeDevconsoleBottom.png
new file mode 100644
index 0000000000000..dd9b87798246c
Binary files /dev/null and b/bundles/org.openhab.binding.ahawastecollection/doc/images/ChromeDevconsoleBottom.png differ
diff --git a/bundles/org.openhab.binding.ahawastecollection/doc/images/ChromeDevconsoleTop.png b/bundles/org.openhab.binding.ahawastecollection/doc/images/ChromeDevconsoleTop.png
new file mode 100644
index 0000000000000..8e9b925963119
Binary files /dev/null and b/bundles/org.openhab.binding.ahawastecollection/doc/images/ChromeDevconsoleTop.png differ
diff --git a/bundles/org.openhab.binding.ahawastecollection/pom.xml b/bundles/org.openhab.binding.ahawastecollection/pom.xml
new file mode 100644
index 0000000000000..e23178b337245
--- /dev/null
+++ b/bundles/org.openhab.binding.ahawastecollection/pom.xml
@@ -0,0 +1,26 @@
+
+
+
+ 4.0.0
+
+
+ org.openhab.addons.bundles
+ org.openhab.addons.reactor.bundles
+ 3.1.0-SNAPSHOT
+
+
+ org.openhab.binding.ahawastecollection
+
+ openHAB Add-ons :: Bundles :: aha Waste Collection Binding
+
+
+
+ org.jsoup
+ jsoup
+ 1.8.3
+ provided
+
+
+
+
diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/feature/feature.xml b/bundles/org.openhab.binding.ahawastecollection/src/main/feature/feature.xml
new file mode 100644
index 0000000000000..b09d4bcd0b694
--- /dev/null
+++ b/bundles/org.openhab.binding.ahawastecollection/src/main/feature/feature.xml
@@ -0,0 +1,10 @@
+
+
+ mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features
+
+
+ openhab-runtime-base
+ mvn:org.jsoup/jsoup/1.8.3
+ mvn:org.openhab.addons.bundles/org.openhab.binding.ahawastecollection/${project.version}
+
+
diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionSchedule.java b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionSchedule.java
new file mode 100644
index 0000000000000..6afb91fdaffc1
--- /dev/null
+++ b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionSchedule.java
@@ -0,0 +1,33 @@
+/**
+ * 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.ahawastecollection.internal;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.ahawastecollection.internal.CollectionDate.WasteType;
+
+/**
+ * Schedule that returns the next collection dates from the aha website.
+ *
+ * @author Sönke Küper - Initial contribution
+ */
+@NonNullByDefault
+public interface AhaCollectionSchedule {
+
+ /**
+ * Returns the next collection dates per {@link WasteType}.
+ */
+ public Map getCollectionDates() throws IOException;
+}
diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionScheduleFactory.java b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionScheduleFactory.java
new file mode 100644
index 0000000000000..20b80d605c438
--- /dev/null
+++ b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionScheduleFactory.java
@@ -0,0 +1,30 @@
+/**
+ * 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.ahawastecollection.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Factory for creating an {@link AhaCollectionSchedule}.
+ *
+ * @author Sönke Küper - Initial contribution
+ */
+@NonNullByDefault
+public interface AhaCollectionScheduleFactory {
+
+ /**
+ * Creates an new {@link AhaCollectionSchedule} for the given location.
+ */
+ public AhaCollectionSchedule create(final String commune, final String street, final String houseNumber,
+ final String houseNumberAddon, final String collectionPlace);
+}
diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionScheduleImpl.java b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionScheduleImpl.java
new file mode 100644
index 0000000000000..d031ceb6b77db
--- /dev/null
+++ b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionScheduleImpl.java
@@ -0,0 +1,195 @@
+/**
+ * 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.ahawastecollection.internal;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.jsoup.Connection.Method;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.openhab.binding.ahawastecollection.internal.CollectionDate.WasteType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Schedule that returns the next collection dates from the aha website.
+ *
+ * @author Sönke Küper - Initial contribution
+ */
+@NonNullByDefault
+final class AhaCollectionScheduleImpl implements AhaCollectionSchedule {
+
+ private static final Pattern TIME_PATTERN = Pattern.compile("\\S\\S,\\s(\\d\\d.\\d\\d.\\d\\d\\d\\d)");
+ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy");
+ private static final String WEBSITE_URL = "https://www.aha-region.de/abholtermine/abfuhrkalender/";
+
+ private final Logger logger = LoggerFactory.getLogger(AhaCollectionScheduleImpl.class);
+ private final String commune;
+ private final String street;
+ private final String houseNumber;
+ private final String houseNumberAddon;
+ private final String collectionPlace;
+
+ /**
+ * Creates an new {@link AhaCollectionScheduleImpl} for the given location.
+ */
+ public AhaCollectionScheduleImpl(final String commune, final String street, final String houseNumber,
+ final String houseNumberAddon, final String collectionPlace) {
+ this.commune = commune;
+ this.street = street;
+ this.houseNumber = houseNumber;
+ this.houseNumberAddon = houseNumberAddon;
+ this.collectionPlace = collectionPlace;
+ }
+
+ @Override
+ public Map getCollectionDates() throws IOException {
+ final Document doc = Jsoup.connect(WEBSITE_URL) //
+ .method(Method.POST) //
+ .data("gemeinde", this.commune) //
+ .data("strasse", this.street) //
+ .data("hausnr", this.houseNumber) //
+ .data("hausnraddon", this.houseNumberAddon) //
+ .data("ladeort", this.collectionPlace) //
+ .data("anzeigen", "Suchen") //
+ .get();
+
+ final Elements table = doc.select("table");
+
+ if (table.size() == 0) {
+ logger.warn("No result table found.");
+ return Collections.emptyMap();
+ }
+
+ final Iterator rowIt = table.get(0).getElementsByTag("tr").iterator();
+ final Map result = new HashMap<>();
+
+ while (rowIt.hasNext()) {
+ final Element currentRow = rowIt.next();
+ if (!currentRow.tagName().equals("tr")) {
+ continue;
+ }
+ // Skip header, empty and download button rows.
+ if (isHeader(currentRow) || isDelimiterOrDownloadRow(currentRow)) {
+ continue;
+ }
+
+ // If no following row is present, no collection dates can be parsed
+ if (!rowIt.hasNext()) {
+ logger.warn("No row with collection dates found.");
+ break;
+ }
+ final Element collectionDatesRow = rowIt.next();
+
+ final CollectionDate date = this.parseRows(currentRow, collectionDatesRow);
+ if (date != null) {
+ result.put(date.getType(), date);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Parses the row with the waste type and the following row with the collection dates.
+ *
+ * @param wasteTypeRow Row that contains the waste type information
+ * @param collectionDatesRow Row that contains the collection date informations.
+ * @return The parsed {@link CollectionDate} or null if information could not be parsed.
+ */
+ @Nullable
+ private CollectionDate parseRows(Element wasteTypeRow, Element collectionDatesRow) {
+ // Try to extract the waste Type from the first row
+ final Elements wasteTypeElement = wasteTypeRow.select("td").select("strong");
+ if (wasteTypeElement.size() != 1) {
+ this.logger.warn("Could not parse waste type row: {}", wasteTypeRow.toString());
+ return null;
+ }
+ final WasteType wasteType = parseWasteType(wasteTypeElement.get(0));
+
+ // Try to extract the collection dates from the second row
+ final Elements collectionDatesColumns = collectionDatesRow.select("td");
+ if (collectionDatesColumns.size() != 3) {
+ this.logger.warn("collection dates row could not be parsed.");
+ return null;
+ }
+
+ final Element collectionDatesColumn = collectionDatesColumns.get(1);
+ final List collectionDates = parseTimes(collectionDatesColumn);
+
+ if (!collectionDates.isEmpty()) {
+ return new CollectionDate(wasteType, collectionDates);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns true if the row is an (empty) delimiter row or if its an row that contains the download
+ * buttons for ical.
+ */
+ private boolean isDelimiterOrDownloadRow(Element currentRow) {
+ final Elements columns = currentRow.select("td");
+ return columns.size() == 1 && columns.get(0).text().isBlank() || !columns.select("form").isEmpty();
+ }
+
+ private boolean isHeader(Element currentRow) {
+ return !currentRow.select("th").isEmpty();
+ }
+
+ /**
+ * Parses the waste types from the given {@link Element table cell}.
+ */
+ private static WasteType parseWasteType(final Element element) {
+ String value = element.text().trim();
+ final int firstSpace = value.indexOf(" ");
+ if (firstSpace > 0) {
+ value = value.substring(0, firstSpace);
+ }
+ return WasteType.parseValue(value);
+ }
+
+ /**
+ * Parses the {@link CollectionDate} from the given {@link Element table cell}.
+ */
+ private List parseTimes(final Element element) {
+ final List result = new ArrayList<>();
+ final String value = element.text();
+ final Matcher matcher = TIME_PATTERN.matcher(value);
+ while (matcher.find()) {
+ final String dateValue = matcher.group(1);
+ try {
+ synchronized (DATE_FORMAT) {
+ result.add(DATE_FORMAT.parse(dateValue));
+ }
+ } catch (final ParseException e) {
+ this.logger.warn("Could not parse date: {}", dateValue);
+ }
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionBindingConstants.java b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionBindingConstants.java
new file mode 100644
index 0000000000000..ed12c3ef175b8
--- /dev/null
+++ b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionBindingConstants.java
@@ -0,0 +1,37 @@
+/**
+ * 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.ahawastecollection.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link AhaWasteCollectionBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Sönke Küper - Initial contribution
+ */
+@NonNullByDefault
+public class AhaWasteCollectionBindingConstants {
+
+ private static final String BINDING_ID = "ahawastecollection";
+
+ // List of all Thing Type UIDs
+ public static final ThingTypeUID THING_TYPE_SCHEDULE = new ThingTypeUID(BINDING_ID, "collectionSchedule");
+
+ // List of all Channel ids
+ public static final String GENERAL_WASTE = "generalWaste";
+ public static final String LEIGHTWEIGHT_PACKAGING = "leightweightPackaging";
+ public static final String BIOWASTE = "bioWaste";
+ public static final String PAPER = "paper";
+}
diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionConfiguration.java b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionConfiguration.java
new file mode 100644
index 0000000000000..d496ee907511c
--- /dev/null
+++ b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionConfiguration.java
@@ -0,0 +1,49 @@
+/**
+ * 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.ahawastecollection.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link AhaWasteCollectionConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Sönke Küper - Initial contribution
+ */
+@NonNullByDefault
+public class AhaWasteCollectionConfiguration {
+
+ /**
+ * Commune.
+ */
+ public String commune = "";
+
+ /**
+ * Street.
+ */
+ public String street = "";
+
+ /**
+ * House number.
+ */
+ public String houseNumber = "";
+
+ /**
+ * House number addon.
+ */
+ public String houseNumberAddon = "";
+
+ /**
+ * Collection place.
+ */
+ public String collectionPlace = "";
+}
diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandler.java b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandler.java
new file mode 100644
index 0000000000000..26bffeb6c002e
--- /dev/null
+++ b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandler.java
@@ -0,0 +1,208 @@
+/**
+ * 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.ahawastecollection.internal;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.time.ZonedDateTime;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.ahawastecollection.internal.CollectionDate.WasteType;
+import org.openhab.core.cache.ExpiringCache;
+import org.openhab.core.i18n.TimeZoneProvider;
+import org.openhab.core.library.types.DateTimeType;
+import org.openhab.core.scheduler.CronScheduler;
+import org.openhab.core.scheduler.ScheduledCompletableFuture;
+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 AhaWasteCollectionHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Sönke Küper - Initial contribution
+ */
+@NonNullByDefault
+public class AhaWasteCollectionHandler extends BaseThingHandler {
+
+ private static final String DAILY_MIDNIGHT = "30 0 0 * * ? *";
+
+ /** Scheduler to schedule jobs */
+ private final CronScheduler cronScheduler;
+ private final Lock monitor = new ReentrantLock();
+ private final ExpiringCache