MultiGroups + UDP Broadcast

This commit is contained in:
Patrick Haßel 2021-10-28 08:50:53 +02:00
parent 06099e291f
commit d8664a800a
10 changed files with 136 additions and 77 deletions

View File

@ -3,5 +3,5 @@
cd "$(dirname "$0")" || exit 1 cd "$(dirname "$0")" || exit 1
mvn clean package spring-boot:repackage && \ mvn clean package spring-boot:repackage && \
scp target/Homeautomation.jar media@10.0.0.50:/home/media/Homeautomation/Homeautomation.jar && \ scp target/Homeautomation.jar media@10.0.0.50:/home/media/Homeautomation/Homeautomation.jar.update && \
curl -m 2 -s http://10.0.0.50:8080/server/shutdown && echo "Server restarting..." || echo "Failed to restart server!" curl -m 2 -s http://10.0.0.50:8080/server/shutdown && echo "Server restarting..." || echo "Failed to restart server!"

View File

@ -35,112 +35,111 @@ public class DemoDataService {
@PostConstruct @PostConstruct
public void postConstruct() { public void postConstruct() {
final KnxGroupDto eg_flur_licht_schalten = createKnxGroupIfNotExists("EG Flur Licht Schalten", 1294, "1.001", false); final KnxGroupDto eg_flur_licht_schalten = createKnxGroupIfNotExists("EG Flur Licht Schalten", 1294, "1.001", false, false);
final KnxGroupDto eg_ambiente_schalten = createKnxGroupIfNotExists("EG Ambiente Schalten", 848, "1.001", false); final KnxGroupDto eg_ambiente_schalten = createKnxGroupIfNotExists("EG Ambiente Schalten", 848, "1.001", false, false);
final KnxGroupDto og_ambiente_schalten = createKnxGroupIfNotExists("OG Ambiente Schalten", 1539, "1.001", false); final KnxGroupDto og_ambiente_schalten = createKnxGroupIfNotExists("OG Ambiente Schalten", 1539, "1.001", false, false);
final KnxGroupDto wohnzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Wohnzimmer Rollladen Position Anfahren", new GroupAddress(0, 4, 24), "5.001", false); final KnxGroupDto wohnzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Wohnzimmer Rollladen Position Anfahren", new GroupAddress(0, 4, 24), "5.001", false, false);
final KnxGroupDto schlafzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Schlafzimmer Rollladen Position Anfahren", new GroupAddress(0, 3, 3), "5.001", false); final KnxGroupDto schlafzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Schlafzimmer Rollladen Position Anfahren", new GroupAddress(0, 3, 3), "5.001", false, false);
final KnxGroupDto flur_rollladen_position_anfahren = createKnxGroupIfNotExists("Flur Rollladen Position Anfahren", new GroupAddress(0, 5, 13), "5.001", false); final KnxGroupDto flur_rollladen_position_anfahren = createKnxGroupIfNotExists("Flur Rollladen Position Anfahren", new GroupAddress(0, 5, 13), "5.001", false, false);
final KnxGroupDto badewanne_schalten = createKnxGroupIfNotExists("Badewanne Schalten", 781, "1.001", false); final KnxGroupDto badewanne_schalten = createKnxGroupIfNotExists("Badewanne Schalten", 781, "1.001", false, false);
final KnxGroupDto bad_licht_mitteschalten = createKnxGroupIfNotExists("Bad Licht Mitte Schalten", 797, "1.001", false); final KnxGroupDto bad_licht_mitteschalten = createKnxGroupIfNotExists("Bad Licht Mitte Schalten", 797, "1.001", false, false);
final KnxGroupDto helligkeit = createKnxGroupIfNotExists("Helligkeit", 1286, "9.004", false); final KnxGroupDto helligkeit = createKnxGroupIfNotExists("Helligkeit", 1286, "9.004", false, true);
final Schedule scheduleEgFlurLicht = new Schedule(); final Schedule scheduleEgFlurLicht = new Schedule();
scheduleEgFlurLicht.setName("EG Flur Licht"); scheduleEgFlurLicht.setName("EG Flur Licht");
createTime(scheduleEgFlurLicht, 11, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten.getAddress(), "true")); createTime(scheduleEgFlurLicht, 11, 30, 0, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten, true));
createTime(scheduleEgFlurLicht, 12, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten.getAddress(), "false")); createTime(scheduleEgFlurLicht, 12, 30, 0, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten, false));
createTime(scheduleEgFlurLicht, 16, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten.getAddress(), "true")); createTime(scheduleEgFlurLicht, 16, 30, 0, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten, true));
createTime(scheduleEgFlurLicht, 17, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten.getAddress(), "false")); createTime(scheduleEgFlurLicht, 17, 30, 0, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten, false));
createTime(scheduleEgFlurLicht, 22, 0, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten.getAddress(), "true")); createTime(scheduleEgFlurLicht, 22, 0, 0, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten, true));
createTime(scheduleEgFlurLicht, 23, 0, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten.getAddress(), "false")); createTime(scheduleEgFlurLicht, 23, 0, 0, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten, false));
createTime(scheduleEgFlurLicht, 1, 0, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten.getAddress(), "true")); createTime(scheduleEgFlurLicht, 1, 0, 0, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten, true));
createTime(scheduleEgFlurLicht, 2, 0, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten.getAddress(), "false")); createTime(scheduleEgFlurLicht, 2, 0, 0, MIN30_SEC, new PropertyEntry(eg_flur_licht_schalten, false));
scheduleRepository.save(scheduleEgFlurLicht); scheduleRepository.save(scheduleEgFlurLicht);
final Schedule scheduleEgAmbiente = new Schedule(); final Schedule scheduleEgAmbiente = new Schedule();
scheduleEgAmbiente.setName("EG Ambiente"); scheduleEgAmbiente.setName("EG Ambiente");
createTime(scheduleEgAmbiente, 7, 15, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten.getAddress(), "true")); createTime(scheduleEgAmbiente, 7, 15, 0, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten, true));
createTime(scheduleEgAmbiente, 9, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten.getAddress(), "false")); createTime(scheduleEgAmbiente, 9, 30, 0, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten, false));
createSunset(scheduleEgAmbiente, Zenith.OFFICIAL, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten.getAddress(), "true")); createSunset(scheduleEgAmbiente, Zenith.OFFICIAL, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten, true));
createSunset(scheduleEgAmbiente, Zenith.ASTRONOMICAL, MIN30_SEC, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten.getAddress(), "false")); createSunset(scheduleEgAmbiente, Zenith.ASTRONOMICAL, MIN30_SEC, new PropertyEntry(eg_ambiente_schalten, false));
scheduleRepository.save(scheduleEgAmbiente); scheduleRepository.save(scheduleEgAmbiente);
final Schedule scheduleOgAmbiente = new Schedule(); final Schedule scheduleOgAmbiente = new Schedule();
scheduleOgAmbiente.setName("OG Ambiente"); scheduleOgAmbiente.setName("OG Ambiente");
createTime(scheduleOgAmbiente, 7, 15, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(og_ambiente_schalten.getAddress(), "true")); createTime(scheduleOgAmbiente, 7, 15, 0, MIN30_SEC, new PropertyEntry(og_ambiente_schalten, true));
createTime(scheduleOgAmbiente, 9, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(og_ambiente_schalten.getAddress(), "false")); createTime(scheduleOgAmbiente, 9, 30, 0, MIN30_SEC, new PropertyEntry(og_ambiente_schalten, false));
createSunset(scheduleOgAmbiente, Zenith.OFFICIAL, MIN30_SEC, MIN30_SEC, new PropertyEntry(og_ambiente_schalten.getAddress(), "true")); createSunset(scheduleOgAmbiente, Zenith.OFFICIAL, MIN30_SEC, new PropertyEntry(og_ambiente_schalten, true));
createSunset(scheduleOgAmbiente, Zenith.ASTRONOMICAL, MIN30_SEC, MIN30_SEC, new PropertyEntry(og_ambiente_schalten.getAddress(), "false")); createSunset(scheduleOgAmbiente, Zenith.ASTRONOMICAL, MIN30_SEC, new PropertyEntry(og_ambiente_schalten, false));
scheduleRepository.save(scheduleOgAmbiente); scheduleRepository.save(scheduleOgAmbiente);
final Schedule scheduleWohnzimmerRollladen = new Schedule(); final Schedule scheduleWohnzimmerRollladen = new Schedule();
scheduleWohnzimmerRollladen.setName("Rollläden Wohnzimmer"); scheduleWohnzimmerRollladen.setName("Rollläden Wohnzimmer");
createSunrise(scheduleWohnzimmerRollladen, Zenith.OFFICIAL, 0, 0, new PropertyEntry(wohnzimmer_rollladen_position_anfahren.getAddress(), "0")); createSunrise(scheduleWohnzimmerRollladen, Zenith.CIVIL, 0, new PropertyEntry(wohnzimmer_rollladen_position_anfahren, 0));
createSunset(scheduleWohnzimmerRollladen, Zenith.OFFICIAL, 0, 0, new PropertyEntry(wohnzimmer_rollladen_position_anfahren.getAddress(), "100")); createSunset(scheduleWohnzimmerRollladen, Zenith.CIVIL, 0, new PropertyEntry(wohnzimmer_rollladen_position_anfahren, 100));
scheduleRepository.save(scheduleWohnzimmerRollladen); scheduleRepository.save(scheduleWohnzimmerRollladen);
final Schedule scheduleSchlafzimmerRollladen = new Schedule(); final Schedule scheduleSchlafzimmerRollladen = new Schedule();
scheduleSchlafzimmerRollladen.setName("Rollläden Schlafzimmer"); scheduleSchlafzimmerRollladen.setName("Rollläden Schlafzimmer");
createTime(scheduleSchlafzimmerRollladen, 7, 0, 0, 0, 0, new PropertyEntry(schlafzimmer_rollladen_position_anfahren.getAddress(), "0")); createTime(scheduleSchlafzimmerRollladen, 7, 0, 0, 0, new PropertyEntry(schlafzimmer_rollladen_position_anfahren, 0));
createTime(scheduleSchlafzimmerRollladen, 20, 0, 0, 0, 0, new PropertyEntry(schlafzimmer_rollladen_position_anfahren.getAddress(), "100")); createSunset(scheduleSchlafzimmerRollladen, Zenith.CIVIL, 0, new PropertyEntry(schlafzimmer_rollladen_position_anfahren, 100));
scheduleRepository.save(scheduleSchlafzimmerRollladen); scheduleRepository.save(scheduleSchlafzimmerRollladen);
final Schedule scheduleFlurRollladen = new Schedule(); final Schedule scheduleFlurRollladen = new Schedule();
scheduleFlurRollladen.setName("Rollläden Flur"); scheduleFlurRollladen.setName("Rollläden Flur");
createSunrise(scheduleFlurRollladen, Zenith.NAUTICAL, 0, 0, new PropertyEntry(flur_rollladen_position_anfahren.getAddress(), "0")); createSunrise(scheduleFlurRollladen, Zenith.CIVIL, 0, new PropertyEntry(flur_rollladen_position_anfahren, 0));
createSunset(scheduleFlurRollladen, Zenith.NAUTICAL, 0, 0, new PropertyEntry(flur_rollladen_position_anfahren.getAddress(), "100")); createSunset(scheduleFlurRollladen, Zenith.CIVIL, 0, new PropertyEntry(flur_rollladen_position_anfahren, 100));
scheduleRepository.save(scheduleFlurRollladen); scheduleRepository.save(scheduleFlurRollladen);
final Schedule scheduleBadewanneBlinken = new Schedule(); final Schedule scheduleBadewanneBlinken = new Schedule();
scheduleBadewanneBlinken.setName("Badewanne"); scheduleBadewanneBlinken.setName("Badewanne");
final int interval = 2; final int interval = 2;
final int fuzzy = 0;
int seconds = interval; int seconds = interval;
createRelative(scheduleBadewanneBlinken, seconds += interval, fuzzy, fuzzy, new PropertyEntry(badewanne_schalten.getAddress(), "true")); createRelative(scheduleBadewanneBlinken, seconds += interval, 0, new PropertyEntry(badewanne_schalten, true));
createRelative(scheduleBadewanneBlinken, seconds += interval, fuzzy, fuzzy, new PropertyEntry(badewanne_schalten.getAddress(), "false")); createRelative(scheduleBadewanneBlinken, seconds += interval, 0, new PropertyEntry(badewanne_schalten, false));
createRelative(scheduleBadewanneBlinken, seconds += interval, fuzzy, fuzzy, new PropertyEntry(badewanne_schalten.getAddress(), "true")); createRelative(scheduleBadewanneBlinken, seconds += interval, 0, new PropertyEntry(badewanne_schalten, true));
createRelative(scheduleBadewanneBlinken, seconds += interval, fuzzy, fuzzy, new PropertyEntry(badewanne_schalten.getAddress(), "false")); createRelative(scheduleBadewanneBlinken, seconds += interval, 0, new PropertyEntry(badewanne_schalten, false));
scheduleRepository.save(scheduleBadewanneBlinken); scheduleRepository.save(scheduleBadewanneBlinken);
final Schedule scheduleBadLichtMitte = new Schedule(); final Schedule scheduleBadLichtMitte = new Schedule();
scheduleBadLichtMitte.setName("Bad Licht Mitte"); scheduleBadLichtMitte.setName("Bad Licht Mitte");
createTime(scheduleBadLichtMitte, 10, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten.getAddress(), "true")); createTime(scheduleBadLichtMitte, 10, 30, 0, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten, true));
createTime(scheduleBadLichtMitte, 11, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten.getAddress(), "false")); createTime(scheduleBadLichtMitte, 11, 30, 0, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten, false));
createTime(scheduleBadLichtMitte, 15, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten.getAddress(), "true")); createTime(scheduleBadLichtMitte, 15, 30, 0, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten, true));
createTime(scheduleBadLichtMitte, 16, 30, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten.getAddress(), "false")); createTime(scheduleBadLichtMitte, 16, 30, 0, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten, false));
createTime(scheduleBadLichtMitte, 21, 0, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten.getAddress(), "true")); createTime(scheduleBadLichtMitte, 21, 0, 0, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten, true));
createTime(scheduleBadLichtMitte, 22, 0, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten.getAddress(), "false")); createTime(scheduleBadLichtMitte, 22, 0, 0, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten, false));
createTime(scheduleBadLichtMitte, 0, 0, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten.getAddress(), "true")); createTime(scheduleBadLichtMitte, 0, 0, 0, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten, true));
createTime(scheduleBadLichtMitte, 1, 0, 0, MIN30_SEC, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten.getAddress(), "false")); createTime(scheduleBadLichtMitte, 1, 0, 0, MIN30_SEC, new PropertyEntry(bad_licht_mitteschalten, false));
scheduleRepository.save(scheduleBadLichtMitte); scheduleRepository.save(scheduleBadLichtMitte);
} }
private KnxGroupDto createKnxGroupIfNotExists(final String name, final int address, final String dpt, final boolean readable) { private KnxGroupDto createKnxGroupIfNotExists(final String name, final int address, final String dpt, final boolean readable, final boolean multiGroup) {
return createKnxGroupIfNotExists(name, new GroupAddress(address), dpt, readable); return createKnxGroupIfNotExists(name, new GroupAddress(address), dpt, readable, multiGroup);
} }
private KnxGroupDto createKnxGroupIfNotExists(final String name, final GroupAddress address, final String dpt, final boolean readable) { private KnxGroupDto createKnxGroupIfNotExists(final String name, final GroupAddress address, final String dpt, final boolean readable, final boolean multiGroup) {
return knxGroupRepository.findByAddressRaw(address.getRawAddress()).map(KnxGroupDto::new).orElseGet(() -> knxGroupWriteService.create(name, address, dpt, readable)); return knxGroupRepository.findByAddressRaw(address.getRawAddress()).map(KnxGroupDto::new).orElseGet(() -> knxGroupWriteService.create(name, address, dpt, readable, multiGroup));
} }
private ScheduleEntry createRelative(final Schedule schedule, final int inSeconds, final int fuzzyMinusSeconds, final int fuzzyPlusSeconds, final Map.Entry<String, String>... entries) { private ScheduleEntry createRelative(final Schedule schedule, final int inSeconds, final int plusMinusSeconds, 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(), fuzzyMinusSeconds, fuzzyPlusSeconds, entries); return create(schedule, ScheduleEntryType.TIME, null, now.getHour(), now.getMinute(), now.getSecond(), plusMinusSeconds, 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) { private ScheduleEntry createTime(final Schedule schedule, final int hour, final int minute, final int second, final int plusMinusSeconds, final Map.Entry<String, String>... entries) {
return create(schedule, ScheduleEntryType.TIME, null, hour, minute, second, fuzzyMinusSeconds, fuzzyPlusSeconds, entries); return create(schedule, ScheduleEntryType.TIME, null, hour, minute, second, plusMinusSeconds, entries);
} }
private ScheduleEntry createSunrise(final Schedule schedule, final Zenith zenith, final int fuzzyMinusSeconds, final int fuzzyPlusSeconds, final Map.Entry<String, String>... entries) { private ScheduleEntry createSunrise(final Schedule schedule, final Zenith zenith, final int plusMinusSeconds, final Map.Entry<String, String>... entries) {
return create(schedule, ScheduleEntryType.SUNRISE, zenith, 0, 0, 0, fuzzyMinusSeconds, fuzzyPlusSeconds, entries); return create(schedule, ScheduleEntryType.SUNRISE, zenith, 0, 0, 0, plusMinusSeconds, entries);
} }
private ScheduleEntry createSunset(final Schedule schedule, final Zenith zenith, final int fuzzyMinusSeconds, final int fuzzyPlusSeconds, final Map.Entry<String, String>... entries) { private ScheduleEntry createSunset(final Schedule schedule, final Zenith zenith, final int plusMinusSeconds, final Map.Entry<String, String>... entries) {
return create(schedule, ScheduleEntryType.SUNSET, zenith, 0, 0, 0, fuzzyMinusSeconds, fuzzyPlusSeconds, entries); return create(schedule, ScheduleEntryType.SUNSET, zenith, 0, 0, 0, plusMinusSeconds, 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) { private ScheduleEntry create(final Schedule schedule, final ScheduleEntryType type, final Zenith zenith, final int hour, final int minute, final int second, final int plusMinusSeconds, 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) {
@ -149,8 +148,7 @@ 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.setPlusMinusSeconds(plusMinusSeconds);
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

@ -21,12 +21,12 @@ public class DeviceWriteService {
public void postConstruct() { public void postConstruct() {
final DeviceSwitch deviceSwitch = new DeviceSwitch(); final DeviceSwitch deviceSwitch = new DeviceSwitch();
deviceSwitch.setName("TEST"); deviceSwitch.setName("TEST");
deviceSwitch.setStatePropertyName("knx.group.0/3/6"); deviceSwitch.setStatePropertyName("knx.group.0.3.6");
deviceRepository.save(deviceSwitch); deviceRepository.save(deviceSwitch);
final DeviceNumber deviceNumber = new DeviceNumber(); final DeviceNumber deviceNumber = new DeviceNumber();
deviceNumber.setName("Helligkeit"); deviceNumber.setName("Helligkeit");
deviceNumber.setValuePropertyName("knx.group.0/5/6"); deviceNumber.setValuePropertyName("knx.group.0.5.6");
deviceRepository.save(deviceNumber); deviceRepository.save(deviceNumber);
} }

View File

@ -129,14 +129,14 @@ public class KnxThreadService extends AbstractThreadService implements NetworkLi
@Override @Override
public void groupReadResponse(final ProcessEvent processEvent) { public void groupReadResponse(final ProcessEvent processEvent) {
synchronized (databaseAccessLock) { synchronized (databaseAccessLock) {
knxGroupWriteService.updateIfExists(processEvent.getDestination().getRawAddress(), processEvent.getASDU()); knxGroupWriteService.updateIfExists(processEvent.getDestination().getRawAddress(), processEvent.getASDU(), processEvent.getSourceAddr());
} }
} }
@Override @Override
public void groupWrite(final ProcessEvent processEvent) { public void groupWrite(final ProcessEvent processEvent) {
synchronized (databaseAccessLock) { synchronized (databaseAccessLock) {
knxGroupWriteService.updateIfExists(processEvent.getDestination().getRawAddress(), processEvent.getASDU()); knxGroupWriteService.updateIfExists(processEvent.getDestination().getRawAddress(), processEvent.getASDU(), processEvent.getSourceAddr());
} }
} }

View File

@ -32,6 +32,10 @@ public class KnxGroup {
private byte[] value; private byte[] value;
private int lastDeviceAddressRaw;
private String lastDeviceAddressString;
private Boolean booleanValue; private Boolean booleanValue;
private Double numberValue; private Double numberValue;
@ -42,6 +46,8 @@ public class KnxGroup {
private int readInterval; private int readInterval;
private boolean multiGroup;
@Embedded @Embedded
private KnxGroupLinkInfo read = new KnxGroupLinkInfo(); private KnxGroupLinkInfo read = new KnxGroupLinkInfo();
@ -61,4 +67,9 @@ public class KnxGroup {
return new GroupAddress(addressRaw); return new GroupAddress(addressRaw);
} }
public String getPropertyName() {
final GroupAddress address = getAddress();
return "knx.group." + address.getMainGroup() + "." + address.getMiddleGroup() + "." + address.getSubGroup8();
}
} }

View File

@ -14,6 +14,8 @@ public class KnxGroupDto {
public final String addressStr; public final String addressStr;
public final String propertyName;
public final String dpt; public final String dpt;
public final String name; public final String name;
@ -28,6 +30,7 @@ public class KnxGroupDto {
id = knxGroup.getId(); id = knxGroup.getId();
addressRaw = knxGroup.getAddressRaw(); addressRaw = knxGroup.getAddressRaw();
addressStr = knxGroup.getAddressStr(); addressStr = knxGroup.getAddressStr();
propertyName = knxGroup.getPropertyName();
dpt = knxGroup.getDpt(); dpt = knxGroup.getDpt();
name = knxGroup.getName(); name = knxGroup.getName();
booleanValue = knxGroup.getBooleanValue(); booleanValue = knxGroup.getBooleanValue();

View File

@ -25,7 +25,7 @@ import static de.ph87.homeautomation.shared.Helpers.quoteOrNull;
public class KnxGroupSetService implements IPropertyOwner { public class KnxGroupSetService implements IPropertyOwner {
@Getter @Getter
private final Pattern propertyNamePattern = Pattern.compile("^knx\\.group\\.(\\d+)/(\\d+)/(\\d+)$"); private final Pattern propertyNamePattern = Pattern.compile("^knx\\.group\\.(\\d+)\\.(\\d+)\\.(\\d+)$");
private final KnxThreadService knxThreadService; private final KnxThreadService knxThreadService;

View File

@ -6,10 +6,15 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import tuwien.auto.calimero.GroupAddress; import tuwien.auto.calimero.GroupAddress;
import tuwien.auto.calimero.IndividualAddress;
import tuwien.auto.calimero.KNXException; import tuwien.auto.calimero.KNXException;
import tuwien.auto.calimero.KNXFormatException; import tuwien.auto.calimero.KNXFormatException;
import tuwien.auto.calimero.dptxlator.*; import tuwien.auto.calimero.dptxlator.*;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
@ -24,20 +29,35 @@ public class KnxGroupWriteService {
private final KnxGroupRepository knxGroupRepository; private final KnxGroupRepository knxGroupRepository;
public void updateIfExists(final int rawAddress, final byte[] data) { private DatagramSocket broadcastDatagramSocket;
private InetAddress broadcastAddress;
private final int broadcastPort = 1987;
@PostConstruct
public void postConstruct() throws SocketException, UnknownHostException {
broadcastDatagramSocket = new DatagramSocket();
broadcastDatagramSocket.setBroadcast(true);
broadcastAddress = InetAddress.getByName("255.255.255.255");
}
public void updateIfExists(final int rawAddress, final byte[] data, final IndividualAddress knxDeviceAddress) {
final Optional<KnxGroup> knxGroupOptional = knxGroupRepository.findByAddressRaw(rawAddress); final Optional<KnxGroup> knxGroupOptional = knxGroupRepository.findByAddressRaw(rawAddress);
if (knxGroupOptional.isEmpty()) { if (knxGroupOptional.isEmpty()) {
log.debug("No KnxGroup with address={}", new GroupAddress(rawAddress)); log.debug("No KnxGroup with address={}", new GroupAddress(rawAddress));
} }
knxGroupOptional.ifPresent(knxGroup -> { knxGroupOptional.ifPresent(knxGroup -> {
knxGroup.setValue(data); knxGroup.setValue(data);
knxGroup.setLastDeviceAddressRaw(knxDeviceAddress.getRawAddress());
knxGroup.setLastDeviceAddressString(knxDeviceAddress.toString());
knxGroup.setValueTimestamp(ZonedDateTime.now()); knxGroup.setValueTimestamp(ZonedDateTime.now());
knxGroup.setBooleanValue(null); knxGroup.setBooleanValue(null);
knxGroup.setNumberValue(null); knxGroup.setNumberValue(null);
try { try {
final DPTXlator translator = findTranslator(knxGroup); final DPTXlator translator = findTranslator(knxGroup);
translator.setData(data); translator.setData(data);
translate(DPTXlatorBoolean.class, translator, knxGroup::setBooleanValue, DPTXlatorBoolean::getValueBoolean); translate(DPTXlatorBoolean.class, translator, value -> setBooleanValue(knxGroup, value), DPTXlatorBoolean::getValueBoolean);
translate(DPTXlator8BitUnsigned.class, translator, knxGroup::setNumberValue, DPTXlator8BitUnsigned::getNumericValue); translate(DPTXlator8BitUnsigned.class, translator, knxGroup::setNumberValue, DPTXlator8BitUnsigned::getNumericValue);
translate(DPTXlator2ByteFloat.class, translator, knxGroup::setNumberValue, DPTXlator2ByteFloat::getNumericValue); translate(DPTXlator2ByteFloat.class, translator, knxGroup::setNumberValue, DPTXlator2ByteFloat::getNumericValue);
translate(DPTXlator2ByteUnsigned.class, translator, knxGroup::setNumberValue, DPTXlator2ByteUnsigned::getNumericValue); translate(DPTXlator2ByteUnsigned.class, translator, knxGroup::setNumberValue, DPTXlator2ByteUnsigned::getNumericValue);
@ -48,6 +68,7 @@ public class KnxGroupWriteService {
translate(DPTXlator64BitSigned.class, translator, knxGroup::setNumberValue, DPTXlator64BitSigned::getNumericValue); translate(DPTXlator64BitSigned.class, translator, knxGroup::setNumberValue, DPTXlator64BitSigned::getNumericValue);
translate(DPTXlatorSceneNumber.class, translator, knxGroup::setNumberValue, DPTXlatorSceneNumber::getNumericValue); translate(DPTXlatorSceneNumber.class, translator, knxGroup::setNumberValue, DPTXlatorSceneNumber::getNumericValue);
// TODO implement all DPTXlator... // TODO implement all DPTXlator...
broadcast(knxGroup);
} catch (NoTranslatorException e) { } catch (NoTranslatorException e) {
log.error(e.getMessage()); log.error(e.getMessage());
} }
@ -55,6 +76,28 @@ public class KnxGroupWriteService {
}); });
} }
private void setBooleanValue(final KnxGroup knxGroup, final Boolean value) {
knxGroup.setBooleanValue(value);
if (value == null) {
knxGroup.setNumberValue(null);
} else {
knxGroup.setNumberValue(value ? 1.0 : 0.0);
}
}
private void broadcast(final KnxGroup knxGroup) {
if (knxGroup.getNumberValue() != null && !knxGroup.getNumberValue().isNaN()) {
final String message = knxGroup.getPropertyName() + (knxGroup.isMultiGroup() ? ".from." + knxGroup.getLastDeviceAddressString() : "") + " " + knxGroup.getNumberValue();
try {
log.info("UDP Broadcast {}:{}: {}", broadcastAddress, broadcastPort, message);
final byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
broadcastDatagramSocket.send(new DatagramPacket(bytes, bytes.length, broadcastAddress, broadcastPort));
} catch (IOException e) {
log.error("Failed to broadcast property change of {}: {}", knxGroup, e.getMessage());
}
}
}
private <X extends DPTXlator, T> void translate(final Class<X> dptXlatorClass, final DPTXlator translator, final Consumer<T> setter, final Function<X, T> getter) { private <X extends DPTXlator, T> void translate(final Class<X> dptXlatorClass, final DPTXlator translator, final Consumer<T> setter, final Function<X, T> getter) {
if (dptXlatorClass.isInstance(translator)) { if (dptXlatorClass.isInstance(translator)) {
setter.accept(getter.apply(dptXlatorClass.cast(translator))); setter.accept(getter.apply(dptXlatorClass.cast(translator)));
@ -65,10 +108,11 @@ public class KnxGroupWriteService {
knxGroupRepository.findAllByRead_AbleTrue().forEach(knxGroup -> knxGroup.getRead().setNextTimestamp(ZonedDateTime.now())); knxGroupRepository.findAllByRead_AbleTrue().forEach(knxGroup -> knxGroup.getRead().setNextTimestamp(ZonedDateTime.now()));
} }
public KnxGroupDto 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 boolean multiGroup) {
final KnxGroup trans = new KnxGroup(); final KnxGroup trans = new KnxGroup();
trans.setAddress(address); trans.setAddress(address);
trans.setDpt(dpt); trans.setDpt(dpt);
trans.setMultiGroup(multiGroup);
trans.setName(name); trans.setName(name);
trans.getRead().setAble(readable); trans.getRead().setAble(readable);
return new KnxGroupDto(knxGroupRepository.save(trans)); return new KnxGroupDto(knxGroupRepository.save(trans));

View File

@ -1,7 +1,7 @@
package de.ph87.homeautomation.schedule; package de.ph87.homeautomation.schedule;
import de.ph87.homeautomation.knx.group.KnxGroupDto;
import lombok.Data; import lombok.Data;
import tuwien.auto.calimero.GroupAddress;
import java.util.Map; import java.util.Map;
@ -12,9 +12,14 @@ public class PropertyEntry implements Map.Entry<String, String> {
private String value; private String value;
public PropertyEntry(final GroupAddress groupAddress, final String value) { public PropertyEntry(final KnxGroupDto knxGroupDto, final boolean value) {
this.key = "knx.group." + groupAddress; this.key = knxGroupDto.getPropertyName();
this.value = value; this.value = "" + value;
}
public PropertyEntry(final KnxGroupDto knxGroupDto, final int value) {
this.key = knxGroupDto.getPropertyName();
this.value = "" + value;
} }
public String setValue(final String value) { public String setValue(final String value) {

View File

@ -50,9 +50,7 @@ public class ScheduleEntry {
private int second; private int second;
private int fuzzyMinusSeconds = 0; private int plusMinusSeconds = 0;
private int fuzzyPlusSeconds = 0;
private ZonedDateTime nextClearTimestamp; private ZonedDateTime nextClearTimestamp;
@ -67,8 +65,8 @@ public class ScheduleEntry {
public void setNextClearTimestamp(final ZonedDateTime next) { public void setNextClearTimestamp(final ZonedDateTime next) {
nextClearTimestamp = next; nextClearTimestamp = next;
if (nextClearTimestamp != null && (lastClearTimestamp == null || nextClearTimestamp.compareTo(lastClearTimestamp) != 0)) { if (nextClearTimestamp != null && (lastClearTimestamp == null || nextClearTimestamp.compareTo(lastClearTimestamp) != 0)) {
final int secondsRange = fuzzyPlusSeconds + fuzzyMinusSeconds; final int secondsRange = 2 * plusMinusSeconds;
final int fuzzySeconds = secondsRange > 0 ? RANDOM.nextInt(secondsRange) - fuzzyMinusSeconds : 0; final int fuzzySeconds = secondsRange > 0 ? RANDOM.nextInt(secondsRange) - plusMinusSeconds : 0;
nextFuzzyTimestamp = nextClearTimestamp.plusSeconds(fuzzySeconds); nextFuzzyTimestamp = nextClearTimestamp.plusSeconds(fuzzySeconds);
} else { } else {
nextFuzzyTimestamp = null; nextFuzzyTimestamp = null;