Skip to content

Commit

Permalink
[astro] Add option to force event to occur (openhab#14132)
Browse files Browse the repository at this point in the history
* fix issue 11424

Signed-off-by: lsiepel <leosiepel@gmail.com>
  • Loading branch information
lsiepel authored and FordPrfkt committed Apr 19, 2023
1 parent 7de0d52 commit 48c506b
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 14 deletions.
6 changes: 6 additions & 0 deletions bundles/org.openhab.binding.astro/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ public class AstroChannelConfig {
public int offset = 0;
public @Nullable String earliest;
public @Nullable String latest;
public boolean forceEvent = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,25 +114,44 @@ public static void scheduleEvent(String thingUID, AstroThingHandler astroHandler
* @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);

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;
}

scheduleEvent(thingUID, astroHandler, configStart, EVENT_START, channelId, true);
scheduleEvent(thingUID, astroHandler, configEnd, EVENT_END, channelId, true);
return new Range(truncateToSecond(applyConfig(start, config)), truncateToSecond(applyConfig(end, config)));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,14 @@ public static boolean isTimeGreaterEquals(Calendar cal1, Calendar cal2) {
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.
*/
Expand All @@ -223,11 +231,11 @@ public static Calendar applyConfig(Calendar cal, AstroChannelConfig config) {
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;
}
Expand All @@ -244,6 +252,10 @@ private static Calendar adjustTime(Calendar cal, int minutes) {
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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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());
}
}

0 comments on commit 48c506b

Please sign in to comment.