diff --git a/CODEOWNERS b/CODEOWNERS index 122c664046cb4..759119ef777c3 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.airquality/ @kubawolanin /bundles/org.openhab.binding.airvisualnode/ @3cky /bundles/org.openhab.binding.alarmdecoder/ @bobadair @billfor diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 4eaa9f9befd40..14c94b00a5d0e 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.bundles org.openhab.binding.airquality diff --git a/bundles/org.openhab.binding.ahawastecollection/README.md b/bundles/org.openhab.binding.ahawastecollection/README.md index c7db328231885..f4465fdf0c4f7 100644 --- a/bundles/org.openhab.binding.ahawastecollection/README.md +++ b/bundles/org.openhab.binding.ahawastecollection/README.md @@ -1,10 +1,10 @@ # aha Waste Collection Binding -This Binding allows requesting the next waste collection days from the aha waste collection schedule, reachable at [aha Abfuhrkalender](https://www.aha-region.de/abholtermine/abfuhrkalender). +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 -The binding supports one thing type **aha Waste Collection Schedule** with four channels for the different waste types. +- **collectionSchedule:** Represents the connection to the **aha Waste Collection Schedule** with four channels for the different waste types. ## Discovery @@ -12,18 +12,37 @@ Discovery is not possible, due some form input values from the website above are ## Thing Configuration -To configure an **aha Waste Collection Schedule** thing, you need first to get the required parameters from to get them follow the instructions below: -the form at https://www.aha-region.de/abholtermine/abfuhrkalender. +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 Housenumber and hit "Suchen". -4. Grab the form input fields from the first POST request to https://www.aha-region.de/abholtermine/abfuhrkalender. -5. Fill in the values from the form input in thing configuration. +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 next day of waste collection from the different waste types. +The thing **aha Waste Collection Schedule** provides four channels for the upcoming day of waste collection for the different waste types. | channel | type | description | @@ -38,13 +57,13 @@ The thing **aha Waste Collection Schedule** provides four channels for the next wasteCollection.things -```xtend +``` Thing ahawastecollection:collectionSchedule:wasteCollectionSchedule "aha Abfuhrkalender" [ commune="Isernhagen", street="67269@Rosmarinweg+/+Kirchhorst@Kirchhorst", houseNumber="10", houseNumberAddon="", collectionPlace="67269-0010+" ] ``` wasteCollection.items -```xtend +``` DateTime collectionDay_generalWaste "Next genral 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"} 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 index 2ed1039f1a011..7f623bc1a7596 100644 --- a/bundles/org.openhab.binding.ahawastecollection/pom.xml +++ b/bundles/org.openhab.binding.ahawastecollection/pom.xml @@ -12,7 +12,7 @@ org.openhab.binding.ahawastecollection - openHAB Add-ons :: Bundles :: AhaWasteCollection Binding + openHAB Add-ons :: Bundles :: aha Waste Collection Binding diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/feature/feature.xml b/bundles/org.openhab.binding.ahawastecollection/src/main/feature/feature.xml index e7d5af064e92f..6fd4501566d6e 100644 --- a/bundles/org.openhab.binding.ahawastecollection/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.ahawastecollection/src/main/feature/feature.xml @@ -2,7 +2,7 @@ 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.ahawastecollection/${project.version} 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 index cd2c5bbd74589..20b80d605c438 100644 --- 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 @@ -16,7 +16,7 @@ /** * Factory for creating an {@link AhaCollectionSchedule}. - * + * * @author Sönke Küper - Initial contribution */ @NonNullByDefault @@ -25,6 +25,6 @@ public interface AhaCollectionScheduleFactory { /** * Creates an new {@link AhaCollectionSchedule} for the given location. */ - public AhaCollectionSchedule create(final String gemeinde, final String strasse, final String hausnr, - final String hausnraddon, final String ladeort); + 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 index e631cd91970ea..08151ed726681 100644 --- 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 @@ -37,7 +37,7 @@ /** * Schedule that returns the next collection dates from the aha website. - * + * * @author Sönke Küper - Initial contribution */ @NonNullByDefault @@ -48,33 +48,33 @@ final class AhaCollectionScheduleImpl implements AhaCollectionSchedule { private static final String WEBSITE_URL = "https://www.aha-region.de/abholtermine/abfuhrkalender/"; private final Logger logger = LoggerFactory.getLogger(AhaCollectionScheduleImpl.class); - private final String gemeinde; - private final String strasse; - private final String hausnr; - private final String hausnraddon; - private final String ladeort; + 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 gemeinde, final String strasse, final String hausnr, - final String hausnraddon, final String ladeort) { - this.gemeinde = gemeinde; - this.strasse = strasse; - this.hausnr = hausnr; - this.hausnraddon = hausnraddon; - this.ladeort = ladeort; + 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.gemeinde) // - .data("strasse", this.strasse) // - .data("hausnr", this.hausnr) // - .data("hausnraddon", this.hausnraddon) // - .data("ladeort", this.ladeort) // + .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 tableRows = doc.select("table").select("tr"); @@ -98,11 +98,10 @@ public Map getCollectionDates() throws IOException { /** * Parses the {@link CollectionDate} from the given {@link Element table row}. - * + * * @return The {@link CollectionDate} or null if no dates could be parsed. */ - @Nullable - private CollectionDate parseRow(final Element row) { + private @Nullable CollectionDate parseRow(final Element row) { final Elements columns = row.select("td"); if (columns.size() != 5) { this.logger.debug("Could not parse row: {}", row.toString()); @@ -143,7 +142,7 @@ private List parseTimes(final Element element) { try { result.add(DATE_FORMAT.parse(dateValue)); } catch (final ParseException e) { - this.logger.warn("Could not parse date: {}", dateValue); //$NON-NLS-1$ + 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/AhaWasteCollectionHandler.java b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandler.java index 71be86121df47..92d91dbd5fda7 100644 --- 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 @@ -64,10 +64,10 @@ public class AhaWasteCollectionHandler extends BaseThingHandler { private @Nullable ScheduledCompletableFuture dailyJob; - private AhaCollectionScheduleFactory scheduleFactory; + private final AhaCollectionScheduleFactory scheduleFactory; public AhaWasteCollectionHandler(final Thing thing, final CronScheduler scheduler, - final TimeZoneProvider timeZoneProvider, AhaCollectionScheduleFactory scheduleFactory) { + final TimeZoneProvider timeZoneProvider, final AhaCollectionScheduleFactory scheduleFactory) { super(thing); this.cronScheduler = scheduler; this.timeZoneProvider = timeZoneProvider; @@ -77,8 +77,10 @@ public AhaWasteCollectionHandler(final Thing thing, final CronScheduler schedule private Map loadCollectionDates() { try { - return this.collectionSchedule.getCollectionDates(); - } catch (IOException e) { + final Map collectionDates = this.collectionSchedule.getCollectionDates(); + this.updateStatus(ThingStatus.ONLINE); + return collectionDates; + } catch (final IOException e) { this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); return Collections.emptyMap(); } @@ -97,19 +99,20 @@ public void handleCommand(final ChannelUID channelUID, final Command command) { public void initialize() { this.config = this.getConfigAs(AhaWasteCollectionConfiguration.class); - final String gemeinde = this.config.commune; + final String commune = this.config.commune; final String street = this.config.street; - final String hausnr = this.config.houseNumber; - final String hausnraddon = this.config.houseNumberAddon; - final String ladeort = this.config.collectionPlace; + final String houseNumber = this.config.houseNumber; + final String houseNumberAddon = this.config.houseNumberAddon; + final String collectionPlace = this.config.collectionPlace; - if (gemeinde.isBlank() || street.isBlank() || hausnr.isBlank() || ladeort.isBlank()) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + if (commune.isBlank() || street.isBlank() || houseNumber.isBlank() || collectionPlace.isBlank()) { + this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Parameters are mandatory and must be configured"); return; } - this.collectionSchedule = scheduleFactory.create(gemeinde, street, hausnr, hausnraddon, ladeort); + this.collectionSchedule = this.scheduleFactory.create(commune, street, houseNumber, houseNumberAddon, + collectionPlace); this.updateStatus(ThingStatus.UNKNOWN); @@ -133,7 +136,7 @@ private void restartJob() { this.dailyJob = this.cronScheduler.schedule(this::updateCollectionDates, DAILY_MIDNIGHT); this.logger.debug("Scheduled {} at midnight", this.dailyJob); // Execute daily startup job immediately - updateCollectionDates(); + this.updateCollectionDates(); } } finally { this.monitor.unlock(); @@ -164,8 +167,6 @@ private boolean updateCollectionDates() { this.logger.debug("Retrieved {} collection entries.", collectionDates.size()); this.updateChannels(collectionDates); - - this.updateStatus(ThingStatus.ONLINE); return true; } @@ -178,7 +179,7 @@ private void updateChannels(final Map collectionDates final CollectionDate collectionDate = collectionDates.get(wasteType); if (collectionDate == null) { - this.logger.warn("No collection dates found for waste type: {}", wasteType); //$NON-NLS-1$ + this.logger.warn("No collection dates found for waste type: {}", wasteType); continue; } diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandlerFactory.java b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandlerFactory.java index 51d32eb15b92a..f11dcd5a006e1 100644 --- a/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandlerFactory.java +++ b/bundles/org.openhab.binding.ahawastecollection/src/main/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandlerFactory.java @@ -62,9 +62,10 @@ public AhaWasteCollectionHandlerFactory(final @Reference CronScheduler scheduler final AhaCollectionScheduleFactory factory = new AhaCollectionScheduleFactory() { @Override - public AhaCollectionScheduleImpl create(final String gemeinde, final String strasse, String hausnr, - String hausnraddon, String ladeort) { - return new AhaCollectionScheduleImpl(gemeinde, strasse, hausnr, hausnraddon, ladeort); + public AhaCollectionScheduleImpl create(final String commune, final String street, + final String houseNumber, final String houseNumberAddon, final String collectionPlace) { + return new AhaCollectionScheduleImpl(commune, street, houseNumber, houseNumberAddon, + collectionPlace); } }; return new AhaWasteCollectionHandler(thing, this.scheduler, this.timeZoneProvider, factory); diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/binding/binding.xml index 8ee3de3ecda7c..752f20958e3a6 100644 --- a/bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/binding/binding.xml +++ b/bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/binding/binding.xml @@ -4,7 +4,10 @@ xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd"> aha WasteCollection Binding - This binding requests the next waste collection dates from the aha collection schedule served by - https://www.aha-region.de/abholtermine/abfuhrkalender. + This binding provides information about the upcoming waste collection dates for places, that are served by + aha, + the waste collection company of the region Hannover. The values are retrieved from the online + aha waste collection + schedule available at: https://www.aha-region.de/abholtermine/abfuhrkalender. diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/thing/thing-types.xml index c6b3f4a2d184f..aa6d38a29045e 100644 --- a/bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/thing/thing-types.xml @@ -19,23 +19,25 @@ - Commune from form input + The selected commune, taken from the form field 'gemeinde'. - Street from selected street value. For example "02095@Oesterleystr.+/+Südstadt@Südstadt" + The selected street, taken from the form field 'strasse'. This value must look like + 67269@Rosmarinweg+/+Kirchhorst@Kirchhorst - - House number from form input + + The selected house number, taken from the form field 'hausnr'. - - + + The selected house number addon, taken from the form field 'hausnraddon'. - - Collection place from form input, for example: "02095-0010+" + + Form value for the collection place, taken from the form field `ladeort`. This value must look like + 67269-0010+ diff --git a/bundles/org.openhab.binding.ahawastecollection/src/test/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionScheduleStubFactory.java b/bundles/org.openhab.binding.ahawastecollection/src/test/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionScheduleStubFactory.java index 69638ec49eadf..2411736b008e2 100644 --- a/bundles/org.openhab.binding.ahawastecollection/src/test/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionScheduleStubFactory.java +++ b/bundles/org.openhab.binding.ahawastecollection/src/test/java/org/openhab/binding/ahawastecollection/internal/AhaCollectionScheduleStubFactory.java @@ -21,8 +21,8 @@ public final class AhaCollectionScheduleStubFactory implements AhaCollectionScheduleFactory { @Override - public AhaCollectionSchedule create(final String gemeinde, final String strasse, final String hausnr, - final String hausnraddon, final String ladeort) { + public AhaCollectionSchedule create(final String commune, final String street, final String houseNumber, + final String houseNumberAddon, final String collectionPlace) { return new AhaCollectionScheduleStub(); } } diff --git a/bundles/org.openhab.binding.ahawastecollection/src/test/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandlerTest.java b/bundles/org.openhab.binding.ahawastecollection/src/test/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandlerTest.java index 16819dcc5434a..b3ed481ad133d 100644 --- a/bundles/org.openhab.binding.ahawastecollection/src/test/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandlerTest.java +++ b/bundles/org.openhab.binding.ahawastecollection/src/test/java/org/openhab/binding/ahawastecollection/internal/AhaWasteCollectionHandlerTest.java @@ -21,6 +21,8 @@ import java.util.Date; import java.util.Map; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -43,11 +45,12 @@ /** * @author Sönke Küper - Initial contribution */ +@NonNullByDefault public class AhaWasteCollectionHandlerTest { - private ThingHandler handler; - private ThingHandlerCallback callback; - private Thing thing; + private @Nullable ThingHandler handler; + private @Nullable ThingHandlerCallback callback; + private @Nullable Thing thing; @BeforeEach public void setUp() { @@ -58,20 +61,7 @@ public void setUp() { config.put("houseNumberAddon", ""); config.put("street", "02095@Oesterleystr.+/+Südstadt@Südstadt"); - this.thing = mock(Thing.class); - when(this.thing.getUID()) - .thenReturn(new ThingUID(AhaWasteCollectionBindingConstants.THING_TYPE_SCHEDULE, "collectionCalendar")); - when(this.thing.getConfiguration()).thenReturn(config); - - final Channel channelBioWaste = mockChannel(this.thing.getUID(), AhaWasteCollectionBindingConstants.BIOWASTE); - final Channel channelGeneralWaste = mockChannel(this.thing.getUID(), - AhaWasteCollectionBindingConstants.GENERAL_WASTE); - final Channel channelPaper = mockChannel(this.thing.getUID(), AhaWasteCollectionBindingConstants.PAPER); - final Channel channelLeightweightPackaging = mockChannel(this.thing.getUID(), - AhaWasteCollectionBindingConstants.LEIGHTWEIGHT_PACKAGING); - - when(this.thing.getChannels()).thenReturn( - Arrays.asList(channelBioWaste, channelGeneralWaste, channelLeightweightPackaging, channelPaper)); + this.thing = mockThing(config); // Stub-Scheduler that executes the command synchronous @SuppressWarnings("unchecked") @@ -100,12 +90,45 @@ public ScheduledCompletableFuture schedule(final SchedulerRunnable runnabl } }; - this.handler = new AhaWasteCollectionHandler(this.thing, scheduler, ZoneId::systemDefault, + this.handler = new AhaWasteCollectionHandler(this.getThing(), scheduler, ZoneId::systemDefault, new AhaCollectionScheduleStubFactory()); this.callback = mock(ThingHandlerCallback.class); this.handler.setCallback(this.callback); } + private static Thing mockThing(final Configuration config) { + final Thing thing = mock(Thing.class); + when(thing.getUID()) + .thenReturn(new ThingUID(AhaWasteCollectionBindingConstants.THING_TYPE_SCHEDULE, "collectionCalendar")); + when(thing.getConfiguration()).thenReturn(config); + + final Channel channelBioWaste = mockChannel(thing.getUID(), AhaWasteCollectionBindingConstants.BIOWASTE); + final Channel channelGeneralWaste = mockChannel(thing.getUID(), + AhaWasteCollectionBindingConstants.GENERAL_WASTE); + final Channel channelPaper = mockChannel(thing.getUID(), AhaWasteCollectionBindingConstants.PAPER); + final Channel channelLeightweightPackaging = mockChannel(thing.getUID(), + AhaWasteCollectionBindingConstants.LEIGHTWEIGHT_PACKAGING); + + when(thing.getChannels()).thenReturn( + Arrays.asList(channelBioWaste, channelGeneralWaste, channelLeightweightPackaging, channelPaper)); + return thing; + } + + private static Channel mockChannel(final ThingUID thingId, final String channelId) { + final Channel channel = Mockito.mock(Channel.class); + when(channel.getUID()).thenReturn(new ChannelUID(thingId, channelId)); + return channel; + } + + // Needed because of NotNullCheck will fail otherwise when using attribute thing in mockito verify. + private Thing getThing() { + if (this.thing != null) { + return this.thing; + } else { + throw new AssertionError(); + } + } + @AfterEach public void tearDown() { this.handler.dispose(); @@ -114,7 +137,7 @@ public void tearDown() { @Test public void testUpdateChannels() { this.handler.initialize(); - verify(this.callback).statusUpdated(eq(this.thing), + verify(this.callback).statusUpdated(eq(this.getThing()), argThat(arg -> arg.getStatus().equals(ThingStatus.UNKNOWN))); verify(this.callback, timeout(1000)).statusUpdated(eq(this.thing), argThat(arg -> arg.getStatus().equals(ThingStatus.ONLINE))); @@ -136,10 +159,4 @@ private static State getDateTime(final Date day) { final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(day.toInstant(), ZoneId.systemDefault()); return new DateTimeType(zonedDateTime); } - - private static Channel mockChannel(final ThingUID thingId, final String channelId) { - final Channel channel = Mockito.mock(Channel.class); - when(channel.getUID()).thenReturn(new ChannelUID(thingId, channelId)); - return channel; - } }