Merge branch 'old_lib' into 'master'

Working version of modbus integration wiht frisko module

See merge request mariusz.pacek/home-pump!1
This commit is contained in:
root committed 2022-04-09 19:00:15 +00:00
commit f801e98554
33 files changed
+762 -254

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
# This file is a template, and might need editing before it works on your project.
include:
template: Jobs/Code-Quality.gitlab-ci.yml
+10
View File
@@ -6,6 +6,11 @@
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="ias-snapshots" />
<option name="name" value="Infinite Automation Snapshot Repository" />
<option name="url" value="https://maven.mangoautomation.net/repository/ias-snapshot/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
@@ -16,5 +21,10 @@
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="ias-releases" />
<option name="name" value="Infinite Automation Release Repository" />
<option name="url" value="https://maven.mangoautomation.net/repository/ias-release/" />
</remote-repository>
</component>
</project>
+1 -1
View File
@@ -8,7 +8,7 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="openjdk-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
+81 -46
View File
@@ -3,57 +3,92 @@
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>org.example</groupId>
<artifactId>test.com</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
<dependency>
<groupId>com.digitalpetri.modbus</groupId>
<artifactId>modbus-master-tcp</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
<dependency>
<groupId>com.infiniteautomation</groupId>
<artifactId>modbus4j</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.influxdb</groupId>
<artifactId>influxdb-java</artifactId>
<version>2.22</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<repositories>
<repository>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
<id>ias-snapshots</id>
<name>Infinite Automation Snapshot Repository</name>
<url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
</repository>
<repository>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>ias-releases</id>
<name>Infinite Automation Release Repository</name>
<url>https://maven.mangoautomation.net/repository/ias-release/</url>
</repository>
</repositories>
</project>
+37 -15
View File
@@ -1,28 +1,50 @@
package home.automation;
import home.automation.configuration.JsonFileBasedConfiguration;
import home.automation.configuration.RegistryMapping;
import home.automation.influxdb.InfluxConnection;
import home.automation.influxdb.InfluxMetricModbusSender;
import home.automation.modbus.ModbusConnection;
import home.automation.modbus.ModbusRtuTcpRepository;
import home.automation.modbus.Registry;
import home.automation.modbus.SDMService;
import home.automation.modbus.configuration.JsonFileBasedConfiguration;
import home.automation.modbus.configuration.RegistryMapping;
import home.automation.modbus.ModbusService;
import lombok.*;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws Exception {
final JsonFileBasedConfiguration jsonFileBasedConfiguration = new JsonFileBasedConfiguration();
final List<RegistryMapping> registryMappings = jsonFileBasedConfiguration.getConfig().get().getRegistry_mapping();
SDMService service = new SDMService(new ModbusRtuTcpRepository(new ModbusConnection(new JsonFileBasedConfiguration()), registryMappings));
jsonFileBasedConfiguration.getConfig().get().getRegistry_mapping().stream().mapToInt(RegistryMapping::getRegistry).forEach(number -> {
try {
System.out.println(service.get(number));
} catch (ExecutionException e) {
e.printStackTrace();
}
});
final JsonFileBasedConfiguration jsonFileBasedConfiguration = new JsonFileBasedConfiguration();
final List<RegistryMapping> registryMappings = jsonFileBasedConfiguration
.getConfig()
.orElseThrow(() -> new Exception("Missing configuration file"))
.getRegistry_mapping();
final InfluxConnection connection = new InfluxConnection(
jsonFileBasedConfiguration.getConfig()
.get()
.getInflux_db()
);
ModbusService service = new ModbusService(
new ModbusRtuTcpRepository(
new ModbusConnection(
new JsonFileBasedConfiguration()
), registryMappings)
);
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(
new InfluxMetricModbusSender(connection.getConnection(), service),
0,
1,
TimeUnit.MINUTES
);
}
}
@@ -1,4 +1,4 @@
package home.automation.modbus.configuration;
package home.automation.configuration;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -14,8 +14,8 @@ public interface ConfigurationStrategy {
try {
return Optional.of(mapper.readValue(json, RegistryConfiguration.class));
} catch (JsonProcessingException e) {
e.printStackTrace();
return Optional.empty();
}
}
}
@@ -0,0 +1,24 @@
package home.automation.configuration;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.Objects;
@Getter
@Setter
@ToString
public class InfluxDBConfiguration {
private String address;
private String password;
private String username;
public String getPassword() {
return Objects.isNull(password) ? "" : password;
}
public String getUsername() {
return Objects.isNull(username) ? "" : username;
}
}
@@ -1,4 +1,4 @@
package home.automation.modbus.configuration;
package home.automation.configuration;
import java.io.IOException;
import java.io.InputStream;
@@ -14,7 +14,7 @@ public class JsonFileBasedConfiguration implements ConfigurationStrategy {
public Optional<RegistryConfiguration> getConfig() {
final InputStream resource = Thread.currentThread().getContextClassLoader().getResourceAsStream(CONFIGURATION_NAME);
Objects.requireNonNull(resource, "Configuration file not present please check the path:" + System.getProperty("usr.dir"));
String jsonConfiguration = null;
String jsonConfiguration;
try {
jsonConfiguration = new String(resource.readAllBytes(), UTF_8);
} catch (IOException e) {
@@ -0,0 +1,18 @@
package home.automation.configuration;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.net.InetAddress;
import java.util.List;
@ToString
@Getter
@Setter
public class RegistryConfiguration {
private InetAddress address;
private Integer port;
private InfluxDBConfiguration influx_db;
private List<RegistryMapping> registry_mapping;
}
@@ -0,0 +1,14 @@
package home.automation.configuration;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@ToString
@Getter
@Setter
public class RegistryMapping {
private Integer registry;
private String desc;
}
@@ -0,0 +1,26 @@
package home.automation.influxdb;
import home.automation.configuration.InfluxDBConfiguration;
import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBFactory;
public class InfluxConnection {
private final InfluxDB connection;
public InfluxConnection(InfluxDBConfiguration configuration) {
if (configuration.getUsername().isBlank()) {
this.connection = InfluxDBFactory.connect(configuration.getAddress());
} else {
this.connection = InfluxDBFactory.connect(
configuration.getAddress(),
configuration.getUsername(),
configuration.getPassword()
);
}
Runtime.getRuntime().addShutdownHook(new Thread(connection::close));
}
public InfluxDB getConnection() {
return connection;
}
}
@@ -0,0 +1,46 @@
package home.automation.influxdb;
import home.automation.modbus.ModbusService;
import home.automation.modbus.Registry;
import org.influxdb.InfluxDB;
import org.influxdb.dto.Point;
import org.influxdb.dto.Query;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class InfluxMetricModbusSender implements MetricSender<Registry>, Runnable {
private final ModbusService modbusService;
private final InfluxDB influxConnection;
public InfluxMetricModbusSender(InfluxDB connection, ModbusService service) {
this.modbusService = service;
this.influxConnection = connection;
connection.enableBatch();
connection.enableGzip();
String databaseName = "Dom_Pompa";
connection.query(new Query("CREATE DATABASE " + databaseName));
connection.setDatabase(databaseName);
connection.setLogLevel(InfluxDB.LogLevel.FULL);
}
@Override
public boolean send(List<Registry> metricsToSend) {
modbusService.readAll().forEach(registry ->
influxConnection.write(
Point.measurement("POMPA")
.addField(registry.getDesc(), Double.valueOf(registry.getValue()))
.time(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
.build()
)
);
influxConnection.flush();
return true;
}
@Override
public void run() {
final List<Registry> registries = modbusService.readAll();
send(registries);
}
}
@@ -0,0 +1,7 @@
package home.automation.influxdb;
import java.util.List;
public interface MetricSender<T> {
boolean send(List<T> metricToSend);
}
@@ -0,0 +1,7 @@
package home.automation.modbus;
import com.serotonin.modbus4j.ModbusMaster;
public interface Connection {
ModbusMaster getConnection() throws Exception;
}
@@ -0,0 +1,50 @@
package home.automation.modbus;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.ExecutionException;
import static home.automation.modbus.Registry.builder;
import static java.util.Collections.singletonList;
@Slf4j
public class ModbusCachedWrapper implements Repository {
private final Cache<Integer, Registry> repositoryCache;
private final Cache<Integer, List<Registry>> repositoryCacheAllElements;
private final Repository repository;
public static final int ALL_ELEMENTS = 1;
public ModbusCachedWrapper(Repository repository, Duration prevenstionTime) {
this.repository = repository;
repositoryCacheAllElements = CacheBuilder.newBuilder()
.expireAfterWrite(prevenstionTime)
.build();
repositoryCache = CacheBuilder.newBuilder()
.expireAfterWrite(prevenstionTime)
.build();
}
@Override
public List<Registry> getAll() {
try {
return repositoryCacheAllElements.get(ALL_ELEMENTS, repository::getAll);
} catch (ExecutionException e) {
log.error("Cannot get all keys due to: ", e);
return singletonList(builder().registry(0).desc("").value("").build());
}
}
@Override
public Registry get(int register) {
try {
return repositoryCache.get(register, () -> repository.get(register));
} catch (ExecutionException e) {
log.error("Cannot get" + register + "due to: ", e);
return builder().registry(0).desc("").value("").build();
}
}
}
@@ -1,41 +1,55 @@
package home.automation.modbus;
import com.digitalpetri.modbus.master.ModbusTcpMaster;
import com.digitalpetri.modbus.master.ModbusTcpMasterConfig;
import home.automation.modbus.configuration.ConfigurationStrategy;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.ip.IpParameters;
import home.automation.configuration.ConfigurationStrategy;
import java.net.InetAddress;
import java.time.Duration;
import java.util.Objects;
public class ModbusConnection {
ConfigurationStrategy config;
private volatile ModbusTcpMaster connection;
import static java.util.Objects.isNull;
public ModbusConnection(ConfigurationStrategy config) throws Exception {
public class ModbusConnection implements Connection {
private final ConfigurationStrategy config;
private volatile ModbusMaster connection;
public ModbusConnection(ConfigurationStrategy config) {
this.config = config;
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (Objects.nonNull(connection)) {
connection.destroy();
}
}));
}
private Pair<InetAddress, Integer> getPortAndAddresFromConfig(ConfigurationStrategy config) {
private Pair<InetAddress, Integer> getPortAndAddressFromConfig(ConfigurationStrategy config) {
return config.getConfig()
.map(registryCon -> new Pair<>(registryCon.getAddress(), registryCon.getPort()))
.orElseThrow(() -> new RuntimeException("Missing configuration"));
}
synchronized public ModbusTcpMaster getConnection() throws Exception {
final Pair<InetAddress, Integer> portAndAddresFromConfig = getPortAndAddresFromConfig(config);
this.connection = initConnection(portAndAddresFromConfig.getFirst(), portAndAddresFromConfig.getSecond());
@Override
synchronized public ModbusMaster getConnection() throws Exception {
if (isNull(connection) || !connection.isConnected()) {
if (Objects.nonNull(connection)) {
connection.destroy();
}
final Pair<InetAddress, Integer> portAndAddressFromConfig = getPortAndAddressFromConfig(config);
this.connection = initConnection(portAndAddressFromConfig.getFirst(), portAndAddressFromConfig.getSecond());
}
return connection;
}
private ModbusTcpMaster initConnection(InetAddress address, int port) throws Exception {
private ModbusMaster initConnection(InetAddress address, int port) throws Exception {
final String ip = address.getHostAddress();
IpParameters ipParameters = new IpParameters();
ipParameters.setHost(ip);
ipParameters.setPort(port);
ModbusFactory factory = new ModbusFactory();
final ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder(ip).setPort(port).setTimeout(Duration.ofSeconds(5)).build();
ModbusTcpMaster connection = new ModbusTcpMaster(config);
connection.connect();
return connection;
final ModbusMaster tcpMaster = factory.createTcpMaster(ipParameters, true);
tcpMaster.init();
return tcpMaster;
}
}
@@ -1,88 +1,96 @@
package home.automation.modbus;
import com.digitalpetri.modbus.master.ModbusTcpMaster;
import com.digitalpetri.modbus.requests.ReadHoldingRegistersRequest;
import com.digitalpetri.modbus.responses.ReadHoldingRegistersResponse;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import home.automation.modbus.configuration.RegistryMapping;
import io.netty.buffer.ByteBufUtil;
import io.netty.util.ReferenceCountUtil;
import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersRequest;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse;
import home.automation.configuration.RegistryMapping;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class ModbusRtuTcpRepository {
private final LoadingCache<Integer, Registry> repositoryCache;
private final ModbusConnection connection;
import static com.serotonin.modbus4j.code.DataType.TWO_BYTE_INT_SIGNED;
public class ModbusRtuTcpRepository implements Repository {
private static final int ZERO = 0;
private static final int HALF_SHORT_INT = 32768;
private final Connection connection;
private final List<RegistryMapping> registryMappings;
public ModbusRtuTcpRepository(ModbusConnection connection, List<RegistryMapping> mappings) throws Exception {
public ModbusRtuTcpRepository(Connection connection, List<RegistryMapping> mappings) {
this.connection = connection;
this.registryMappings = mappings;
CacheLoader<Integer, Registry> loader = configureCacheLoader();
repositoryCache = CacheBuilder.newBuilder()
.refreshAfterWrite(5, TimeUnit.SECONDS)
.build(loader);
}
private CacheLoader<Integer, Registry> configureCacheLoader() {
return new CacheLoader<>() {
@Override
public Registry load(Integer registerNumber) throws Exception {
final ModbusTcpMaster connection = ModbusRtuTcpRepository.this.connection.getConnection();
try {
final CompletableFuture<ReadHoldingRegistersResponse> modbusResponseCompletableFuture = connection.sendRequest(new ReadHoldingRegistersRequest(0, 10), 0);
modbusResponseCompletableFuture.whenCompleteAsync((response, ex) -> {
if (Objects.nonNull(response)) {
System.out.println(ByteBufUtil.hexDump(response.getRegisters()));
ReferenceCountUtil.release(response);
}
}, Executors.newSingleThreadExecutor());
modbusResponseCompletableFuture.get();
// .findFirst()
// .map(register -> Registry
// .builder()
// .registry(registerNumber)
// .desc(registryMappings
// .stream()
// .filter(elem -> elem.getRegistry().equals(registerNumber))
// .findFirst()
// .map(RegistryMapping::getDesc)
// .orElse("Uknow registry number"))
// .value(normalizeRegistryValue(register))
// .build());
// return registryMeasurement.orElse(null);
} finally {
connection.disconnect();
}
return new Registry(1, "test", "test");
}
};
private String normalizeRegistryValue(Short value) {
if (ZERO > value) {
return String.valueOf(-(value + HALF_SHORT_INT) / 10.0);
} else {
return String.valueOf((value / 10.0));
}
}
//
// private String normalizeRegistryValue(Register reg) {
// float v = reg.toShort();
// if (v < 0) {
// return String.valueOf(-(v + 32768) / 10);
// } else {
// return String.valueOf((reg.getValue() / 10.0));
// }
// }
@Override
public List<Registry> getAll() {
return (List<Registry>) repositoryCache.asMap().values();
BatchRead<Integer> requestBatchRead = new BatchRead<>();
registryMappings.forEach(elem -> requestBatchRead.addLocator(
elem.getRegistry(),
BaseLocator.holdingRegister(1, elem.getRegistry(), TWO_BYTE_INT_SIGNED)
));
try {
final BatchResults<Integer> send = connection.getConnection().send(requestBatchRead);
return registryMappings.stream()
.map(mapping -> {
final Double doubleValue = send.getDoubleValue(mapping.getRegistry());
return Registry.builder()
.registry(mapping.getRegistry())
.value(doubleValue.toString())
.desc(mapping.getDesc())
.build();
}
).collect(Collectors.toList());
} catch (Exception e) {
e.printStackTrace();
return Collections.emptyList();
}
}
public Registry get(int register) throws ExecutionException {
return repositoryCache.get(register);
@Override
public Registry get(int register) {
try {
ReadHoldingRegistersResponse response = getRegistry(register);
final String value = normalizeRegistryValue(response.getShortData()[0]);
final RegistryMapping mapping = findRegistryMapping(register);
return Registry.builder().registry(register)
.value(value)
.desc(mapping.getDesc())
.build();
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
@NotNull
private ReadHoldingRegistersResponse getRegistry(int register) throws Exception {
ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(1, register, 1);
ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) connection.getConnection().send(request);
if (response.isException()) {
throw new Exception(response.getExceptionMessage());
}
return response;
}
private RegistryMapping findRegistryMapping(int register) throws Exception {
return registryMappings.stream()
.filter(reg -> reg.getRegistry().equals(register))
.findFirst()
.orElseThrow(() -> new Exception("Missing registry mapping in configuration"));
}
}
@@ -0,0 +1,20 @@
package home.automation.modbus;
import java.util.List;
public class ModbusService {
private final Repository repository;
public ModbusService(Repository repository) {
this.repository = repository;
}
public List<Registry> readAll() {
return repository.getAll();
}
public Registry get(int register) {
return repository.get(register);
}
}
@@ -1,14 +1,13 @@
package home.automation.modbus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.*;
@Getter
@Setter
@Builder
@AllArgsConstructor
@ToString
public class Registry {
private Integer registry;
private String desc;
@@ -0,0 +1,9 @@
package home.automation.modbus;
import java.util.List;
public interface Repository {
List<Registry> getAll();
Registry get(int register);
}
@@ -1,23 +0,0 @@
package home.automation.modbus;
import home.automation.modbus.configuration.RegistryMapping;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class SDMService {
private final ModbusRtuTcpRepository repository;
public SDMService(ModbusRtuTcpRepository repository) throws Exception {
this.repository = repository;
}
public List<Registry> readAll() {
return repository.getAll();
}
public Registry get(int register) throws ExecutionException {
return repository.get(register);
}
}
@@ -1,41 +0,0 @@
package home.automation.modbus.configuration;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.ToString;
import java.net.InetAddress;
import java.util.List;
import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY;
@JsonInclude(NON_EMPTY)
@ToString
public class RegistryConfiguration {
private InetAddress address;
private Integer port;
private List<RegistryMapping> registry_mapping;
public InetAddress getAddress() {
return address;
}
public void setAddress(InetAddress address) {
this.address = address;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public List<RegistryMapping> getRegistry_mapping() {
return registry_mapping;
}
public void setRegistry_mapping(List<RegistryMapping> registry_mapping) {
this.registry_mapping = registry_mapping;
}
}
@@ -1,26 +0,0 @@
package home.automation.modbus.configuration;
import lombok.ToString;
@ToString
public class RegistryMapping {
private Integer registry;
private String desc;
public void setRegistry(Integer registry) {
this.registry = registry;
}
public Integer getRegistry() {
return registry;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
}
+41
View File
@@ -1,6 +1,11 @@
{
"address": "192.168.0.65",
"port": 502,
"influx_db": {
"address": "https://influxdb.mariuszpacek.pl",
"username": "",
"password": ""
},
"registry_mapping": [
{
"registry": 4065,
@@ -45,6 +50,42 @@
{
"registry": 4199,
"desc": "Temp zsr"
},
{
"registry": 4117,
"desc": "Pompa Dz"
},
{
"registry": 4113,
"desc": "Pompa BUF"
},
{
"registry": 4112,
"desc": "Pompa CO"
},
{
"registry": 4118,
"desc": "Pompa CWU"
},
{
"registry": 4114,
"desc": "Sprezarka"
},
{
"registry": 4115,
"desc": "GrzalkaCWU"
},
{
"registry": 4119,
"desc": "WyCHL"
},
{
"registry": 4116,
"desc": "Pompa CCW"
},
{
"registry": 4116,
"desc": "Pompa CCW"
}
]
}
@@ -0,0 +1,19 @@
package home.automation.configuration;
import home.automation.influxdb.InfluxConnection;
import org.influxdb.InfluxDB;
import org.junit.jupiter.api.Test;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InfluxConnectionTest {
@Test
public void givenConfigurationWhenInfluxPingThenConnectionIsAstablished() throws UnknownHostException {
final InfluxDBConfiguration connection = new InfluxDBConfiguration();
final InetAddress byName = InetAddress.getByName("https://influxdb.mariuszpacek.pl");
connection.setAddress(byName.getHostName());
final InfluxDB db = new InfluxConnection(connection).getConnection();
assert (db.ping().isGood());
}
}
@@ -1,17 +1,15 @@
package home.automation.modbus.configuration;
package home.automation.configuration;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.Optional;
class JsonFileBasedConfigurationTest {
@Test
public void GivenFileConfigurationStrategy_When_getConfig_Then_MappedClassShoudlBeCreated() throws IOException {
public void GivenFileConfigurationStrategy_When_getConfig_Then_MappedClassShoudlBeCreated() {
ConfigurationStrategy configuration = new JsonFileBasedConfiguration();
final Optional<RegistryConfiguration> config = configuration.getConfig();
assert (config.isPresent());
System.out.println(config.get());
}
}
@@ -0,0 +1,16 @@
package home.automation.modbus;
import com.serotonin.modbus4j.ModbusMaster;
public class MockConnection implements Connection {
private final ModbusMaster mock;
public MockConnection(ModbusMaster mockModbusMaster) {
this.mock = mockModbusMaster;
}
@Override
public ModbusMaster getConnection() throws Exception {
return mock;
}
}
@@ -0,0 +1,81 @@
package home.automation.modbus;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import java.util.List;
import static java.lang.Thread.sleep;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
class ModbusCachedWrapperTest {
public static final int MAX_TESTS = 10;
private final RepositoryInMemory repository = new RepositoryInMemory();
private final ModbusCachedWrapper cachedRepository = new ModbusCachedWrapper(repository, Duration.ofSeconds(1));
@Test
public void givenRepositoryInMemoryAndCacheDurationOf1Seconds_WhenGetRegistryFromCachedRepository2times_ThenValuesAreTheSame() {
final Registry firstTry = cachedRepository.get(4065);
final Registry secondTry = cachedRepository.get(4065);
assert (firstTry.getValue().equals(secondTry.getValue()));
}
@Test
public void givenRepositoryInMemoryAndCacheDurationOf1Seconds_WhenGetRegistryFromCachedRepository2timesWithDelayMoreThan1Sec_ThenValuesAreTheDifferent() throws InterruptedException {
final Registry firstTry = cachedRepository.get(4065);
final long currentTimeMillis = System.currentTimeMillis();
final long desireTimeoutInMs = 1000;
while (desireTimeoutInMs > System.currentTimeMillis() - currentTimeMillis) {
sleep(510);
}
final Registry secondTry = cachedRepository.get(4065);
assert (!firstTry.getValue().equals(secondTry.getValue()));
}
@Test
public void givenRepositoryInMemoryAndCacheDurationOf3Seconds_WhenGetRegistryFromCachedRepositoryMultipleTimesWithIn3SecondDelay_ThenAllValuesAreTheSame() throws InterruptedException {
final Registry firstTry = cachedRepository.get(4065);
final long currentTimeMillis = System.currentTimeMillis();
final long desireTimeoutInMs = 500;
int count = 0;
while (desireTimeoutInMs > System.currentTimeMillis() - currentTimeMillis || count == MAX_TESTS) {
count++;
final Registry secondTry = cachedRepository.get(4065);
assert (firstTry.getValue().equals(secondTry.getValue()));
}
}
@Test
public void givenRepositoryInMemoryAndCacheDurationOf3Seconds_WhenGetAllFromCachedRepository2times_ThenValuesAreTheSame() {
final List<Registry> firstTry = cachedRepository.getAll();
final List<Registry> secondTry = cachedRepository.getAll();
assertEquals(firstTry, secondTry);
}
@Test
public void givenRepositoryInMemoryAndCacheDurationOf3Seconds_WhenGetAllFromCachedRepository2timesWith4SecondDelay_ThenValuesAreTheDifferent() throws InterruptedException {
final List<Registry> firstTry = cachedRepository.getAll();
final long currentTimeMillis = System.currentTimeMillis();
final long desireTimeoutInMs = 1000;
while (desireTimeoutInMs > System.currentTimeMillis() - currentTimeMillis) {
sleep(510);
}
final List<Registry> secondTry = cachedRepository.getAll();
assertNotEquals(firstTry, secondTry);
}
@Test
public void givenRepositoryInMemoryAndCacheDurationOf3Seconds_WhenGetAllFromCachedRepositoryMultipleTimesWithIn3SecondDelay_ThenAllValuesAreTheSame() throws InterruptedException {
final List<Registry> firstTry = cachedRepository.getAll();
final long currentTimeMillis = System.currentTimeMillis();
final long desireTimeoutInMs = 500;
int count = 0;
while (desireTimeoutInMs > System.currentTimeMillis() - currentTimeMillis || count == MAX_TESTS) {
count++;
final List<Registry> secondTry = cachedRepository.getAll();
assertEquals(firstTry, secondTry);
}
}
}
@@ -0,0 +1,66 @@
package home.automation.modbus;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.msg.ModbusRequest;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse;
import home.automation.configuration.JsonFileBasedConfiguration;
import home.automation.configuration.RegistryMapping;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import static java.lang.Short.parseShort;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class ModbusRtuTcpRepositoryTest {
private ModbusRtuTcpRepository repository;
@Mock
private ModbusMaster modbusMaster;
@Mock
private ReadHoldingRegistersResponse response;
JsonFileBasedConfiguration configuration = new JsonFileBasedConfiguration();
@BeforeEach
public void setup() {
final List<RegistryMapping> registry_mapping = configuration.getConfig().get().getRegistry_mapping();
this.repository = new ModbusRtuTcpRepository(new MockConnection(modbusMaster), registry_mapping);
}
@Test
public void givenModbusRepositoryWhenGetRegistryValueIsNormalizedAndReturned() throws Exception {
when(response.isException()).thenReturn(false);
short[] returnValue = {parseShort("100")};
when(response.getShortData()).thenReturn(returnValue);
when(modbusMaster.send(any(ModbusRequest.class))).thenReturn(response);
assert ("10.0".equals(repository.get(4201).getValue()));
assert ("Set Temp wew".equals(repository.get(4201).getDesc()));
}
@Test
public void givenModbusRepositoryWhenGetRegistryIsNegativeValueIsNormalizedAndReturned() throws Exception {
when(response.isException()).thenReturn(false);
short[] returnValue = {parseShort("-32668")};
when(response.getShortData()).thenReturn(returnValue);
when(modbusMaster.send(any(ModbusRequest.class))).thenReturn(response);
assert ("-10.0".equals(repository.get(4201).getValue()));
assert ("Set Temp wew".equals(repository.get(4201).getDesc()));
}
@Test
public void givenModbusRepositoryWhenGetRegistryThenExecptionIsRised() throws Exception {
when(response.isException()).thenReturn(true);
short[] returnValue = {parseShort("-32668")};
when(modbusMaster.send(any(ModbusRequest.class))).thenReturn(response);
Assertions.assertThrowsExactly(RuntimeException.class,() -> "-10.0".equals(repository.get(4201).getValue()));
}
}
@@ -0,0 +1,28 @@
package home.automation.modbus;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ModbusServiceTest {
@Test
public void givenRegistryWhenGetRegistryThenValueFromRepositoryIsReturned(){
ModbusService service = new ModbusService(new RepositoryInMemory());
int givenRegistry = 4065;
final Registry registry = service.get(givenRegistry);
assertTrue(Objects.nonNull(registry));
}
@Test
public void givenNoRegistryWhenGetAllRegistryThenListOfValuesFromRepositoryIsReturned(){
ModbusService service = new ModbusService(new RepositoryInMemory());
final List<Registry> registry = service.readAll();
assertTrue(Objects.nonNull(registry));
assertFalse(registry.isEmpty());
}
}
@@ -0,0 +1,31 @@
package home.automation.modbus;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
public class RepositoryInMemory implements Repository {
private final List<Integer> DEFINED_REGISTRY_FOR_TEST =
Arrays.asList(4065, 4070, 4071, 4072, 4067, 4202, 4069, 4203, 4066, 4201, 4199);
@Override
public List<Registry> getAll() {
return DEFINED_REGISTRY_FOR_TEST.stream()
.map(this::generateRandomResponse)
.collect(Collectors.toList());
}
@Override
public Registry get(int register) {
return generateRandomResponse(register);
}
private Registry generateRandomResponse(int registry) {
final Random random = new Random();
return Registry.builder()
.registry(registry)
.value(Double.toString(random.nextDouble()))
.desc("TEST").build();
}
}
@@ -0,0 +1 @@
mock-maker-inline
+5
View File
@@ -1,6 +1,11 @@
{
"address": "192.168.0.62",
"port": 502,
"influx_db": {
"address":"influxdb.mariuszpacek.pl",
"username": "test",
"password": "1234"
},
"registry_mapping": [
{
"registry": 4065,