diff --git a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java index 632a818f3..8dbf05d4c 100644 --- a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java +++ b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java @@ -65,6 +65,7 @@ import org.slf4j.LoggerFactory; * @author Michael Wodniok - Initial contribution * @author Andrew Fiddian-Green - Support for Command Tags embedded in the Event description * @author Michael Wodniok - Added last_update-channel and additional needed handling of it + * @author Michael Wodniok - Changed calculation of Future for refresh of channels */ @NonNullByDefault public class ICalendarHandler extends BaseBridgeHandler implements CalendarUpdateListener { @@ -337,6 +338,7 @@ public class ICalendarHandler extends BaseBridgeHandler implements CalendarUpdat return; } final Instant now = Instant.now(); + Instant nextRegularUpdate = null; if (currentCalendar.isEventPresent(now)) { final Event currentEvent = currentCalendar.getCurrentEvent(now); if (currentEvent == null) { @@ -344,32 +346,33 @@ public class ICalendarHandler extends BaseBridgeHandler implements CalendarUpdat "Could not schedule next update of states, due to unexpected behaviour of calendar implementation."); return; } + nextRegularUpdate = currentEvent.end; + } + + final Event nextEvent = currentCalendar.getNextEvent(now); + final ICalendarConfiguration currentConfig = this.configuration; + if (currentConfig == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "Something is broken, the configuration is not available."); + return; + } + if (nextEvent != null) { + if (nextRegularUpdate == null || nextEvent.start.isBefore(nextRegularUpdate)) { + nextRegularUpdate = nextEvent.start; + } + } + + if (nextRegularUpdate != null) { updateJobFuture = scheduler.schedule(() -> { ICalendarHandler.this.updateStates(); ICalendarHandler.this.rescheduleCalendarStateUpdate(); - }, currentEvent.end.getEpochSecond() - now.getEpochSecond(), TimeUnit.SECONDS); - logger.debug("Scheduled update in {} seconds", currentEvent.end.getEpochSecond() - now.getEpochSecond()); + }, nextRegularUpdate.getEpochSecond() - now.getEpochSecond(), TimeUnit.SECONDS); + logger.debug("Scheduled update in {} seconds", nextRegularUpdate.getEpochSecond() - now.getEpochSecond()); } else { - final Event nextEvent = currentCalendar.getNextEvent(now); - final ICalendarConfiguration currentConfig = this.configuration; - if (currentConfig == null) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "Something is broken, the configuration is not available."); - return; - } - if (nextEvent == null) { - updateJobFuture = scheduler.schedule(() -> { - ICalendarHandler.this.rescheduleCalendarStateUpdate(); - }, 1L, TimeUnit.DAYS); - logger.debug("Scheduled reschedule in 1 day"); - } else { - updateJobFuture = scheduler.schedule(() -> { - ICalendarHandler.this.updateStates(); - ICalendarHandler.this.rescheduleCalendarStateUpdate(); - }, nextEvent.start.getEpochSecond() - now.getEpochSecond(), TimeUnit.SECONDS); - logger.debug("Scheduled update in {} seconds", nextEvent.start.getEpochSecond() - now.getEpochSecond()); - - } + updateJobFuture = scheduler.schedule(() -> { + ICalendarHandler.this.rescheduleCalendarStateUpdate(); + }, 1L, TimeUnit.DAYS); + logger.debug("Scheduled reschedule in 1 day"); } } diff --git a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java index 4f6d23edb..61d2f9a25 100644 --- a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java +++ b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java @@ -59,6 +59,8 @@ import biweekly.util.com.google.ical.compat.javautil.DateIterator; * @author Andrew Fiddian-Green - Methods getJustBegunEvents() & getJustEndedEvents() * @author Michael Wodniok - Extension for filtered events * @author Michael Wodniok - Added logic for events moved with "RECURRENCE-ID" (issue 9647) + * @author Michael Wodniok - Extended logic for defined behavior with parallel current events + * (issue 10808) */ @NonNullByDefault class BiweeklyPresentableCalendar extends AbstractPresentableCalendar { @@ -320,6 +322,8 @@ class BiweeklyPresentableCalendar extends AbstractPresentableCalendar { final List positiveEvents = new ArrayList(); classifyEvents(positiveEvents, negativeEvents); + VEventWPeriod earliestEndingEvent = null; + for (final VEvent currentEvent : positiveEvents) { final DateIterator startDates = this.getRecurredEventDateIterator(currentEvent); final Duration duration = getEventLength(currentEvent); @@ -333,7 +337,9 @@ class BiweeklyPresentableCalendar extends AbstractPresentableCalendar { if (startInstant.isBefore(instant) && endInstant.isAfter(instant)) { final Uid eventUid = currentEvent.getUid(); if (eventUid == null || !isCounteredBy(startInstant, eventUid, negativeEvents)) { - return new VEventWPeriod(currentEvent, startInstant, endInstant); + if (earliestEndingEvent == null || endInstant.isBefore(earliestEndingEvent.end)) { + earliestEndingEvent = new VEventWPeriod(currentEvent, startInstant, endInstant); + } } } if (startInstant.isAfter(instant.plus(duration))) { @@ -342,7 +348,7 @@ class BiweeklyPresentableCalendar extends AbstractPresentableCalendar { } } - return null; + return earliestEndingEvent; } /** diff --git a/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java b/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java index 7bdb0e397..7c60c4fb6 100644 --- a/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java +++ b/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java @@ -41,13 +41,14 @@ import org.openhab.core.types.Command; * @author Michael Wodniok - Initial contribution. * @author Andrew Fiddian-Green - Tests for Command Tag code * @author Michael Wodniok - Extended Tests for filtered Events - * + * @author Michael Wodniok - Extended Test for parallel current events */ public class BiweeklyPresentableCalendarTest { private AbstractPresentableCalendar calendar; private AbstractPresentableCalendar calendar2; private AbstractPresentableCalendar calendar3; private AbstractPresentableCalendar calendar_issue9647; + private AbstractPresentableCalendar calendar_issue10808; @BeforeEach public void setUp() throws IOException, CalendarException { @@ -56,6 +57,8 @@ public class BiweeklyPresentableCalendarTest { calendar3 = new BiweeklyPresentableCalendar(new FileInputStream("src/test/resources/test3.ics")); calendar_issue9647 = new BiweeklyPresentableCalendar( new FileInputStream("src/test/resources/test-issue9647.ics")); + calendar_issue10808 = new BiweeklyPresentableCalendar( + new FileInputStream("src/test/resources/test-issue10808.ics")); } /** @@ -117,6 +120,18 @@ public class BiweeklyPresentableCalendarTest { Event nonExistingEvent = calendar.getCurrentEvent(Instant.parse("2019-09-09T09:07:00Z")); assertNull(nonExistingEvent); + + Event currentEvent2 = calendar_issue10808.getCurrentEvent(Instant.parse("2021-06-05T17:10:05Z")); + assertNotNull(currentEvent2); + assertTrue("Test event 1".contentEquals(currentEvent2.title)); + + Event currentEvent3 = calendar_issue10808.getCurrentEvent(Instant.parse("2021-06-05T17:13:05Z")); + assertNotNull(currentEvent3); + assertTrue("Test event 2".contentEquals(currentEvent3.title)); + + Event currentEvent4 = calendar_issue10808.getCurrentEvent(Instant.parse("2021-06-05T17:18:05Z")); + assertNotNull(currentEvent4); + assertTrue("Test event 1".contentEquals(currentEvent4.title)); } /** diff --git a/bundles/org.openhab.binding.icalendar/src/test/resources/test-issue10808.ics b/bundles/org.openhab.binding.icalendar/src/test/resources/test-issue10808.ics new file mode 100644 index 000000000..baadc321b --- /dev/null +++ b/bundles/org.openhab.binding.icalendar/src/test/resources/test-issue10808.ics @@ -0,0 +1,47 @@ +BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +PRODID:-//SabreDAV//SabreDAV//EN +X-WR-CALNAME:Test +X-APPLE-CALENDAR-COLOR:#499AA2 +REFRESH-INTERVAL;VALUE=DURATION:PT4H +X-PUBLISHED-TTL:PT4H +BEGIN:VTIMEZONE +TZID:Europe/Paris +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +CREATED:20210107T155730Z +DTSTAMP:20210107T160226Z +LAST-MODIFIED:20210605T163408Z +SEQUENCE:4 +UID:bd676ec9-0cdb-4c8d-a6dd-9e3fcf77a45f +DTSTART;TZID=Europe/Paris:20210605T191000 +DTEND;TZID=Europe/Paris:20210605T192000 +SUMMARY:Test event 1 +DESCRIPTION:BEGIN:DemoString:EHLO1 +END:VEVENT +BEGIN:VEVENT +CREATED:20210107T160405Z +DTSTAMP:20210107T160405Z +LAST-MODIFIED:20210605T163512Z +UID:7d1ecca5-1ddd-4932-b096-d034c8d7f5aa +DTSTART;TZID=Europe/Paris:20210605T191200 +DTEND;TZID=Europe/Paris:20210605T191600 +SUMMARY:Test event 2 +DESCRIPTION:BEGIN:DemoString:EHLO2 +END:VEVENT +END:VCALENDAR