[astro] Add option to force event to occur (#14132)
* fix issue 11424 Signed-off-by: lsiepel <leosiepel@gmail.com>
This commit is contained in:
parent
9001ee7426
commit
15a25db130
|
@ -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.
|
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
|
## Full Example
|
||||||
|
|
||||||
Things:
|
Things:
|
||||||
|
|
|
@ -25,4 +25,5 @@ public class AstroChannelConfig {
|
||||||
public int offset = 0;
|
public int offset = 0;
|
||||||
public @Nullable String earliest;
|
public @Nullable String earliest;
|
||||||
public @Nullable String latest;
|
public @Nullable String latest;
|
||||||
|
public boolean forceEvent = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,25 +114,44 @@ public interface Job extends SchedulerRunnable, Runnable {
|
||||||
* @param channelId the channel ID
|
* @param channelId the channel ID
|
||||||
*/
|
*/
|
||||||
public static void scheduleRange(String thingUID, AstroThingHandler astroHandler, Range range, String channelId) {
|
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);
|
final Channel channel = astroHandler.getThing().getChannel(channelId);
|
||||||
if (channel == null) {
|
if (channel == null) {
|
||||||
LOGGER.warn("Cannot find channel '{}' for thing '{}'.", channelId, astroHandler.getThing().getUID());
|
LOGGER.warn("Cannot find channel '{}' for thing '{}'.", channelId, astroHandler.getThing().getUID());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AstroChannelConfig config = channel.getConfiguration().as(AstroChannelConfig.class);
|
AstroChannelConfig config = channel.getConfiguration().as(AstroChannelConfig.class);
|
||||||
Calendar configStart = truncateToSecond(applyConfig(start, config));
|
Range adjustedRange = adjustRangeToConfig(range, config);
|
||||||
Calendar configEnd = truncateToSecond(applyConfig(end, config));
|
|
||||||
|
|
||||||
scheduleEvent(thingUID, astroHandler, configStart, EVENT_START, channelId, true);
|
Calendar start = adjustedRange.getStart();
|
||||||
scheduleEvent(thingUID, astroHandler, configEnd, EVENT_END, channelId, true);
|
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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -211,6 +211,14 @@ public class DateTimeUtils {
|
||||||
return truncCal1.getTimeInMillis() >= truncCal2.getTimeInMillis();
|
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.
|
* Applies the config to the given calendar.
|
||||||
*/
|
*/
|
||||||
|
@ -223,11 +231,11 @@ public class DateTimeUtils {
|
||||||
cCal = cOffset;
|
cCal = cOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
Calendar cEarliest = adjustTime(cCal, getMinutesFromTime(config.earliest));
|
Calendar cEarliest = getAdjustedEarliest(cCal, config);
|
||||||
if (cCal.before(cEarliest)) {
|
if (cCal.before(cEarliest)) {
|
||||||
return cEarliest;
|
return cEarliest;
|
||||||
}
|
}
|
||||||
Calendar cLatest = adjustTime(cCal, getMinutesFromTime(config.latest));
|
Calendar cLatest = getAdjustedLatest(cCal, config);
|
||||||
if (cCal.after(cLatest)) {
|
if (cCal.after(cLatest)) {
|
||||||
return cLatest;
|
return cLatest;
|
||||||
}
|
}
|
||||||
|
@ -244,6 +252,10 @@ public class DateTimeUtils {
|
||||||
return cal;
|
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.
|
* Parses a HH:MM string and returns the minutes.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -53,6 +53,11 @@
|
||||||
<description>The latest time of the day for the event or the datetime value (hh:mm).</description>
|
<description>The latest time of the day for the event or the datetime value (hh:mm).</description>
|
||||||
<context>time</context>
|
<context>time</context>
|
||||||
</parameter>
|
</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-description:config-descriptions>
|
</config-description:config-descriptions>
|
||||||
|
|
|
@ -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.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.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.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.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
|
channel-type.config.astro.config.offset.label = Offset
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue