Homeautomation/src/main/java/de/ph87/homeautomation/knx/group/KnxGroupLinkService.java

110 lines
4.7 KiB
Java

package de.ph87.homeautomation.knx.group;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tuwien.auto.calimero.GroupAddress;
import tuwien.auto.calimero.KNXException;
import tuwien.auto.calimero.KNXFormatException;
import tuwien.auto.calimero.KNXTimeoutException;
import tuwien.auto.calimero.datapoint.StateDP;
import tuwien.auto.calimero.dptxlator.TranslatorTypes;
import tuwien.auto.calimero.process.ProcessCommunicatorImpl;
import java.time.ZonedDateTime;
import java.util.Optional;
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class KnxGroupLinkService {
public static final long ERROR_DELAY_FACTOR = 500 * 1000 * 1000L;
private final KnxGroupRepository knxGroupRepository;
public boolean sendNext(final ProcessCommunicatorImpl processCommunicator) throws KNXException {
final Optional<KnxGroup> nextOptional = knxGroupRepository.findFirstBySend_NextTimestampNotNullOrderBySend_NextTimestampAsc();
if (nextOptional.isEmpty()) {
return false;
}
return send(processCommunicator, nextOptional.get());
}
public boolean readNext(final ProcessCommunicatorImpl processCommunicator) throws KNXException, InterruptedException {
final Optional<KnxGroup> nextOptional = knxGroupRepository.findFirstByRead_NextTimestampLessThanEqualOrderByRead_NextTimestampAsc(ZonedDateTime.now());
if (nextOptional.isEmpty()) {
return false;
}
return read(processCommunicator, nextOptional.get());
}
private boolean send(final ProcessCommunicatorImpl processCommunicator, final KnxGroup knxGroup) throws KNXException {
try {
log.debug("Sending KnxGroup: {}", knxGroup);
processCommunicator.write(knxGroup.getAddress(), TranslatorTypes.createTranslator(knxGroup.getDptMain(), knxGroup.getDptSub(), knxGroup.getSendValue()));
if (knxGroup.getSend().getErrorCount() > 0) {
log.info("KnxGroup recovered from send-error: {}", knxGroup);
}
knxGroup.getSend().setErrorCount(0);
knxGroup.getSend().setErrorMessage(null);
knxGroup.getSend().setNextTimestamp(null);
log.debug("Successfully sent KnxGroup: {}", knxGroup);
return true;
} catch (KNXTimeoutException | KNXFormatException e) {
log.error("Failed to send KnxGroup {}", knxGroup);
knxGroup.getSend().setErrorCount(knxGroup.getSend().getErrorCount() + 1);
knxGroup.getSend().setErrorMessage(e.getMessage());
knxGroup.getSend().setNextTimestamp(ZonedDateTime.now().plusNanos(knxGroup.getSend().getErrorCount() * knxGroup.getSend().getErrorCount() * ERROR_DELAY_FACTOR));
}
return false;
}
private boolean read(final ProcessCommunicatorImpl processCommunicator, final KnxGroup knxGroup) throws KNXException, InterruptedException {
try {
log.debug("Reading KnxGroup: {}", knxGroup);
processCommunicator.read(createStateDP(knxGroup));
if (knxGroup.getRead().getErrorCount() > 0) {
log.info("KnxGroup recovered from read-error: {}", knxGroup);
}
knxGroup.getRead().setErrorCount(0);
knxGroup.getRead().setErrorMessage(null);
knxGroup.getRead().setNextTimestamp(null);
log.debug("Successfully sent KnxGroup: {}", knxGroup);
return true;
} catch (KNXTimeoutException | KNXFormatException e) {
log.error("Failed to read KnxGroup {}", knxGroup);
knxGroup.getRead().setErrorCount(knxGroup.getRead().getErrorCount() + 1);
knxGroup.getRead().setErrorMessage(e.getMessage());
knxGroup.getRead().setNextTimestamp(ZonedDateTime.now().plusNanos(knxGroup.getRead().getErrorCount() * knxGroup.getRead().getErrorCount() * ERROR_DELAY_FACTOR));
}
return false;
}
private StateDP createStateDP(final KnxGroup knxGroup) {
final GroupAddress groupAddress = knxGroup.getAddress();
return new StateDP(groupAddress, groupAddress.toString(), knxGroup.getDptMain(), knxGroup.getDpt());
}
public ZonedDateTime getNextTimestamp() {
final Optional<ZonedDateTime> sendOptional = knxGroupRepository.findFirstBySend_NextTimestampNotNullOrderBySend_NextTimestampAsc().map(KnxGroup::getSend).map(KnxGroupLinkInfo::getNextTimestamp);
final Optional<ZonedDateTime> readOptional = knxGroupRepository.findFirstByRead_NextTimestampNotNullOrderByRead_NextTimestampAsc().map(KnxGroup::getRead).map(KnxGroupLinkInfo::getNextTimestamp);
if (sendOptional.isEmpty()) {
return readOptional.orElse(null);
}
final ZonedDateTime send = sendOptional.get();
if (readOptional.isEmpty()) {
return send;
}
final ZonedDateTime read = readOptional.get();
if (send.isBefore(read)) {
return send;
}
return read;
}
}