KnxLinkService working now
This commit is contained in:
commit
28cf4eed2e
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/target/
|
||||||
|
/.idea/
|
||||||
|
/.jpb/
|
||||||
|
/application.properties
|
||||||
160
pom.xml
Normal file
160
pom.xml
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>de.ph87</groupId>
|
||||||
|
<artifactId>Homeautomation</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.3.6.RELEASE</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.calimero</groupId>
|
||||||
|
<artifactId>calimero-core</artifactId>
|
||||||
|
<version>2.5-M1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.eirslett</groupId>
|
||||||
|
<artifactId>frontend-maven-plugin</artifactId>
|
||||||
|
<version>1.10.3</version>
|
||||||
|
<configuration>
|
||||||
|
<workingDirectory>src/main/angular</workingDirectory>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>install-node-and-npm</id>
|
||||||
|
<goals>
|
||||||
|
<goal>install-node-and-npm</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<nodeVersion>v14.15.5</nodeVersion>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>npm install</id>
|
||||||
|
<goals>
|
||||||
|
<goal>npm</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<arguments>install</arguments>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>npm build</id>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>npm</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<arguments>run build</arguments>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>copy-resources</id>
|
||||||
|
<phase>process-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>copy-resources</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<outputDirectory>target/classes/resources/</outputDirectory>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/angular/dist/angular/</directory>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<classifier>spring-boot</classifier>
|
||||||
|
<mainClass>
|
||||||
|
de.ph87.de.ph87.homeautomation.BackendApplication
|
||||||
|
</mainClass>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>11</source>
|
||||||
|
<target>11</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
54
src/main/java/de/ph87/homeautomation/BackendApplication.java
Normal file
54
src/main/java/de/ph87/homeautomation/BackendApplication.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package de.ph87.homeautomation;
|
||||||
|
|
||||||
|
import de.ph87.homeautomation.knx.KnxLinkService;
|
||||||
|
import de.ph87.homeautomation.knx.group.KnxGroup;
|
||||||
|
import de.ph87.homeautomation.knx.group.KnxGroupRepository;
|
||||||
|
import de.ph87.homeautomation.knx.group.KnxGroupWriteService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class BackendApplication {
|
||||||
|
|
||||||
|
private final KnxGroupRepository knxGroupRepository;
|
||||||
|
|
||||||
|
private final KnxLinkService knxLinkService;
|
||||||
|
|
||||||
|
private final KnxGroupWriteService knxGroupWriteService;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(BackendApplication.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void postConstruct() {
|
||||||
|
knxGroupCreate(0, 0, 1, "1.001");
|
||||||
|
knxGroupCreate(0, 3, 6, "1.001");
|
||||||
|
|
||||||
|
requestAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void knxGroupCreate(final int main, final int middle, final int sub, final String dpt) {
|
||||||
|
final KnxGroup trans = new KnxGroup();
|
||||||
|
trans.setAddress(main, middle, sub);
|
||||||
|
trans.setDpt(dpt);
|
||||||
|
knxGroupRepository.save(trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestAll() {
|
||||||
|
knxGroupWriteService.markAllForRead();
|
||||||
|
knxLinkService.notifyActionPending();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener(ApplicationStartedEvent.class)
|
||||||
|
public void applicationStarted() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
185
src/main/java/de/ph87/homeautomation/knx/KnxLinkService.java
Normal file
185
src/main/java/de/ph87/homeautomation/knx/KnxLinkService.java
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
package de.ph87.homeautomation.knx;
|
||||||
|
|
||||||
|
import de.ph87.homeautomation.knx.group.KnxGroupLinkService;
|
||||||
|
import de.ph87.homeautomation.knx.group.KnxGroupWriteService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import tuwien.auto.calimero.CloseEvent;
|
||||||
|
import tuwien.auto.calimero.DetachEvent;
|
||||||
|
import tuwien.auto.calimero.FrameEvent;
|
||||||
|
import tuwien.auto.calimero.KNXException;
|
||||||
|
import tuwien.auto.calimero.link.KNXNetworkLinkIP;
|
||||||
|
import tuwien.auto.calimero.link.NetworkLinkListener;
|
||||||
|
import tuwien.auto.calimero.link.medium.TPSettings;
|
||||||
|
import tuwien.auto.calimero.process.ProcessCommunicatorImpl;
|
||||||
|
import tuwien.auto.calimero.process.ProcessEvent;
|
||||||
|
import tuwien.auto.calimero.process.ProcessListener;
|
||||||
|
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class KnxLinkService implements NetworkLinkListener, ProcessListener {
|
||||||
|
|
||||||
|
public static final int ERROR_DELAY_MS = 3000;
|
||||||
|
|
||||||
|
private final KnxGroupWriteService knxGroupWriteService;
|
||||||
|
|
||||||
|
private final KnxGroupLinkService knxGroupLinkService;
|
||||||
|
|
||||||
|
private InetAddress remoteAddress = null;
|
||||||
|
|
||||||
|
private final Thread thread = new Thread(this::run);
|
||||||
|
|
||||||
|
private boolean stop = false;
|
||||||
|
|
||||||
|
private KNXNetworkLinkIP link = null;
|
||||||
|
|
||||||
|
private ProcessCommunicatorImpl processCommunicator = null;
|
||||||
|
|
||||||
|
private final Object lock = new Object();
|
||||||
|
|
||||||
|
@EventListener(ApplicationStartedEvent.class)
|
||||||
|
public void afterStartup() throws UnknownHostException {
|
||||||
|
remoteAddress = Inet4Address.getByName("10.0.0.102");
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void preDestroy() {
|
||||||
|
stop = true;
|
||||||
|
final KNXNetworkLinkIP copy = link;
|
||||||
|
if (copy != null) {
|
||||||
|
copy.close();
|
||||||
|
}
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void run() {
|
||||||
|
try {
|
||||||
|
while (!stop) {
|
||||||
|
if (link == null) {
|
||||||
|
try {
|
||||||
|
connect();
|
||||||
|
} catch (KNXException e) {
|
||||||
|
error(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
work();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
log.info("KNX Thread terminated.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connect() throws KNXException, InterruptedException {
|
||||||
|
log.debug("Connecting KNX link...");
|
||||||
|
link = KNXNetworkLinkIP.newTunnelingLink(new InetSocketAddress("10.0.0.132", 0), new InetSocketAddress(remoteAddress, 3671), false, new TPSettings());
|
||||||
|
link.addLinkListener(this);
|
||||||
|
processCommunicator = new ProcessCommunicatorImpl(link);
|
||||||
|
processCommunicator.addProcessListener(this);
|
||||||
|
log.info("KNX link established.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void work() throws InterruptedException {
|
||||||
|
try {
|
||||||
|
if (!knxGroupLinkService.sendNext(processCommunicator) && !knxGroupLinkService.readNext(processCommunicator)) {
|
||||||
|
final ZonedDateTime nextTimestamp = knxGroupLinkService.getNextTimestamp();
|
||||||
|
if (nextTimestamp == null) {
|
||||||
|
doWait(0);
|
||||||
|
} else {
|
||||||
|
final long waitMs = Duration.between(ZonedDateTime.now(), nextTimestamp).toMillis();
|
||||||
|
if (waitMs > 0) {
|
||||||
|
doWait(waitMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (KNXException e) {
|
||||||
|
error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void error(final KNXException e) throws InterruptedException {
|
||||||
|
log.error(e.toString());
|
||||||
|
cleanUp();
|
||||||
|
doWait(ERROR_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doWait(final long waitMs) throws InterruptedException {
|
||||||
|
synchronized (lock) {
|
||||||
|
log.debug("KNX Thread going to sleep{}...", waitMs > 0 ? " for " + waitMs + "ms" : "");
|
||||||
|
if (waitMs > 0) {
|
||||||
|
lock.wait(waitMs);
|
||||||
|
} else {
|
||||||
|
lock.wait();
|
||||||
|
}
|
||||||
|
log.debug("KNX Thread woke up.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanUp() {
|
||||||
|
if (link != null) {
|
||||||
|
link.close();
|
||||||
|
link = null;
|
||||||
|
processCommunicator = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyActionPending() {
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void confirmation(final FrameEvent e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void indication(final FrameEvent e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void linkClosed(final CloseEvent e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void groupReadResponse(final ProcessEvent processEvent) {
|
||||||
|
log.debug("{}", processEvent);
|
||||||
|
knxGroupWriteService.updateOrCreate(processEvent.getDestination().getRawAddress(), processEvent.getASDU());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void groupWrite(final ProcessEvent processEvent) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void groupReadRequest(final ProcessEvent processEvent) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void detached(final DetachEvent detachEvent) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
24
src/main/java/de/ph87/homeautomation/knx/group/ComInfo.java
Normal file
24
src/main/java/de/ph87/homeautomation/knx/group/ComInfo.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package de.ph87.homeautomation.knx.group;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@Embeddable
|
||||||
|
public class ComInfo {
|
||||||
|
|
||||||
|
private boolean able = true;
|
||||||
|
|
||||||
|
private ZonedDateTime nextTimestamp = null;
|
||||||
|
|
||||||
|
private int errorCount = 0;
|
||||||
|
|
||||||
|
private String errorMessage = null;
|
||||||
|
|
||||||
|
}
|
||||||
84
src/main/java/de/ph87/homeautomation/knx/group/KnxGroup.java
Normal file
84
src/main/java/de/ph87/homeautomation/knx/group/KnxGroup.java
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package de.ph87.homeautomation.knx.group;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tuwien.auto.calimero.GroupAddress;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@Entity
|
||||||
|
public class KnxGroup {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
@Setter(AccessLevel.NONE)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(unique = true)
|
||||||
|
private int addressRaw;
|
||||||
|
|
||||||
|
@Column(unique = true)
|
||||||
|
private String addressStr;
|
||||||
|
|
||||||
|
private String dpt;
|
||||||
|
|
||||||
|
private byte[] value;
|
||||||
|
|
||||||
|
private ZonedDateTime valueTimestamp;
|
||||||
|
|
||||||
|
private byte[] sendValue;
|
||||||
|
|
||||||
|
private int readInterval;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private ComInfo read = new ComInfo();
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private ComInfo send = new ComInfo();
|
||||||
|
|
||||||
|
public void setAddress(final int rawAddress) {
|
||||||
|
setAddress(new GroupAddress(rawAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(final int main, final int middle, final int sub) {
|
||||||
|
setAddress(new GroupAddress(main, middle, sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(final GroupAddress groupAddress) {
|
||||||
|
this.addressRaw = groupAddress.getRawAddress();
|
||||||
|
this.addressStr = groupAddress.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupAddress getAddress() {
|
||||||
|
return new GroupAddress(addressRaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReadInterval(final int readInterval) {
|
||||||
|
if (readInterval <= 0) {
|
||||||
|
this.readInterval = 0;
|
||||||
|
} else {
|
||||||
|
this.readInterval = readInterval;
|
||||||
|
if (read.getNextTimestamp() == null || Duration.between(ZonedDateTime.now(), read.getNextTimestamp()).toSeconds() > this.readInterval) {
|
||||||
|
updateNextReadTimestamp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateNextReadTimestamp() {
|
||||||
|
if (read.getErrorCount() == 0) {
|
||||||
|
if (this.readInterval <= 0) {
|
||||||
|
read.setNextTimestamp(null);
|
||||||
|
} else {
|
||||||
|
read.setNextTimestamp(ZonedDateTime.now().plusSeconds(read.getNextTimestamp() == null ? 0 : this.readInterval));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
package de.ph87.homeautomation.knx.group;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import tuwien.auto.calimero.GroupAddress;
|
||||||
|
import tuwien.auto.calimero.KNXException;
|
||||||
|
import tuwien.auto.calimero.KNXFormatException;
|
||||||
|
import tuwien.auto.calimero.datapoint.StateDP;
|
||||||
|
import tuwien.auto.calimero.dptxlator.TranslatorTypes;
|
||||||
|
import tuwien.auto.calimero.process.ProcessCommunicatorImpl;
|
||||||
|
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class KnxGroupLinkService {
|
||||||
|
|
||||||
|
private final KnxGroupRepository knxGroupRepository;
|
||||||
|
|
||||||
|
public boolean sendNext(final ProcessCommunicatorImpl processCommunicator) throws KNXException {
|
||||||
|
final Optional<KnxGroup> knxGroupOptional = knxGroupRepository.findFirstBySend_NextTimestampNotNullOrderBySend_NextTimestampAsc();
|
||||||
|
if (knxGroupOptional.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return send(processCommunicator, knxGroupOptional.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean readNext(final ProcessCommunicatorImpl processCommunicator) throws KNXException, InterruptedException {
|
||||||
|
final Optional<KnxGroup> knxGroupOptional = knxGroupRepository.findFirstByRead_NextTimestampLessThanEqualOrderByRead_NextTimestampAsc(ZonedDateTime.now());
|
||||||
|
if (knxGroupOptional.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return read(processCommunicator, knxGroupOptional.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.getDpt(), knxGroup.getSendValue()));
|
||||||
|
knxGroup.getSend().setErrorCount(0);
|
||||||
|
knxGroup.getSend().setErrorMessage(null);
|
||||||
|
knxGroup.getSend().setNextTimestamp(null);
|
||||||
|
log.debug("Successfully sent KnxGroup: {}", knxGroup);
|
||||||
|
return true;
|
||||||
|
} catch (KNXFormatException e) {
|
||||||
|
log.error(e.toString());
|
||||||
|
knxGroup.getSend().setErrorCount(knxGroup.getSend().getErrorCount() + 1);
|
||||||
|
knxGroup.getSend().setErrorMessage(e.toString());
|
||||||
|
knxGroup.getSend().setNextTimestamp(ZonedDateTime.now().plusSeconds(knxGroup.getSend().getErrorCount()));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean read(final ProcessCommunicatorImpl processCommunicator, final KnxGroup knxGroup) throws KNXException, InterruptedException {
|
||||||
|
try {
|
||||||
|
log.debug("Reading KnxGroup: {}", knxGroup);
|
||||||
|
processCommunicator.read(createStateDP(knxGroup));
|
||||||
|
knxGroup.getRead().setErrorCount(0);
|
||||||
|
knxGroup.getRead().setErrorMessage(null);
|
||||||
|
return true;
|
||||||
|
} catch (KNXFormatException e) {
|
||||||
|
log.error(e.toString());
|
||||||
|
knxGroup.getRead().setErrorCount(knxGroup.getRead().getErrorCount() + 1);
|
||||||
|
knxGroup.getRead().setErrorMessage(e.toString());
|
||||||
|
} finally {
|
||||||
|
knxGroup.updateNextReadTimestamp();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StateDP createStateDP(final KnxGroup knxGroup) {
|
||||||
|
final GroupAddress groupAddress = knxGroup.getAddress();
|
||||||
|
final int mainNumber = Integer.parseInt(knxGroup.getDpt().split("\\.", 2)[0]);
|
||||||
|
return new StateDP(groupAddress, groupAddress.toString(), mainNumber, knxGroup.getDpt());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZonedDateTime getNextTimestamp() {
|
||||||
|
if (knxGroupRepository.findFirstBySend_NextTimestampNotNullOrderBySend_NextTimestampAsc().isPresent()) {
|
||||||
|
return ZonedDateTime.now();
|
||||||
|
}
|
||||||
|
return knxGroupRepository.findFirstByRead_NextTimestampNotNullOrderByRead_NextTimestampAsc().map(KnxGroup::getRead).map(ComInfo::getNextTimestamp).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package de.ph87.homeautomation.knx.group;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface KnxGroupRepository extends CrudRepository<KnxGroup, Long> {
|
||||||
|
|
||||||
|
Optional<KnxGroup> findByAddressRaw(int rawAddress);
|
||||||
|
|
||||||
|
List<KnxGroup> findAll();
|
||||||
|
|
||||||
|
Optional<KnxGroup> findFirstBySend_NextTimestampNotNullOrderBySend_NextTimestampAsc();
|
||||||
|
|
||||||
|
Optional<KnxGroup> findFirstByRead_NextTimestampLessThanEqualOrderByRead_NextTimestampAsc(ZonedDateTime timestamp);
|
||||||
|
|
||||||
|
List<KnxGroup> findAllByRead_AbleTrue();
|
||||||
|
|
||||||
|
Optional<KnxGroup> findFirstByRead_NextTimestampNotNullOrderByRead_NextTimestampAsc();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package de.ph87.homeautomation.knx.group;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
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());
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markAllForRead() {
|
||||||
|
knxGroupRepository.findAllByRead_AbleTrue().forEach(knxGroup -> knxGroup.getRead().setNextTimestamp(ZonedDateTime.now()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
17
src/main/resources/application.properties
Normal file
17
src/main/resources/application.properties
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
logging.level.root=WARN
|
||||||
|
logging.level.de.ph87=INFO
|
||||||
|
#-
|
||||||
|
spring.datasource.url=jdbc:h2:./Homeautomation;AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=FALSE
|
||||||
|
spring.datasource.driverClassName=org.h2.Driver
|
||||||
|
spring.datasource.username=sa
|
||||||
|
spring.datasource.password=password
|
||||||
|
#-
|
||||||
|
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl
|
||||||
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
|
spring.jpa.open-in-view=false
|
||||||
|
#-
|
||||||
|
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||||
|
#-
|
||||||
|
spring.jackson.serialization.indent_output=true
|
||||||
|
#-
|
||||||
|
spring.main.banner-mode=off
|
||||||
Loading…
Reference in New Issue
Block a user