[astro] Add option to force event to occur (#14132)

* fix issue 11424

Signed-off-by: lsiepel <leosiepel@gmail.com>
This commit is contained in:
lsiepel 2023-01-29 22:15:38 +01:00 committed by GitHub
parent 9001ee7426
commit 15a25db130
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 173 additions and 14 deletions

View File

@ -130,6 +130,12 @@ OR
sunset is 22:10 but `latest` is set to 20:00 so the event/datetime value is moved 20:00.
**Force event:** For each trigger channel and `start`, `end` datetime value, you can force the `earliest`, `latest` time of the day, when the event is actually not taking place (e.g. astronomic dawn during summer in Sweden)
e.g `sun#astroDawn earliest=6:00, latest=20:00 forceEvent=true`
astronomic dawn start is null but `earliest` is set to 06:00 so the event/datetime value is set to 06:00.
## Full Example
Things:

View File

@ -25,4 +25,5 @@ public class AstroChannelConfig {
public int offset = 0;
public @Nullable String earliest;
public @Nullable String latest;
public boolean forceEvent = false;
}

View File

@ -114,25 +114,44 @@ public interface Job extends SchedulerRunnable, Runnable {
* @param channelId the channel ID
*/
public static void scheduleRange(String thingUID, AstroThingHandler astroHandler, Range range, String channelId) {
Calendar start = range.getStart();
Calendar end = range.getEnd();
// depending on the location you might not have a valid range for day/night, so skip the events:
if (start == null || end == null) {
return;
}
final Channel channel = astroHandler.getThing().getChannel(channelId);
if (channel == null) {
LOGGER.warn("Cannot find channel '{}' for thing '{}'.", channelId, astroHandler.getThing().getUID());
return;
}
AstroChannelConfig config = channel.getConfiguration().as(AstroChannelConfig.class);
Calendar configStart = truncateToSecond(applyConfig(start, config));
Calendar configEnd = truncateToSecond(applyConfig(end, config));
Range adjustedRange = adjustRangeToConfig(range, config);
scheduleEvent(thingUID, astroHandler, configStart, EVENT_START, channelId, true);
scheduleEvent(thingUID, astroHandler, configEnd, EVENT_END, channelId, true);
Calendar start = adjustedRange.getStart();
Calendar end = adjustedRange.getEnd();
if (start == null || end == null) {
LOGGER.debug("event was not scheduled as either start or end was null");
return;
}
scheduleEvent(thingUID, astroHandler, start, EVENT_START, channelId, true);
scheduleEvent(thingUID, astroHandler, end, EVENT_END, channelId, true);
}
public static Range adjustRangeToConfig(Range range, AstroChannelConfig config) {
Calendar start = range.getStart();
Calendar end = range.getEnd();
if (config.forceEvent && start == null) {
start = getAdjustedEarliest(Calendar.getInstance(), config);
}
if (config.forceEvent && end == null) {
end = getAdjustedLatest(Calendar.getInstance(), config);
}
// depending on the location and configuration you might not have a valid range for day/night, so skip the
// events:
if (start == null || end == null) {
return range;
}
return new Range(truncateToSecond(applyConfig(start, config)), truncateToSecond(applyConfig(end, config)));
}
/**

View File

@ -211,6 +211,14 @@ public class DateTimeUtils {
return truncCal1.getTimeInMillis() >= truncCal2.getTimeInMillis();
}
public static Calendar getAdjustedEarliest(Calendar cal, AstroChannelConfig config) {
return adjustTime(cal, getMinutesFromTime(config.earliest));
}
public static Calendar getAdjustedLatest(Calendar cal, AstroChannelConfig config) {
return adjustTime(cal, getMinutesFromTime(config.latest));
}
/**
* Applies the config to the given calendar.
*/
@ -223,11 +231,11 @@ public class DateTimeUtils {
cCal = cOffset;
}
Calendar cEarliest = adjustTime(cCal, getMinutesFromTime(config.earliest));
Calendar cEarliest = getAdjustedEarliest(cCal, config);
if (cCal.before(cEarliest)) {
return cEarliest;
}
Calendar cLatest = adjustTime(cCal, getMinutesFromTime(config.latest));
Calendar cLatest = getAdjustedLatest(cCal, config);
if (cCal.after(cLatest)) {
return cLatest;
}
@ -244,6 +252,10 @@ public class DateTimeUtils {
return cal;
}
public static Calendar createCalendarForToday(int hour, int minute) {
return DateTimeUtils.adjustTime(Calendar.getInstance(), hour * 60 + minute);
}
/**
* Parses a HH:MM string and returns the minutes.
*/

View File

@ -53,6 +53,11 @@
<description>The latest time of the day for the event or the datetime value (hh:mm).</description>
<context>time</context>
</parameter>
<parameter name="forceEvent" type="boolean">
<label>Force Event</label>
<description>Force event to occur according to Earliest/Latest, even when the event doesn't exist (null)</description>
<default>false</default>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@ -217,6 +217,8 @@ channel-type.astro.winter.state.pattern = %1$tF %1$tR
channel-type.config.astro.config.earliest.label = Earliest
channel-type.config.astro.config.earliest.description = The earliest time of the day for the event or the datetime value (hh:mm).
channel-type.config.astro.config.forceEvent.label = Force Event
channel-type.config.astro.config.forceEvent.description = Force event to occur according to Earliest/Latest, even when the event doesn't exist (null)
channel-type.config.astro.config.latest.label = Latest
channel-type.config.astro.config.latest.description = The latest time of the day for the event or the datetime value (hh:mm).
channel-type.config.astro.config.offset.label = Offset

View File

@ -0,0 +1,114 @@
/**
* Copyright (c) 2010-2023 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.astro.internal.job;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Calendar;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openhab.binding.astro.internal.config.AstroChannelConfig;
import org.openhab.binding.astro.internal.model.Range;
import org.openhab.binding.astro.internal.util.DateTimeUtils;
/**
* Test class for {@link Job}.
*
* @author Leo Siepel - Initial contribution
*/
@NonNullByDefault
public class JobTest {
@BeforeEach
public void init() {
}
@Test
public void adjustRangeToConfigForceTest() {
// arrange
AstroChannelConfig config = new AstroChannelConfig();
config.earliest = "08:00";
config.latest = "22:00";
config.forceEvent = true;
Calendar pointInTime = DateTimeUtils.createCalendarForToday(12, 0);
Range startNull = new Range(null, pointInTime);
Range endNull = new Range(pointInTime, null);
Range bothNull = new Range(null, null);
Range bothNNShouldCorrect = new Range(DateTimeUtils.createCalendarForToday(6, 0),
DateTimeUtils.createCalendarForToday(22, 0));
Range bothNNShouldNotCorrect = new Range(pointInTime, pointInTime);
// act
Range startNullResult = Job.adjustRangeToConfig(startNull, config);
Range endNullResult = Job.adjustRangeToConfig(endNull, config);
Range bothNullResult = Job.adjustRangeToConfig(bothNull, config);
Range bothNNShouldCorrectResult = Job.adjustRangeToConfig(bothNNShouldCorrect, config);
Range bothNNSouldNotCorrectResult = Job.adjustRangeToConfig(bothNNShouldNotCorrect, config);
Calendar fixedStart = DateTimeUtils.getAdjustedEarliest(pointInTime, config);
Calendar fixdedEnd = DateTimeUtils.getAdjustedLatest(pointInTime, config);
// assert
assertEquals(fixedStart.getTime(), startNullResult.getStart().getTime());
assertEquals(pointInTime.getTime(), startNullResult.getEnd().getTime());
assertEquals(pointInTime, endNullResult.getStart());
assertEquals(fixdedEnd, endNullResult.getEnd());
assertEquals(fixedStart, bothNullResult.getStart());
assertEquals(fixdedEnd, bothNullResult.getEnd());
assertEquals(fixedStart, bothNNShouldCorrectResult.getStart());
assertEquals(fixdedEnd, bothNNShouldCorrectResult.getEnd());
assertEquals(pointInTime, bothNNSouldNotCorrectResult.getStart());
assertEquals(pointInTime, bothNNSouldNotCorrectResult.getEnd());
}
@Test
public void adjustRangeToConfigTestSkipForceTest() {
// arrange
AstroChannelConfig config = new AstroChannelConfig();
config.earliest = "08:00";
config.latest = "22:00";
config.forceEvent = false;
Calendar pointInTime = DateTimeUtils.createCalendarForToday(12, 0);
Range startNull = new Range(null, pointInTime);
Range endNull = new Range(pointInTime, null);
Range bothNull = new Range(null, null);
Range bothNNShouldCorrect = new Range(DateTimeUtils.createCalendarForToday(6, 0),
DateTimeUtils.createCalendarForToday(22, 0));
Range bothNNShouldNotCorrect = new Range(pointInTime, pointInTime);
// act
Range startNullResult = Job.adjustRangeToConfig(startNull, config);
Range endNullResult = Job.adjustRangeToConfig(endNull, config);
Range bothNullResult = Job.adjustRangeToConfig(bothNull, config);
Range bothNNShouldCorrectResult = Job.adjustRangeToConfig(bothNNShouldCorrect, config);
Range bothNNSouldNotCorrectResult = Job.adjustRangeToConfig(bothNNShouldNotCorrect, config);
Calendar fixedStart = DateTimeUtils.getAdjustedEarliest(pointInTime, config);
Calendar fixdedEnd = DateTimeUtils.getAdjustedLatest(pointInTime, config);
// assert
assertEquals(null, startNullResult.getStart());
assertEquals(pointInTime, startNullResult.getEnd());
assertEquals(pointInTime, endNullResult.getStart());
assertEquals(null, endNullResult.getEnd());
assertEquals(null, bothNullResult.getStart());
assertEquals(null, bothNullResult.getEnd());
assertEquals(fixedStart, bothNNShouldCorrectResult.getStart());
assertEquals(fixdedEnd, bothNNShouldCorrectResult.getEnd());
assertEquals(pointInTime, bothNNSouldNotCorrectResult.getStart());
assertEquals(pointInTime, bothNNSouldNotCorrectResult.getEnd());
}
}