diff --git a/deploy.sh b/deploy.sh
new file mode 100755
index 0000000..5bd5f90
--- /dev/null
+++ b/deploy.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+cd "$(dirname "$0")" || exit 1
+
+mvn clean package spring-boot:repackage && \
+scp target/Homeautomation.jar media@10.0.0.50:/home/media/Homeautomation/Homeautomation.jar
diff --git a/pom.xml b/pom.xml
index 5a2f93b..4520155 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,18 +7,16 @@
de.ph87
Homeautomation
1.0-SNAPSHOT
- war
- 11
- 11
+ 15
+ 15
org.springframework.boot
spring-boot-starter-parent
2.3.6.RELEASE
-
@@ -50,11 +48,13 @@
org.projectlombok
lombok
+ 1.18.20
+
com.github.calimero
calimero-core
- 2.5-M1
+ 2.5-rc1
com.luckycatlabs
@@ -71,95 +71,27 @@
+ ${project.artifactId}
-
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 11
+
+
org.springframework.boot
spring-boot-maven-plugin
-
- repackage
-
- spring-boot
-
- de.ph87.de.ph87.homeautomation.BackendApplication
-
+ de.ph87.homeautomation.BackendApplication
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/java/de/ph87/homeautomation/DemoDataService.java b/src/main/java/de/ph87/homeautomation/DemoDataService.java
index 37535a1..5a8f95d 100644
--- a/src/main/java/de/ph87/homeautomation/DemoDataService.java
+++ b/src/main/java/de/ph87/homeautomation/DemoDataService.java
@@ -1,6 +1,7 @@
package de.ph87.homeautomation;
import com.luckycatlabs.sunrisesunset.Zenith;
+import de.ph87.homeautomation.knx.group.KnxGroupRepository;
import de.ph87.homeautomation.knx.group.KnxGroupWriteService;
import de.ph87.homeautomation.schedule.PropertyEntry;
import de.ph87.homeautomation.schedule.Schedule;
@@ -36,13 +37,15 @@ public class DemoDataService {
private final ScheduleRepository scheduleRepository;
+ private final KnxGroupRepository knxGroupRepository;
+
@PostConstruct
public void postConstruct() {
- knxGroupWriteService.create("Wohnzimmer Rollladen Position Anfahren", WOHNZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "5.001", false);
- knxGroupWriteService.create("Schlafzimmer Rollladen Position Anfahren", SCHLAFZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "5.001", false);
- knxGroupWriteService.create("Flur Rollladen Position Anfahren", FLUR_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "5.001", false);
- knxGroupWriteService.create("Badewanne Schalten", BADEWANNE_SCHALTEN, "1.001", false);
- knxGroupWriteService.create("Badewanne Status", BADEWANNE_STATUS, "1.001", true);
+ createKnxGroupIfNotExists("Wohnzimmer Rollladen Position Anfahren", WOHNZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "5.001", false);
+ createKnxGroupIfNotExists("Schlafzimmer Rollladen Position Anfahren", SCHLAFZIMMER_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "5.001", false);
+ createKnxGroupIfNotExists("Flur Rollladen Position Anfahren", FLUR_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "5.001", false);
+ createKnxGroupIfNotExists("Badewanne Schalten", BADEWANNE_SCHALTEN, "1.001", false);
+ createKnxGroupIfNotExists("Badewanne Status", BADEWANNE_STATUS, "1.001", true);
final Schedule wohnzimmer = new Schedule();
wohnzimmer.setName("Rollläden Wohnzimmer");
@@ -62,14 +65,20 @@ public class DemoDataService {
createSunset(flur, Zenith.NAUTICAL, new PropertyEntry(FLUR_ROLLLADEN_POSITION_ANFAHREN_ADDRESS, "100"));
scheduleRepository.save(flur);
-// final Schedule badewanne = new Schedule();
-// badewanne.setName("Badewanne");
-// int seconds = 2;
-// createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "true"));
-// createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "false"));
-// createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "true"));
-// createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "false"));
-// scheduleRepository.save(badewanne);
+ final Schedule badewanne = new Schedule();
+ badewanne.setName("Badewanne");
+ int seconds = 2;
+ createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "true"));
+ createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "false"));
+ createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "true"));
+ createRelative(badewanne, seconds += 2, new PropertyEntry(BADEWANNE_SCHALTEN, "false"));
+ scheduleRepository.save(badewanne);
+ }
+
+ private void createKnxGroupIfNotExists(final String name, final GroupAddress address, final String dpt, final boolean readable) {
+ if (!knxGroupRepository.existsByAddressRaw(address.getRawAddress())) {
+ knxGroupWriteService.create(name, address, dpt, readable);
+ }
}
private ScheduleEntry createRelative(final Schedule schedule, final int inSeconds, final Map.Entry... entries) {
diff --git a/src/main/java/de/ph87/homeautomation/knx/KnxThreadService.java b/src/main/java/de/ph87/homeautomation/knx/KnxThreadService.java
index f76c055..75bf2b4 100644
--- a/src/main/java/de/ph87/homeautomation/knx/KnxThreadService.java
+++ b/src/main/java/de/ph87/homeautomation/knx/KnxThreadService.java
@@ -129,14 +129,14 @@ public class KnxThreadService extends AbstractThreadService implements NetworkLi
@Override
public void groupReadResponse(final ProcessEvent processEvent) {
synchronized (databaseAccessLock) {
- knxGroupWriteService.updateOrCreate(processEvent.getDestination().getRawAddress(), processEvent.getASDU());
+ knxGroupWriteService.updateIfExists(processEvent.getDestination().getRawAddress(), processEvent.getASDU());
}
}
@Override
public void groupWrite(final ProcessEvent processEvent) {
synchronized (databaseAccessLock) {
- knxGroupWriteService.updateOrCreate(processEvent.getDestination().getRawAddress(), processEvent.getASDU());
+ knxGroupWriteService.updateIfExists(processEvent.getDestination().getRawAddress(), processEvent.getASDU());
}
}
diff --git a/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupLinkService.java b/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupLinkService.java
index 83d824c..0c57337 100644
--- a/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupLinkService.java
+++ b/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupLinkService.java
@@ -47,7 +47,7 @@ public class KnxGroupLinkService {
knxGroup.getSend().setErrorCount(0);
knxGroup.getSend().setErrorMessage(null);
knxGroup.getSend().setNextTimestamp(null);
- log.debug("Successfully sent KnxGroup: {}", knxGroup);
+ log.info("Successfully sent KnxGroup: {}", knxGroup);
return true;
} catch (KNXFormatException e) {
log.error(e.toString());
diff --git a/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupRepository.java b/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupRepository.java
index b0c3c8e..8d1eaf1 100644
--- a/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupRepository.java
+++ b/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupRepository.java
@@ -20,4 +20,6 @@ public interface KnxGroupRepository extends CrudRepository {
Optional findFirstByRead_NextTimestampNotNullOrderByRead_NextTimestampAsc();
+ boolean existsByAddressRaw(int rawAddress);
+
}
diff --git a/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupWriteService.java b/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupWriteService.java
index af0e240..40fe28a 100644
--- a/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupWriteService.java
+++ b/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupWriteService.java
@@ -25,32 +25,27 @@ public class KnxGroupWriteService {
private final KnxGroupRepository knxGroupRepository;
- public void updateOrCreate(final int rawAddress, final byte[] data) {
- final KnxGroup knxGroup = getOrCreate(rawAddress);
- knxGroup.setValue(data);
- knxGroup.setValueTimestamp(ZonedDateTime.now());
- knxGroup.setBooleanValue(null);
- knxGroup.setNumberValue(null);
- try {
- final DPTXlator translator = findTranslator(knxGroup);
- translator.setData(data);
- if (translator instanceof DPTXlatorBoolean) {
- knxGroup.setBooleanValue(((DPTXlatorBoolean) translator).getValueBoolean());
- }
- // TODO implement all DPTXlator...
- } catch (NoTranslatorException e) {
- log.error(e.getMessage());
+ public void updateIfExists(final int rawAddress, final byte[] data) {
+ final Optional knxGroupOptional = knxGroupRepository.findByAddressRaw(rawAddress);
+ if (knxGroupOptional.isEmpty()) {
+ log.debug("No KnxGroup with address={}", new GroupAddress(rawAddress));
}
- log.debug("KnxGroup updated: {}", knxGroup);
- }
-
- private KnxGroup getOrCreate(final int rawAddress) {
- return knxGroupRepository.findByAddressRaw(rawAddress).orElseGet(() -> {
- final KnxGroup trans = new KnxGroup();
- trans.setAddress(rawAddress);
- final KnxGroup saved = knxGroupRepository.save(trans);
- log.info("KnxGroup created: {}", saved);
- return saved;
+ knxGroupOptional.ifPresent(knxGroup -> {
+ knxGroup.setValue(data);
+ knxGroup.setValueTimestamp(ZonedDateTime.now());
+ knxGroup.setBooleanValue(null);
+ knxGroup.setNumberValue(null);
+ try {
+ final DPTXlator translator = findTranslator(knxGroup);
+ translator.setData(data);
+ if (translator instanceof DPTXlatorBoolean) {
+ knxGroup.setBooleanValue(((DPTXlatorBoolean) translator).getValueBoolean());
+ }
+ // TODO implement all DPTXlator...
+ } catch (NoTranslatorException e) {
+ log.error(e.getMessage());
+ }
+ log.debug("KnxGroup updated: {}", knxGroup);
});
}
@@ -58,10 +53,6 @@ public class KnxGroupWriteService {
knxGroupRepository.findAllByRead_AbleTrue().forEach(knxGroup -> knxGroup.getRead().setNextTimestamp(ZonedDateTime.now()));
}
- public void create(final String name, final int main, final int middle, final int sub, final String dpt, final boolean readable) {
- create(name, new GroupAddress(main, middle, sub), dpt, readable);
- }
-
public void create(final String name, final GroupAddress address, final String dpt, final boolean readable) {
final KnxGroup trans = new KnxGroup();
trans.setAddress(address);
diff --git a/src/main/java/de/ph87/homeautomation/schedule/ScheduleThreadService.java b/src/main/java/de/ph87/homeautomation/schedule/ScheduleThreadService.java
index f75513e..b46d6ad 100644
--- a/src/main/java/de/ph87/homeautomation/schedule/ScheduleThreadService.java
+++ b/src/main/java/de/ph87/homeautomation/schedule/ScheduleThreadService.java
@@ -27,8 +27,8 @@ public class ScheduleThreadService extends AbstractThreadService {
@Override
protected long doStep() throws InterruptedException {
- scheduleWriteService.executeAllDue();
- return scheduleWriteService.getOverallNextTimestamp().map(nextTimestamp -> Duration.between(ZonedDateTime.now(), nextTimestamp).toMillis()).orElse(0L);
+ scheduleWriteService.executeAllLastDue();
+ return scheduleWriteService.getNextTimestamp().map(nextTimestamp -> Duration.between(ZonedDateTime.now(), nextTimestamp).toMillis()).orElse(0L);
}
@Override
diff --git a/src/main/java/de/ph87/homeautomation/schedule/ScheduleWriteService.java b/src/main/java/de/ph87/homeautomation/schedule/ScheduleWriteService.java
index c23d8a8..05a27f5 100644
--- a/src/main/java/de/ph87/homeautomation/schedule/ScheduleWriteService.java
+++ b/src/main/java/de/ph87/homeautomation/schedule/ScheduleWriteService.java
@@ -39,22 +39,22 @@ public class ScheduleWriteService {
public void calculateAllNext() {
final ZonedDateTime now = ZonedDateTime.now();
- scheduleRepository.findAll().forEach(schedule -> schedule.getEntries().forEach(entry -> calculateNext(schedule, entry, now)));
+ scheduleRepository.findAll().forEach(schedule -> calculateSchedule(schedule, now));
}
- public void executeAllDue() {
+ public void executeAllLastDue() {
final ZonedDateTime now = ZonedDateTime.now();
- scheduleRepository.findAll().forEach(schedule -> executeIfDue(schedule, now));
+ scheduleRepository.findAll().forEach(schedule -> executeLastDue(schedule, now));
}
- private void executeIfDue(final Schedule schedule, final ZonedDateTime now) {
+ private void executeLastDue(final Schedule schedule, final ZonedDateTime now) {
schedule.getEntries().stream()
.filter(entry -> entry.getNextDateTime() != null && !entry.getNextDateTime().isAfter(now))
.max(Comparator.comparing(ScheduleEntry::getNextDateTime))
.ifPresent(entry -> {
log.info("Executing ScheduleEntry {}", entry);
- calculateNext(schedule, entry, now);
entry.getProperties().forEach(this::applyPropertyMapEntry);
+ calculateSchedule(schedule, now);
});
}
@@ -66,24 +66,32 @@ public class ScheduleWriteService {
}
}
- private void calculateNext(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) {
+ private void calculateSchedule(final Schedule schedule, final ZonedDateTime now) {
+ schedule.getEntries().forEach(scheduleEntry -> calculateEntry(schedule, scheduleEntry, now));
+ schedule.getEntries().stream()
+ .filter(entry -> entry.getNextDateTime() != null && entry.getNextDateTime().isAfter(now))
+ .min(Comparator.comparing(ScheduleEntry::getNextDateTime))
+ .ifPresent(scheduleEntry -> log.info("Next schedule for \"{}\": {}", schedule.getName(), scheduleEntry.getNextDateTime()));
+ }
+
+ private void calculateEntry(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) {
log.debug("calculateNext \"{}\", {}:", schedule.getName(), entry);
if (!entry.isEnabled() || !isAnyWeekdayEnabled(entry)) {
entry.setNextDateTime(null);
return;
}
ZonedDateTime midnight = now.withHour(0).withMinute(0).withSecond(0).withNano(0);
- ZonedDateTime next = nextForDay(entry, midnight);
+ ZonedDateTime next = calculateEntryForDay(entry, midnight);
while (next != null && (!next.isAfter(now) || !isWeekdayValid(entry, next))) {
log.debug(" -- skipping: {}", next);
midnight = midnight.plusDays(1);
- next = nextForDay(entry, midnight);
+ next = calculateEntryForDay(entry, midnight);
}
log.debug(" => {}", next);
entry.setNextDateTime(next);
}
- private ZonedDateTime nextForDay(final ScheduleEntry entry, final ZonedDateTime midnight) {
+ private ZonedDateTime calculateEntryForDay(final ScheduleEntry entry, final ZonedDateTime midnight) {
switch (entry.getType()) {
case TIME:
return midnight.withHour(entry.getHour()).withMinute(entry.getMinute()).withSecond(entry.getSecond());
@@ -142,7 +150,7 @@ public class ScheduleWriteService {
return false;
}
- public Optional getOverallNextTimestamp() {
+ public Optional getNextTimestamp() {
return scheduleEntryRepository.findFirstNextDateTimeByNextDateTimeNotNullOrderByNextDateTimeAsc().map(ScheduleEntry::getNextDateTime);
}
diff --git a/src/main/java/de/ph87/homeautomation/shared/AbstractThreadService.java b/src/main/java/de/ph87/homeautomation/shared/AbstractThreadService.java
index 17883aa..c8b564a 100644
--- a/src/main/java/de/ph87/homeautomation/shared/AbstractThreadService.java
+++ b/src/main/java/de/ph87/homeautomation/shared/AbstractThreadService.java
@@ -21,6 +21,8 @@ public abstract class AbstractThreadService {
private final Object lock = new Object();
+ private boolean started = false;
+
private boolean stopped = false;
protected abstract String getThreadName();
@@ -35,6 +37,9 @@ public abstract class AbstractThreadService {
@EventListener(ApplicationStartedEvent.class)
public void afterStartup() {
+ synchronized (lock) {
+ started = true;
+ }
thread.start();
}
@@ -46,7 +51,7 @@ public abstract class AbstractThreadService {
synchronized (lock) {
lock.notifyAll();
try {
- while (!stopped) {
+ while (started && !stopped) {
lock.wait();
}
} catch (InterruptedException e) {