Implemented fuzzy-shift for Scheduler

This commit is contained in:
Patrick Haßel 2021-10-04 10:37:06 +02:00
parent caa7e55d10
commit 36ee78783c
9 changed files with 151 additions and 71 deletions

View File

@ -1,6 +1,7 @@
package de.ph87.homeautomation; package de.ph87.homeautomation;
import com.luckycatlabs.sunrisesunset.Zenith; import com.luckycatlabs.sunrisesunset.Zenith;
import de.ph87.homeautomation.knx.group.KnxGroupDto;
import de.ph87.homeautomation.knx.group.KnxGroupRepository; import de.ph87.homeautomation.knx.group.KnxGroupRepository;
import de.ph87.homeautomation.knx.group.KnxGroupWriteService; import de.ph87.homeautomation.knx.group.KnxGroupWriteService;
import de.ph87.homeautomation.schedule.PropertyEntry; import de.ph87.homeautomation.schedule.PropertyEntry;
@ -18,20 +19,13 @@ import java.time.ZonedDateTime;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
@SuppressWarnings({"unchecked", "UnusedReturnValue", "SameParameterValue", "UnusedAssignment"})
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class DemoDataService { public class DemoDataService {
private static final GroupAddress WOHNZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS = new GroupAddress(0, 4, 24); public static final int MIN30_SEC = 30 * 60;
private static final GroupAddress SCHLAFZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS = new GroupAddress(0, 3, 3);
private static final GroupAddress FLUR_ROLLLADEN_POSITION_ANFAHREN_ADDRESS = new GroupAddress(0, 5, 13);
private static final GroupAddress BADEWANNE_SCHALTEN = new GroupAddress(781);
private static final GroupAddress BADEWANNE_STATUS = new GroupAddress(782);
private final KnxGroupWriteService knxGroupWriteService; private final KnxGroupWriteService knxGroupWriteService;
@ -41,64 +35,86 @@ public class DemoDataService {
@PostConstruct @PostConstruct
public void postConstruct() { public void postConstruct() {
createKnxGroupIfNotExists("Wohnzimmer Rollladen Position Anfahren", WOHNZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "5.001", false); final KnxGroupDto eg_ambiente_schalten = createKnxGroupIfNotExists("EG Ambiente Schalten", 848, "1.001", false);
createKnxGroupIfNotExists("Schlafzimmer Rollladen Position Anfahren", SCHLAFZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "5.001", false); final KnxGroupDto og_ambiente_schalten = createKnxGroupIfNotExists("OG Ambiente Schalten", 1539, "1.001", false);
createKnxGroupIfNotExists("Flur Rollladen Position Anfahren", FLUR_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "5.001", false); final KnxGroupDto wohnzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Wohnzimmer Rollladen Position Anfahren", new GroupAddress(0, 4, 24), "5.001", false);
createKnxGroupIfNotExists("Badewanne Schalten", BADEWANNE_SCHALTEN, "1.001", false); final KnxGroupDto schlafzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Schlafzimmer Rollladen Position Anfahren", new GroupAddress(0, 3, 3), "5.001", false);
createKnxGroupIfNotExists("Badewanne Status", BADEWANNE_STATUS, "1.001", true); final KnxGroupDto flur_rollladen_position_anfahren = createKnxGroupIfNotExists("Flur Rollladen Position Anfahren", new GroupAddress(0, 5, 13), "5.001", false);
final KnxGroupDto badewanne_schalten = createKnxGroupIfNotExists("Badewanne Schalten", new GroupAddress(781), "1.001", false);
final KnxGroupDto badewanne_status = createKnxGroupIfNotExists("Badewanne Status", new GroupAddress(782), "1.001", true);
final Schedule wohnzimmer = new Schedule(); final Schedule scheduleEgAmbiente = new Schedule();
wohnzimmer.setName("Rollläden Wohnzimmer"); scheduleEgAmbiente.setName("EG Ambiente");
createSunrise(wohnzimmer, Zenith.OFFICIAL, new PropertyEntry(WOHNZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "0")); createTime(scheduleEgAmbiente, 7, 15, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten.getAddress(), "true"));
createSunset(wohnzimmer, Zenith.OFFICIAL, new PropertyEntry(WOHNZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "100")); createTime(scheduleEgAmbiente, 9, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten.getAddress(), "false"));
scheduleRepository.save(wohnzimmer); createSunset(scheduleEgAmbiente, Zenith.OFFICIAL, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten.getAddress(), "true"));
createSunset(scheduleEgAmbiente, Zenith.ASTRONOMICAL, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten.getAddress(), "false"));
scheduleRepository.save(scheduleEgAmbiente);
final Schedule schlafzimmer = new Schedule(); final Schedule scheduleOgAmbiente = new Schedule();
schlafzimmer.setName("Rollläden Schlafzimmer"); scheduleOgAmbiente.setName("OG Ambiente");
createTime(schlafzimmer, 7, 0, 0, new PropertyEntry(SCHLAFZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "0")); createTime(scheduleOgAmbiente, 7, 15, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(og_ambiente_schalten.getAddress(), "true"));
createTime(schlafzimmer, 20, 0, 0, new PropertyEntry(SCHLAFZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "100")); createTime(scheduleOgAmbiente, 9, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(og_ambiente_schalten.getAddress(), "false"));
scheduleRepository.save(schlafzimmer); createSunset(scheduleOgAmbiente, Zenith.OFFICIAL, MIN30_SEC, MIN30_SEC, new PropertyEntry(og_ambiente_schalten.getAddress(), "true"));
createSunset(scheduleOgAmbiente, Zenith.ASTRONOMICAL, MIN30_SEC, MIN30_SEC, new PropertyEntry(og_ambiente_schalten.getAddress(), "false"));
scheduleRepository.save(scheduleOgAmbiente);
final Schedule flur = new Schedule(); final Schedule scheduleWohnzimmerRollladen = new Schedule();
flur.setName("Rollläden Flur"); scheduleWohnzimmerRollladen.setName("Rollläden Wohnzimmer");
createSunrise(flur, Zenith.NAUTICAL, new PropertyEntry(FLUR_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "0")); createSunrise(scheduleWohnzimmerRollladen, Zenith.OFFICIAL, 0, 0, new PropertyEntry(wohnzimmer_rollladen_position_anfahren.getAddress(), "0"));
createSunset(flur, Zenith.NAUTICAL, new PropertyEntry(FLUR_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "100")); createSunset(scheduleWohnzimmerRollladen, Zenith.OFFICIAL, 0, 0, new PropertyEntry(wohnzimmer_rollladen_position_anfahren.getAddress(), "100"));
scheduleRepository.save(flur); scheduleRepository.save(scheduleWohnzimmerRollladen);
final Schedule badewanne = new Schedule(); final Schedule scheduleSchlafzimmerRollladen = new Schedule();
badewanne.setName("Badewanne"); scheduleSchlafzimmerRollladen.setName("Rollläden Schlafzimmer");
int seconds = 2; createTime(scheduleSchlafzimmerRollladen, 7, 0, 0, 0, 0, new PropertyEntry(schlafzimmer_rollladen_position_anfahren.getAddress(), "0"));
createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "true")); createTime(scheduleSchlafzimmerRollladen, 20, 0, 0, 0, 0, new PropertyEntry(schlafzimmer_rollladen_position_anfahren.getAddress(), "100"));
createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "false")); scheduleRepository.save(scheduleSchlafzimmerRollladen);
createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "true"));
createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "false")); final Schedule scheduleFlurRollladen = new Schedule();
scheduleRepository.save(badewanne); scheduleFlurRollladen.setName("Rollläden Flur");
createSunrise(scheduleFlurRollladen, Zenith.NAUTICAL, 0, 0, new PropertyEntry(flur_rollladen_position_anfahren.getAddress(), "0"));
createSunset(scheduleFlurRollladen, Zenith.NAUTICAL, 0, 0, new PropertyEntry(flur_rollladen_position_anfahren.getAddress(), "100"));
scheduleRepository.save(scheduleFlurRollladen);
final Schedule scheduleBadewanneBlinken = new Schedule();
scheduleBadewanneBlinken.setName("Badewanne");
final int interval = 2;
final int fuzzy = 0;
int seconds = interval;
createRelative(scheduleBadewanneBlinken, seconds += interval, fuzzy, fuzzy, new PropertyEntry(badewanne_schalten.getAddress(), "true"));
createRelative(scheduleBadewanneBlinken, seconds += interval, fuzzy, fuzzy, new PropertyEntry(badewanne_schalten.getAddress(), "false"));
createRelative(scheduleBadewanneBlinken, seconds += interval, fuzzy, fuzzy, new PropertyEntry(badewanne_schalten.getAddress(), "true"));
createRelative(scheduleBadewanneBlinken, seconds += interval, fuzzy, fuzzy, new PropertyEntry(badewanne_schalten.getAddress(), "false"));
scheduleRepository.save(scheduleBadewanneBlinken);
} }
private void createKnxGroupIfNotExists(final String name, final GroupAddress address, final String dpt, final boolean readable) { private KnxGroupDto createKnxGroupIfNotExists(final String name, final int address, final String dpt, final boolean readable) {
if (!knxGroupRepository.existsByAddressRaw(address.getRawAddress())) { return createKnxGroupIfNotExists(name, new GroupAddress(address), dpt, readable);
knxGroupWriteService.create(name, address, dpt, readable);
}
} }
private ScheduleEntry createRelative(final Schedule schedule, final int inSeconds, final Map.Entry<String, String>... entries) { private KnxGroupDto createKnxGroupIfNotExists(final String name, final GroupAddress address, final String dpt, final boolean readable) {
return knxGroupRepository.findByAddressRaw(address.getRawAddress()).map(KnxGroupDto::new).orElseGet(() -> knxGroupWriteService.create(name, address, dpt, readable));
}
private ScheduleEntry createRelative(final Schedule schedule, final int inSeconds, final int fuzzyMinusSeconds, final int fuzzyPlusSeconds, final Map.Entry<String, String>... entries) {
final ZonedDateTime now = ZonedDateTime.now().plusSeconds(inSeconds).withNano(0); final ZonedDateTime now = ZonedDateTime.now().plusSeconds(inSeconds).withNano(0);
return create(schedule, ScheduleEntryType.TIME, null, now.getHour(), now.getMinute(), now.getSecond(), entries); return create(schedule, ScheduleEntryType.TIME, null, now.getHour(), now.getMinute(), now.getSecond(), fuzzyMinusSeconds, fuzzyPlusSeconds, entries);
} }
private ScheduleEntry createTime(final Schedule schedule, final int hour, final int minute, final int second, final Map.Entry<String, String>... entries) { private ScheduleEntry createTime(final Schedule schedule, final int hour, final int minute, final int second, final int fuzzyMinusSeconds, final int fuzzyPlusSeconds, final Map.Entry<String, String>... entries) {
return create(schedule, ScheduleEntryType.TIME, null, hour, minute, second, entries); return create(schedule, ScheduleEntryType.TIME, null, hour, minute, second, fuzzyMinusSeconds, fuzzyPlusSeconds, entries);
} }
private ScheduleEntry createSunrise(final Schedule schedule, final Zenith zenith, final Map.Entry<String, String>... entries) { private ScheduleEntry createSunrise(final Schedule schedule, final Zenith zenith, final int fuzzyMinusSeconds, final int fuzzyPlusSeconds, final Map.Entry<String, String>... entries) {
return create(schedule, ScheduleEntryType.SUNRISE, zenith, 0, 0, 0, entries); return create(schedule, ScheduleEntryType.SUNRISE, zenith, 0, 0, 0, fuzzyMinusSeconds, fuzzyPlusSeconds, entries);
} }
private ScheduleEntry createSunset(final Schedule schedule, final Zenith zenith, final Map.Entry<String, String>... entries) { private ScheduleEntry createSunset(final Schedule schedule, final Zenith zenith, final int fuzzyMinusSeconds, final int fuzzyPlusSeconds, final Map.Entry<String, String>... entries) {
return create(schedule, ScheduleEntryType.SUNSET, zenith, 0, 0, 0, entries); return create(schedule, ScheduleEntryType.SUNSET, zenith, 0, 0, 0, fuzzyMinusSeconds, fuzzyPlusSeconds, entries);
} }
private ScheduleEntry create(final Schedule schedule, final ScheduleEntryType type, final Zenith zenith, final int hour, final int minute, final int second, final Map.Entry<String, String>... entries) { private ScheduleEntry create(final Schedule schedule, final ScheduleEntryType type, final Zenith zenith, final int hour, final int minute, final int second, final int fuzzyMinusSeconds, final int fuzzyPlusSeconds, final Map.Entry<String, String>... entries) {
final ScheduleEntry entry = new ScheduleEntry(); final ScheduleEntry entry = new ScheduleEntry();
entry.setType(type); entry.setType(type);
if (zenith != null) { if (zenith != null) {
@ -107,6 +123,8 @@ public class DemoDataService {
entry.setHour(hour); entry.setHour(hour);
entry.setMinute(minute); entry.setMinute(minute);
entry.setSecond(second); entry.setSecond(second);
entry.setFuzzyMinusSeconds(fuzzyMinusSeconds);
entry.setFuzzyPlusSeconds(fuzzyPlusSeconds);
Arrays.stream(entries).forEach(p -> entry.getProperties().put(p.getKey(), p.getValue())); Arrays.stream(entries).forEach(p -> entry.getProperties().put(p.getKey(), p.getValue()));
schedule.getEntries().add(entry); schedule.getEntries().add(entry);
return entry; return entry;

View File

@ -0,0 +1,43 @@
package de.ph87.homeautomation.knx.group;
import lombok.Data;
import tuwien.auto.calimero.GroupAddress;
import java.math.BigDecimal;
import java.time.ZonedDateTime;
@Data
public class KnxGroupDto {
public final long id;
public final int addressRaw;
public final String addressStr;
public final String dpt;
public final String name;
public final Boolean booleanValue;
public final BigDecimal numberValue;
public final ZonedDateTime valueTimestamp;
public KnxGroupDto(final KnxGroup knxGroup) {
id = knxGroup.getId();
addressRaw = knxGroup.getAddressRaw();
addressStr = knxGroup.getAddressStr();
dpt = knxGroup.getDpt();
name = knxGroup.getName();
booleanValue = knxGroup.getBooleanValue();
numberValue = knxGroup.getNumberValue();
valueTimestamp = knxGroup.getValueTimestamp();
}
public GroupAddress getAddress() {
return new GroupAddress(addressRaw);
}
}

View File

@ -53,13 +53,13 @@ public class KnxGroupWriteService {
knxGroupRepository.findAllByRead_AbleTrue().forEach(knxGroup -> knxGroup.getRead().setNextTimestamp(ZonedDateTime.now())); knxGroupRepository.findAllByRead_AbleTrue().forEach(knxGroup -> knxGroup.getRead().setNextTimestamp(ZonedDateTime.now()));
} }
public void create(final String name, final GroupAddress address, final String dpt, final boolean readable) { public KnxGroupDto create(final String name, final GroupAddress address, final String dpt, final boolean readable) {
final KnxGroup trans = new KnxGroup(); final KnxGroup trans = new KnxGroup();
trans.setAddress(address); trans.setAddress(address);
trans.setDpt(dpt); trans.setDpt(dpt);
trans.setName(name); trans.setName(name);
trans.getRead().setAble(readable); trans.getRead().setAble(readable);
knxGroupRepository.save(trans); return new KnxGroupDto(knxGroupRepository.save(trans));
} }
public boolean setSendValue(final GroupAddress groupAddress, final String value) throws KnxGroupFormatException { public boolean setSendValue(final GroupAddress groupAddress, final String value) throws KnxGroupFormatException {

View File

@ -17,11 +17,6 @@ public class PropertyEntry implements Map.Entry<String, String> {
this.value = value; this.value = value;
} }
public PropertyEntry(final String propertyName, final String value) {
this.key = propertyName;
this.value = value;
}
public String setValue(final String value) { public String setValue(final String value) {
this.value = value; this.value = value;
return value; return value;

View File

@ -45,14 +45,14 @@ public class ScheduleController {
private ScheduleEntryNextDto(final Schedule schedule, final ScheduleEntry entry) { private ScheduleEntryNextDto(final Schedule schedule, final ScheduleEntry entry) {
this.name = schedule.getName(); this.name = schedule.getName();
this.nextTimestamp = entry.getNextDateTime(); this.nextTimestamp = entry.getNextFuzzyTimestamp();
this.properties = new HashMap<>(entry.getProperties()); this.properties = new HashMap<>(entry.getProperties());
} }
public static Optional<ScheduleEntryNextDto> create(final Schedule schedule, final ZonedDateTime now) { public static Optional<ScheduleEntryNextDto> create(final Schedule schedule, final ZonedDateTime now) {
return schedule.getEntries().stream() return schedule.getEntries().stream()
.filter(entry -> entry.getNextDateTime() != null && entry.getNextDateTime().isAfter(now)) .filter(entry -> entry.getNextFuzzyTimestamp() != null && entry.getNextFuzzyTimestamp().isAfter(now))
.min(Comparator.comparing(ScheduleEntry::getNextDateTime)) .min(Comparator.comparing(ScheduleEntry::getNextFuzzyTimestamp))
.map(scheduleEntry -> new ScheduleEntryNextDto(schedule, scheduleEntry)); .map(scheduleEntry -> new ScheduleEntryNextDto(schedule, scheduleEntry));
} }

View File

@ -49,9 +49,10 @@ public class ScheduleWriteService {
private void executeLastDue(final Schedule schedule, final ZonedDateTime now) { private void executeLastDue(final Schedule schedule, final ZonedDateTime now) {
schedule.getEntries().stream() schedule.getEntries().stream()
.filter(entry -> entry.getNextDateTime() != null && !entry.getNextDateTime().isAfter(now)) .filter(entry -> entry.getNextFuzzyTimestamp() != null && !entry.getNextFuzzyTimestamp().isAfter(now))
.max(Comparator.comparing(ScheduleEntry::getNextDateTime)) .max(Comparator.comparing(ScheduleEntry::getNextFuzzyTimestamp))
.ifPresent(entry -> { .ifPresent(entry -> {
entry.setLastClearTimestamp(entry.getNextClearTimestamp());
log.info("Executing ScheduleEntry {}", entry); log.info("Executing ScheduleEntry {}", entry);
entry.getProperties().forEach(this::applyPropertyMapEntry); entry.getProperties().forEach(this::applyPropertyMapEntry);
calculateSchedule(schedule, now); calculateSchedule(schedule, now);
@ -69,15 +70,15 @@ public class ScheduleWriteService {
private void calculateSchedule(final Schedule schedule, final ZonedDateTime now) { private void calculateSchedule(final Schedule schedule, final ZonedDateTime now) {
schedule.getEntries().forEach(scheduleEntry -> calculateEntry(schedule, scheduleEntry, now)); schedule.getEntries().forEach(scheduleEntry -> calculateEntry(schedule, scheduleEntry, now));
schedule.getEntries().stream() schedule.getEntries().stream()
.filter(entry -> entry.getNextDateTime() != null && entry.getNextDateTime().isAfter(now)) .filter(entry -> entry.getNextFuzzyTimestamp() != null && entry.getNextFuzzyTimestamp().isAfter(now))
.min(Comparator.comparing(ScheduleEntry::getNextDateTime)) .min(Comparator.comparing(ScheduleEntry::getNextFuzzyTimestamp))
.ifPresent(scheduleEntry -> log.info("Next schedule for \"{}\": {}", schedule.getName(), scheduleEntry.getNextDateTime())); .ifPresent(scheduleEntry -> log.info("Next schedule for \"{}\": {}", schedule.getName(), scheduleEntry.getNextFuzzyTimestamp()));
} }
private void calculateEntry(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) { private void calculateEntry(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) {
log.debug("calculateNext \"{}\", {}:", schedule.getName(), entry); log.debug("calculateNext \"{}\", {}:", schedule.getName(), entry);
if (!entry.isEnabled() || !isAnyWeekdayEnabled(entry)) { if (!entry.isEnabled() || !isAnyWeekdayEnabled(entry)) {
entry.setNextDateTime(null); entry.setNextClearTimestamp(null);
return; return;
} }
ZonedDateTime midnight = now.withHour(0).withMinute(0).withSecond(0).withNano(0); ZonedDateTime midnight = now.withHour(0).withMinute(0).withSecond(0).withNano(0);
@ -88,7 +89,7 @@ public class ScheduleWriteService {
next = calculateEntryForDay(entry, midnight); next = calculateEntryForDay(entry, midnight);
} }
log.debug(" => {}", next); log.debug(" => {}", next);
entry.setNextDateTime(next); entry.setNextClearTimestamp(next);
} }
private ZonedDateTime calculateEntryForDay(final ScheduleEntry entry, final ZonedDateTime midnight) { private ZonedDateTime calculateEntryForDay(final ScheduleEntry entry, final ZonedDateTime midnight) {
@ -151,7 +152,7 @@ public class ScheduleWriteService {
} }
public Optional<ZonedDateTime> getNextTimestamp() { public Optional<ZonedDateTime> getNextTimestamp() {
return scheduleEntryRepository.findFirstNextDateTimeByNextDateTimeNotNullOrderByNextDateTimeAsc().map(ScheduleEntry::getNextDateTime); return scheduleEntryRepository.findFirstByNextFuzzyTimestampNotNullOrderByNextFuzzyTimestampAsc().map(ScheduleEntry::getNextFuzzyTimestamp);
} }
} }

View File

@ -9,12 +9,15 @@ import javax.persistence.*;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Random;
@Getter @Getter
@Setter @Setter
@Entity @Entity
public class ScheduleEntry { public class ScheduleEntry {
private static final Random RANDOM = new Random(System.currentTimeMillis());
@Id @Id
@GeneratedValue @GeneratedValue
@Setter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
@ -47,11 +50,31 @@ public class ScheduleEntry {
private int second; private int second;
private ZonedDateTime nextDateTime; private int fuzzyMinusSeconds = 0;
private int fuzzyPlusSeconds = 0;
private ZonedDateTime nextClearTimestamp;
private ZonedDateTime lastClearTimestamp;
@Setter(AccessLevel.NONE)
private ZonedDateTime nextFuzzyTimestamp;
@ElementCollection(fetch = FetchType.EAGER) @ElementCollection(fetch = FetchType.EAGER)
private Map<String, String> properties = new HashMap<>(); private Map<String, String> properties = new HashMap<>();
public void setNextClearTimestamp(final ZonedDateTime next) {
nextClearTimestamp = next;
if (nextClearTimestamp != null && (lastClearTimestamp == null || nextClearTimestamp.compareTo(lastClearTimestamp) != 0)) {
final int secondsRange = fuzzyPlusSeconds + fuzzyMinusSeconds;
final int fuzzySeconds = secondsRange > 0 ? RANDOM.nextInt(secondsRange) - fuzzyMinusSeconds : 0;
nextFuzzyTimestamp = nextClearTimestamp.plusSeconds(fuzzySeconds);
} else {
nextFuzzyTimestamp = null;
}
}
public void setWorkday(final boolean enabled) { public void setWorkday(final boolean enabled) {
monday = enabled; monday = enabled;
tuesday = enabled; tuesday = enabled;

View File

@ -56,7 +56,7 @@ public class ScheduleEntryDto {
hour = scheduleEntry.getHour(); hour = scheduleEntry.getHour();
minute = scheduleEntry.getMinute(); minute = scheduleEntry.getMinute();
second = scheduleEntry.getSecond(); second = scheduleEntry.getSecond();
nextDateTime = scheduleEntry.getNextDateTime(); nextDateTime = scheduleEntry.getNextFuzzyTimestamp();
properties = new HashMap<>(scheduleEntry.getProperties()); properties = new HashMap<>(scheduleEntry.getProperties());
} }

View File

@ -6,6 +6,6 @@ import java.util.Optional;
public interface ScheduleEntryRepository extends CrudRepository<ScheduleEntry, Long> { public interface ScheduleEntryRepository extends CrudRepository<ScheduleEntry, Long> {
Optional<ScheduleEntry> findFirstNextDateTimeByNextDateTimeNotNullOrderByNextDateTimeAsc(); Optional<ScheduleEntry> findFirstByNextFuzzyTimestampNotNullOrderByNextFuzzyTimestampAsc();
} }