mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
If for some reason HP response fails to properly parse, i.e. java.lang.NumberFormatException: For input string: "##"
exception is not handled and scheduler is not re-triggered (polling stops).Fixed build warnings. (#13685)
Signed-off-by: Boris Krivonog <boris.krivonog@inova.si>
This commit is contained in:
parent
fe269b127a
commit
248ca1830a
@ -26,6 +26,8 @@ import java.util.Map;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
@ -34,6 +36,7 @@ import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
@ -45,13 +48,14 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
abstract class HusdataHandler extends BaseThingHandler {
|
||||
|
||||
private static final Map<Integer, String> MAPPINGS;
|
||||
private final Logger logger = LoggerFactory.getLogger(HusdataHandler.class);
|
||||
private RegoConnection connection;
|
||||
private ScheduledFuture<?> scheduledRefreshFuture;
|
||||
private BufferedReader bufferedReader;
|
||||
private @Nullable RegoConnection connection;
|
||||
private @Nullable ScheduledFuture<?> scheduledRefreshFuture;
|
||||
private @Nullable BufferedReader bufferedReader;
|
||||
|
||||
static {
|
||||
MAPPINGS = mappings();
|
||||
@ -61,12 +65,18 @@ abstract class HusdataHandler extends BaseThingHandler {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
protected abstract RegoConnection createConnection();
|
||||
protected abstract RegoConnection createConnection() throws IOException;
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
bufferedReader = null;
|
||||
connection = createConnection();
|
||||
|
||||
try {
|
||||
connection = createConnection();
|
||||
} catch (IOException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
@ -78,14 +88,16 @@ abstract class HusdataHandler extends BaseThingHandler {
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
||||
ScheduledFuture<?> scheduledRefreshFuture = this.scheduledRefreshFuture;
|
||||
this.scheduledRefreshFuture = null;
|
||||
if (scheduledRefreshFuture != null) {
|
||||
scheduledRefreshFuture.cancel(true);
|
||||
scheduledRefreshFuture = null;
|
||||
}
|
||||
|
||||
RegoConnection connection = this.connection;
|
||||
this.connection = null;
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,8 +124,10 @@ abstract class HusdataHandler extends BaseThingHandler {
|
||||
outputStream.flush();
|
||||
}
|
||||
|
||||
BufferedReader bufferedReader = this.bufferedReader;
|
||||
if (bufferedReader == null) {
|
||||
bufferedReader = new BufferedReader(new InputStreamReader(connection.inputStream()));
|
||||
this.bufferedReader = bufferedReader;
|
||||
}
|
||||
|
||||
final String line = bufferedReader.readLine();
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.IpRegoConnection;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
@ -23,6 +24,7 @@ import org.openhab.core.thing.Thing;
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class IpHusdataHandler extends HusdataHandler {
|
||||
public IpHusdataHandler(Thing thing) {
|
||||
super(thing);
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.IpRegoConnection;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
@ -23,6 +24,7 @@ import org.openhab.core.thing.Thing;
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class IpRego6xxHeatPumpHandler extends Rego6xxHeatPumpHandler {
|
||||
public IpRego6xxHeatPumpHandler(Thing thing) {
|
||||
super(thing);
|
||||
|
@ -29,6 +29,8 @@ import java.util.stream.Collectors;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
import org.openhab.binding.regoheatpump.internal.rego6xx.CommandFactory;
|
||||
import org.openhab.binding.regoheatpump.internal.rego6xx.ErrorLine;
|
||||
@ -60,13 +62,15 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
abstract class Rego6xxHeatPumpHandler extends BaseThingHandler {
|
||||
|
||||
private static final class ChannelDescriptor {
|
||||
private Date lastUpdate;
|
||||
private byte[] cachedValue;
|
||||
private @Nullable Date lastUpdate;
|
||||
private byte @Nullable [] cachedValue;
|
||||
|
||||
public byte[] cachedValueIfNotExpired(int refreshTime) {
|
||||
public byte @Nullable [] cachedValueIfNotExpired(int refreshTime) {
|
||||
Date lastUpdate = this.lastUpdate;
|
||||
if (lastUpdate == null || (lastUpdate.getTime() + refreshTime * 900 < new Date().getTime())) {
|
||||
return null;
|
||||
}
|
||||
@ -82,23 +86,27 @@ abstract class Rego6xxHeatPumpHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(Rego6xxHeatPumpHandler.class);
|
||||
private final Map<String, ChannelDescriptor> channelDescriptors = new HashMap<>();
|
||||
private final RegoRegisterMapper mapper = RegoRegisterMapper.REGO600;
|
||||
private @Nullable RegoConnection connection;
|
||||
private @Nullable ScheduledFuture<?> scheduledRefreshFuture;
|
||||
private int refreshInterval;
|
||||
private RegoConnection connection;
|
||||
private RegoRegisterMapper mapper;
|
||||
private ScheduledFuture<?> scheduledRefreshFuture;
|
||||
|
||||
protected Rego6xxHeatPumpHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
protected abstract RegoConnection createConnection();
|
||||
protected abstract RegoConnection createConnection() throws IOException;
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
mapper = RegoRegisterMapper.REGO600;
|
||||
refreshInterval = ((Number) getConfig().get(REFRESH_INTERVAL)).intValue();
|
||||
|
||||
connection = createConnection();
|
||||
try {
|
||||
connection = createConnection();
|
||||
} catch (IOException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
scheduledRefreshFuture = scheduler.scheduleWithFixedDelay(this::refresh, 2, refreshInterval, TimeUnit.SECONDS);
|
||||
|
||||
@ -109,21 +117,21 @@ abstract class Rego6xxHeatPumpHandler extends BaseThingHandler {
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
||||
RegoConnection connection = this.connection;
|
||||
this.connection = null;
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
|
||||
ScheduledFuture<?> scheduledRefreshFuture = this.scheduledRefreshFuture;
|
||||
this.scheduledRefreshFuture = null;
|
||||
if (scheduledRefreshFuture != null) {
|
||||
scheduledRefreshFuture.cancel(true);
|
||||
scheduledRefreshFuture = null;
|
||||
}
|
||||
|
||||
synchronized (channelDescriptors) {
|
||||
channelDescriptors.clear();
|
||||
}
|
||||
|
||||
connection = null;
|
||||
mapper = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -220,7 +228,7 @@ abstract class Rego6xxHeatPumpHandler extends BaseThingHandler {
|
||||
private void readAndUpdateLastError(String channelIID, Function<ErrorLine, State> converter) {
|
||||
executeCommandAndUpdateState(channelIID, CommandFactory.createReadLastErrorCommand(),
|
||||
ResponseParserFactory.ERROR_LINE, e -> {
|
||||
return e == null ? UnDefType.NULL : converter.apply(e);
|
||||
return e == ErrorLine.NO_ERROR ? UnDefType.NULL : converter.apply(e);
|
||||
});
|
||||
}
|
||||
|
||||
@ -252,7 +260,7 @@ abstract class Rego6xxHeatPumpHandler extends BaseThingHandler {
|
||||
});
|
||||
}
|
||||
|
||||
private synchronized <T> void executeCommand(String channelIID, byte[] command, ResponseParser<T> parser,
|
||||
private synchronized <T> void executeCommand(@Nullable String channelIID, byte[] command, ResponseParser<T> parser,
|
||||
Consumer<T> resultProcessor) {
|
||||
try {
|
||||
T result = executeCommandWithRetry(channelIID, command, parser, 5);
|
||||
@ -265,17 +273,19 @@ abstract class Rego6xxHeatPumpHandler extends BaseThingHandler {
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
} catch (Rego6xxProtocolException e) {
|
||||
} catch (Rego6xxProtocolException | RuntimeException e) {
|
||||
logger.warn("Executing command for channel '{}' failed.", channelIID, e);
|
||||
updateState(channelIID, UnDefType.UNDEF);
|
||||
if (channelIID != null) {
|
||||
updateState(channelIID, UnDefType.UNDEF);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
logger.debug("Execution interrupted when accessing value for channel '{}'.", channelIID, e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeCommandWithRetry(String channelIID, byte[] command, ResponseParser<T> parser, int retry)
|
||||
throws Rego6xxProtocolException, IOException, InterruptedException {
|
||||
private <T> T executeCommandWithRetry(@Nullable String channelIID, byte[] command, ResponseParser<T> parser,
|
||||
int retry) throws Rego6xxProtocolException, IOException, InterruptedException {
|
||||
try {
|
||||
checkRegoDevice();
|
||||
return executeCommand(channelIID, command, parser);
|
||||
@ -316,11 +326,12 @@ abstract class Rego6xxHeatPumpHandler extends BaseThingHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeCommand(String channelIID, byte[] command, ResponseParser<T> parser)
|
||||
private <T> T executeCommand(@Nullable String channelIID, byte[] command, ResponseParser<T> parser)
|
||||
throws Rego6xxProtocolException, IOException, InterruptedException {
|
||||
try {
|
||||
return executeCommandInternal(channelIID, command, parser);
|
||||
} catch (IOException e) {
|
||||
RegoConnection connection = this.connection;
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
@ -329,7 +340,7 @@ abstract class Rego6xxHeatPumpHandler extends BaseThingHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeCommandInternal(String channelIID, byte[] command, ResponseParser<T> parser)
|
||||
private <T> T executeCommandInternal(@Nullable String channelIID, byte[] command, ResponseParser<T> parser)
|
||||
throws Rego6xxProtocolException, IOException, InterruptedException {
|
||||
// CHANNEL_LAST_ERROR_CODE and CHANNEL_LAST_ERROR_TIMESTAMP are read from same
|
||||
// register. To prevent accessing same register twice when both channels are linked,
|
||||
@ -338,8 +349,12 @@ abstract class Rego6xxHeatPumpHandler extends BaseThingHandler {
|
||||
|| CHANNEL_LAST_ERROR_TIMESTAMP.equals(channelIID)) ? CHANNEL_LAST_ERROR : channelIID;
|
||||
|
||||
// Use transient channel descriptor for null (not cached) channels.
|
||||
ChannelDescriptor descriptor = channelIID == null ? new ChannelDescriptor()
|
||||
: channelDescriptorForChannel(mappedChannelIID);
|
||||
ChannelDescriptor descriptor;
|
||||
if (mappedChannelIID == null) {
|
||||
descriptor = new ChannelDescriptor();
|
||||
} else {
|
||||
descriptor = channelDescriptorForChannel(mappedChannelIID);
|
||||
}
|
||||
|
||||
byte[] cachedValue = descriptor.cachedValueIfNotExpired(refreshInterval);
|
||||
if (cachedValue != null) {
|
||||
@ -348,6 +363,11 @@ abstract class Rego6xxHeatPumpHandler extends BaseThingHandler {
|
||||
}
|
||||
|
||||
// Send command to device and wait for response.
|
||||
RegoConnection connection = this.connection;
|
||||
if (connection == null) {
|
||||
throw new IOException("Unable to execute command - no connection available");
|
||||
|
||||
}
|
||||
if (!connection.isConnected()) {
|
||||
connection.connect();
|
||||
}
|
||||
|
@ -12,6 +12,10 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.SerialRegoConnection;
|
||||
@ -27,9 +31,10 @@ import org.openhab.core.thing.ThingStatusDetail;
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SerialHusdataHandler extends HusdataHandler {
|
||||
private final SerialPortManager serialPortManager;
|
||||
private SerialPortIdentifier serialPortIdentifier;
|
||||
private @Nullable SerialPortIdentifier serialPortIdentifier;
|
||||
|
||||
public SerialHusdataHandler(Thing thing, SerialPortManager serialPortManager) {
|
||||
super(thing);
|
||||
@ -49,7 +54,11 @@ public class SerialHusdataHandler extends HusdataHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RegoConnection createConnection() {
|
||||
protected RegoConnection createConnection() throws IOException {
|
||||
SerialPortIdentifier serialPortIdentifier = this.serialPortIdentifier;
|
||||
if (serialPortIdentifier == null) {
|
||||
throw new IOException("Serial port does not exist");
|
||||
}
|
||||
return new SerialRegoConnection(serialPortIdentifier, 19200);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,10 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.SerialRegoConnection;
|
||||
@ -27,9 +31,10 @@ import org.openhab.core.thing.ThingStatusDetail;
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SerialRego6xxHeatPumpHandler extends Rego6xxHeatPumpHandler {
|
||||
private final SerialPortManager serialPortManager;
|
||||
private SerialPortIdentifier serialPortIdentifier;
|
||||
private @Nullable SerialPortIdentifier serialPortIdentifier;
|
||||
|
||||
public SerialRego6xxHeatPumpHandler(Thing thing, SerialPortManager serialPortManager) {
|
||||
super(thing);
|
||||
@ -49,7 +54,11 @@ public class SerialRego6xxHeatPumpHandler extends Rego6xxHeatPumpHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RegoConnection createConnection() {
|
||||
protected RegoConnection createConnection() throws IOException {
|
||||
SerialPortIdentifier serialPortIdentifier = this.serialPortIdentifier;
|
||||
if (serialPortIdentifier == null) {
|
||||
throw new IOException("Serial port does not exist");
|
||||
}
|
||||
return new SerialRegoConnection(serialPortIdentifier, 19200);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -26,6 +28,7 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class IpRegoConnection implements RegoConnection {
|
||||
/**
|
||||
* Connection timeout in milliseconds
|
||||
@ -40,7 +43,7 @@ public class IpRegoConnection implements RegoConnection {
|
||||
private final Logger logger = LoggerFactory.getLogger(IpRegoConnection.class);
|
||||
private final String address;
|
||||
private final int port;
|
||||
private Socket clientSocket;
|
||||
private @Nullable Socket clientSocket;
|
||||
|
||||
public IpRegoConnection(String address, int port) {
|
||||
this.address = address;
|
||||
@ -50,10 +53,12 @@ public class IpRegoConnection implements RegoConnection {
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
logger.debug("Connecting to '{}', port = {}.", address, port);
|
||||
Socket clientSocket = this.clientSocket;
|
||||
if (clientSocket == null) {
|
||||
clientSocket = new Socket();
|
||||
clientSocket.setSoTimeout(SOCKET_READ_TIMEOUT);
|
||||
clientSocket.setKeepAlive(true);
|
||||
this.clientSocket = clientSocket;
|
||||
}
|
||||
clientSocket.connect(new InetSocketAddress(address, port), CONNECTION_TIMEOUT);
|
||||
logger.debug("Connected to '{}', port = {}.", address, port);
|
||||
@ -61,12 +66,15 @@ public class IpRegoConnection implements RegoConnection {
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
Socket clientSocket = this.clientSocket;
|
||||
return clientSocket != null && clientSocket.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
Socket clientSocket = this.clientSocket;
|
||||
this.clientSocket = null;
|
||||
if (clientSocket != null) {
|
||||
clientSocket.close();
|
||||
}
|
||||
@ -74,17 +82,23 @@ public class IpRegoConnection implements RegoConnection {
|
||||
// There is really not much we can do here, ignore the error and continue execution.
|
||||
logger.warn("Closing socket failed", e);
|
||||
}
|
||||
|
||||
clientSocket = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream outputStream() throws IOException {
|
||||
return clientSocket.getOutputStream();
|
||||
return getClientSocket().getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream inputStream() throws IOException {
|
||||
return clientSocket.getInputStream();
|
||||
return getClientSocket().getInputStream();
|
||||
}
|
||||
|
||||
private Socket getClientSocket() throws IOException {
|
||||
Socket clientSocket = this.clientSocket;
|
||||
if (clientSocket == null) {
|
||||
throw new IOException("Socket closed");
|
||||
}
|
||||
return clientSocket;
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,14 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link RegoConnection} is responsible for creating connections to clients.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface RegoConnection {
|
||||
/**
|
||||
* Connect to the receiver. Return true if the connection has succeeded or if already connected.
|
||||
|
@ -16,6 +16,8 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.io.transport.serial.PortInUseException;
|
||||
import org.openhab.core.io.transport.serial.SerialPort;
|
||||
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
|
||||
@ -26,10 +28,11 @@ import org.openhab.core.io.transport.serial.UnsupportedCommOperationException;
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SerialRegoConnection implements RegoConnection {
|
||||
private final int baudRate;
|
||||
private final String portName;
|
||||
private SerialPort serialPort;
|
||||
private @Nullable SerialPort serialPort;
|
||||
private final SerialPortIdentifier serialPortIdentifier;
|
||||
|
||||
public SerialRegoConnection(SerialPortIdentifier serialPortIdentifier, int baudRate) {
|
||||
@ -41,10 +44,11 @@ public class SerialRegoConnection implements RegoConnection {
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
try {
|
||||
serialPort = serialPortIdentifier.open(SerialRegoConnection.class.getCanonicalName(), 2000);
|
||||
SerialPort serialPort = serialPortIdentifier.open(SerialRegoConnection.class.getCanonicalName(), 2000);
|
||||
serialPort.enableReceiveTimeout(100);
|
||||
serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
|
||||
SerialPort.PARITY_NONE);
|
||||
this.serialPort = serialPort;
|
||||
} catch (PortInUseException e) {
|
||||
throw new IOException("Serial port already used: " + portName, e);
|
||||
} catch (UnsupportedCommOperationException e) {
|
||||
@ -59,19 +63,36 @@ public class SerialRegoConnection implements RegoConnection {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
SerialPort serialPort = this.serialPort;
|
||||
this.serialPort = null;
|
||||
if (serialPort != null) {
|
||||
serialPort.close();
|
||||
serialPort = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream outputStream() throws IOException {
|
||||
return serialPort.getOutputStream();
|
||||
OutputStream outputStream = getSerialPort().getOutputStream();
|
||||
if (outputStream == null) {
|
||||
throw new IOException("Sending data is not supported");
|
||||
}
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream inputStream() throws IOException {
|
||||
return serialPort.getInputStream();
|
||||
InputStream inputStream = getSerialPort().getInputStream();
|
||||
if (inputStream == null) {
|
||||
throw new IOException("Receiving data is not supported");
|
||||
}
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
private SerialPort getSerialPort() throws IOException {
|
||||
SerialPort serialPort = this.serialPort;
|
||||
if (serialPort == null) {
|
||||
throw new IOException("Connection closed");
|
||||
}
|
||||
return serialPort;
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,14 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link AbstractLongResponseParser} is responsible for parsing long form responses.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
abstract class AbstractLongResponseParser<T> extends AbstractResponseParser<T> {
|
||||
@Override
|
||||
public int responseLength() {
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.util.HexUtils;
|
||||
|
||||
/**
|
||||
@ -20,6 +21,7 @@ import org.openhab.core.util.HexUtils;
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
abstract class AbstractResponseParser<T> implements ResponseParser<T> {
|
||||
private static final byte COMPUTER_ADDRESS = (byte) 0x01;
|
||||
|
||||
|
@ -14,11 +14,14 @@ package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link Checksum} is responsible for calculating checksum of given data.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class Checksum {
|
||||
static byte calculate(byte[]... lists) {
|
||||
return Arrays.stream(lists).reduce((byte) 0, Checksum::calculate, (a, b) -> b);
|
||||
|
@ -12,12 +12,15 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link CommandFactory} is responsible for creating different commands that can
|
||||
* be send to a rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CommandFactory {
|
||||
private static final byte DEVICE_ADDRESS = (byte) 0x81;
|
||||
|
||||
|
@ -15,15 +15,20 @@ package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ErrorLine} is responsible for holding information about a single error line.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ErrorLine {
|
||||
private final byte error;
|
||||
private final String timestamp;
|
||||
|
||||
public static final ErrorLine NO_ERROR = new ErrorLine((byte) 0, "");
|
||||
|
||||
public ErrorLine(byte error, String timestamp) {
|
||||
this.error = error;
|
||||
this.timestamp = timestamp;
|
||||
|
@ -12,18 +12,21 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ErrorLineResponseParser} is responsible for parsing error information (log) entry.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class ErrorLineResponseParser extends AbstractLongResponseParser<ErrorLine> {
|
||||
|
||||
@Override
|
||||
protected ErrorLine convert(byte[] responseBytes) {
|
||||
// 255 marks no error.
|
||||
if (responseBytes[1] == (byte) 255) {
|
||||
return null;
|
||||
return ErrorLine.NO_ERROR;
|
||||
}
|
||||
|
||||
return new ErrorLine(ValueConverter.arrayToByte(responseBytes, 1),
|
||||
|
@ -12,11 +12,14 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link Rego6xxProtocolException} is responsible for holding information about an Rego6xx protocol error.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Rego6xxProtocolException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 7556083982084149686L;
|
||||
|
@ -19,6 +19,8 @@ import java.util.Map;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
|
||||
@ -27,6 +29,7 @@ import org.openhab.core.library.unit.Units;
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RegoRegisterMapper {
|
||||
public static final RegoRegisterMapper REGO600;
|
||||
|
||||
@ -35,7 +38,7 @@ public class RegoRegisterMapper {
|
||||
|
||||
public double scaleFactor();
|
||||
|
||||
public Unit<?> unit();
|
||||
public @Nullable Unit<?> unit();
|
||||
|
||||
public int convertValue(short value);
|
||||
}
|
||||
@ -44,9 +47,9 @@ public class RegoRegisterMapper {
|
||||
private static class ChannelImpl implements Channel {
|
||||
private final short address;
|
||||
private final double scaleFactor;
|
||||
private final Unit<?> unit;
|
||||
private @Nullable final Unit<?> unit;
|
||||
|
||||
private ChannelImpl(short address, double scaleFactor, Unit<?> unit) {
|
||||
private ChannelImpl(short address, double scaleFactor, @Nullable Unit<?> unit) {
|
||||
this.address = address;
|
||||
this.scaleFactor = scaleFactor;
|
||||
this.unit = unit;
|
||||
@ -63,7 +66,7 @@ public class RegoRegisterMapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Unit<?> unit() {
|
||||
public @Nullable Unit<?> unit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
@ -104,7 +107,7 @@ public class RegoRegisterMapper {
|
||||
this.mappings = mappings;
|
||||
}
|
||||
|
||||
public Channel map(String channelIID) {
|
||||
public @Nullable Channel map(String channelIID) {
|
||||
return mappings.get(channelIID);
|
||||
}
|
||||
|
||||
|
@ -12,11 +12,14 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ResponseParser} is responsible for parsing arbitrary data coming from a rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface ResponseParser<T> {
|
||||
public int responseLength();
|
||||
|
||||
|
@ -12,15 +12,18 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ResponseParserFactory} is responsible for providing parsers for all known data
|
||||
* forms coming from the rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ResponseParserFactory {
|
||||
public static final ResponseParser<Short> SHORT = new ShortResponseParser();
|
||||
public static final ResponseParser<String> STRING = new StringResponseParser();
|
||||
public static final ResponseParser<ErrorLine> ERROR_LINE = new ErrorLineResponseParser();
|
||||
public static final ResponseParser<Void> WRITE = new WriteResponse();
|
||||
public static final ResponseParser<String> WRITE = new WriteResponse();
|
||||
}
|
||||
|
@ -12,12 +12,15 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ShortResponseParser} is responsible for parsing short form data format
|
||||
* coming from the rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class ShortResponseParser extends AbstractResponseParser<Short> {
|
||||
|
||||
@Override
|
||||
|
@ -12,12 +12,15 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link StringResponseParser} is responsible for parsing long (text) form data format
|
||||
* coming from the rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class StringResponseParser extends AbstractLongResponseParser<String> {
|
||||
|
||||
@Override
|
||||
|
@ -12,11 +12,14 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ValueConverter} is responsible for converting various rego 6xx specific data types.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class ValueConverter {
|
||||
public static byte[] shortToSevenBitFormat(short value) {
|
||||
byte b1 = (byte) ((value & 0xC000) >> 14);
|
||||
|
@ -12,20 +12,23 @@
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link WriteResponse} is responsible for parsing write responses
|
||||
* coming from the rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
class WriteResponse extends AbstractResponseParser<Void> {
|
||||
@NonNullByDefault
|
||||
class WriteResponse extends AbstractResponseParser<String> {
|
||||
@Override
|
||||
public int responseLength() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void convert(byte[] responseBytes) {
|
||||
return null;
|
||||
protected String convert(byte[] responseBytes) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user