[smartmeter] Fix Undelivered IOException (#17133)

Signed-off-by: Leo Siepel <leosiepel@gmail.com>
This commit is contained in:
lsiepel 2024-09-07 10:06:56 +02:00 committed by GitHub
parent e8190f69fb
commit 9f58f6ddbc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 164 additions and 124 deletions

View File

@ -12,19 +12,25 @@
*/
package org.openhab.binding.smartmeter;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link SmartMeterConfiguration} is the class used to match the
* thing configuration.
*
* @author Matthias Steigenberger - Initial contribution
*/
@NonNullByDefault
public class SmartMeterConfiguration {
@Nullable
public String port;
public Integer refresh;
public Integer baudrateChangeDelay;
public Integer refresh = 10;
public Integer baudrateChangeDelay = 0;
@Nullable
public String initMessage;
public String baudrate;
public String mode;
public String conformity;
public String baudrate = "AUTO";
public String mode = "SML";
public String conformity = "NONE";
}

View File

@ -12,6 +12,7 @@
*/
package org.openhab.binding.smartmeter.internal;
import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
@ -37,6 +38,7 @@ import org.slf4j.LoggerFactory;
import io.reactivex.Flowable;
import io.reactivex.disposables.Disposable;
import io.reactivex.exceptions.UndeliverableException;
import io.reactivex.plugins.RxJavaPlugins;
import io.reactivex.schedulers.Schedulers;
@ -83,7 +85,18 @@ public abstract class MeterDevice<T> {
this.connector = createConnector(serialPortManagerSupplier, serialPort, baudrate, baudrateChangeDelay,
protocolMode);
RxJavaPlugins.setErrorHandler(error -> {
logger.error("Fatal error occured", error);
if (error == null) {
logger.warn("Fatal but unknown error occurred");
return;
}
if (error instanceof UndeliverableException) {
error = error.getCause();
}
if (error instanceof IOException) {
logger.warn("Connection related issue occurred: {}", error.getMessage());
return;
}
logger.warn("Fatal error occurred", error);
});
}

View File

@ -17,7 +17,7 @@ import java.util.function.Supplier;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.smartmeter.internal.helper.ProtocolMode;
import org.openhab.binding.smartmeter.internal.iec62056.Iec62056_21MeterReader;
import org.openhab.binding.smartmeter.internal.iec62056.MeterReader;
import org.openhab.binding.smartmeter.internal.sml.SmlMeterReader;
import org.openhab.core.io.transport.serial.SerialPortManager;
@ -49,8 +49,8 @@ public class MeterDeviceFactory {
switch (protocolMode) {
case D:
case ABC:
return new Iec62056_21MeterReader(serialPortManagerSupplier, deviceId, serialPort, initMessage,
baudrate, baudrateChangeDelay, protocolMode);
return new MeterReader(serialPortManagerSupplier, deviceId, serialPort, initMessage, baudrate,
baudrateChangeDelay, protocolMode);
case SML:
return SmlMeterReader.createInstance(serialPortManagerSupplier, deviceId, serialPort, initMessage,
baudrate, baudrateChangeDelay);

View File

@ -66,11 +66,15 @@ public class MeterValue<Q extends Quantity<Q>> {
@Override
public int hashCode() {
final int prime = 31;
final String status = this.status;
final Unit<? extends Q> unit = this.unit;
final String value = this.value;
int result = 1;
result = prime * result + ((obis == null) ? 0 : obis.hashCode());
result = prime * result + ((status == null) ? 0 : status.hashCode());
result = prime * result + ((unit == null) ? 0 : unit.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
result = prime * result + obis.hashCode();
result = prime * result + (status == null ? 0 : status.hashCode());
result = prime * result + (unit == null ? 0 : unit.hashCode());
result = prime * result + value.hashCode();
return result;
}
@ -90,6 +94,7 @@ public class MeterValue<Q extends Quantity<Q>> {
if (!obis.equals(other.obis)) {
return false;
}
String status = this.status;
if (status == null) {
if (other.status != null) {
return false;
@ -97,6 +102,7 @@ public class MeterValue<Q extends Quantity<Q>> {
} else if (!status.equals(other.status)) {
return false;
}
Unit<? extends Q> unit = this.unit;
if (unit == null) {
if (other.unit != null) {
return false;

View File

@ -82,6 +82,10 @@ public class ObisCode {
* @return the obis as string.
*/
public String asDecimalString() {
Byte a = this.a;
Byte b = this.b;
Byte c = this.c;
Byte f = this.f;
try (Formatter format = new Formatter()) {
format.format(SmartMeterBindingConstants.OBIS_FORMAT, a != null ? a & 0xFF : 0, b != null ? b & 0xFF : 0,
c & 0xFF, d & 0xFF, e & 0xFF, f != null ? f & 0xFF : 0);
@ -118,10 +122,15 @@ public class ObisCode {
return asDecimalString();
}
public boolean matches(@Nullable Byte a, @Nullable Byte b, Byte c, Byte d, Byte e, @Nullable Byte f) {
return (this.a == null || a == null || this.a.equals(a)) && (this.b == null || b == null || this.b.equals(b))
&& this.c.equals(c) && this.d.equals(d) && this.e.equals(e)
&& (this.f == null || f == null || this.f.equals(f));
public boolean matches(@Nullable Byte otherA, @Nullable Byte otherB, Byte otherC, Byte d, Byte e,
@Nullable Byte otherF) {
Byte a = this.a;
Byte b = this.b;
Byte c = this.c;
Byte f = this.f;
return (a == null || otherA == null || a.equals(otherA)) && (b == null || otherB == null || b.equals(otherB))
&& c.equals(otherC) && this.d.equals(d) && this.e.equals(e)
&& (f == null || otherF == null || f.equals(otherF));
}
public boolean matches(Byte c, Byte d, Byte e) {

View File

@ -21,7 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.measure.Quantity;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.smartmeter.SmartMeterBindingConstants;
import org.openhab.core.library.CoreItemFactory;
@ -44,6 +44,7 @@ import org.slf4j.LoggerFactory;
* @author Matthias Steigenberger - Initial contribution
*
*/
@NonNullByDefault
@Component(service = { ChannelTypeProvider.class, SmartMeterChannelTypeProvider.class })
public class SmartMeterChannelTypeProvider implements ChannelTypeProvider, MeterValueListener {
@ -68,14 +69,14 @@ public class SmartMeterChannelTypeProvider implements ChannelTypeProvider, Meter
}
@Override
public <Q extends @NonNull Quantity<Q>> void valueChanged(MeterValue<Q> value) {
public <Q extends Quantity<Q>> void valueChanged(MeterValue<Q> value) {
if (!obisChannelMap.containsKey(value.getObisCode())) {
logger.debug("Creating ChannelType for OBIS {}", value.getObisCode());
obisChannelMap.put(value.getObisCode(), getChannelType(value.getUnit(), value.getObisCode()));
}
}
private ChannelType getChannelType(Unit<?> unit, String obis) {
private ChannelType getChannelType(@Nullable Unit<?> unit, String obis) {
String obisChannelId = SmartMeterBindingConstants.getObisChannelId(obis);
StateChannelTypeBuilder stateDescriptionBuilder;
if (unit != null) {
@ -96,7 +97,7 @@ public class SmartMeterChannelTypeProvider implements ChannelTypeProvider, Meter
}
@Override
public <Q extends @NonNull Quantity<Q>> void valueRemoved(MeterValue<Q> value) {
public <Q extends Quantity<Q>> void valueRemoved(MeterValue<Q> value) {
obisChannelMap.remove(value.getObisCode());
}
@ -106,7 +107,7 @@ public class SmartMeterChannelTypeProvider implements ChannelTypeProvider, Meter
* @param obis The obis code.
* @return The {@link ChannelTypeUID} or null.
*/
public ChannelTypeUID getChannelTypeIdForObis(String obis) {
public @Nullable ChannelTypeUID getChannelTypeIdForObis(String obis) {
ChannelType channeltype = obisChannelMap.get(obis);
return channeltype != null ? channeltype.getUID() : null;
}

View File

@ -68,14 +68,13 @@ import io.reactivex.disposables.Disposable;
public class SmartMeterHandler extends BaseThingHandler {
private static final long DEFAULT_TIMEOUT = 30000;
private static final int DEFAULT_REFRESH_PERIOD = 30;
private Logger logger = LoggerFactory.getLogger(SmartMeterHandler.class);
private MeterDevice<?> smlDevice;
private Disposable valueReader;
private Conformity conformity;
private MeterValueListener valueChangeListener;
private SmartMeterChannelTypeProvider channelTypeProvider;
private @NonNull Supplier<SerialPortManager> serialPortManagerSupplier;
private Supplier<SerialPortManager> serialPortManagerSupplier;
public SmartMeterHandler(Thing thing, SmartMeterChannelTypeProvider channelProvider,
Supplier<SerialPortManager> serialPortManagerSupplier) {
@ -99,11 +98,10 @@ public class SmartMeterHandler extends BaseThingHandler {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Parameter 'port' is mandatory and must be configured");
} else {
byte[] pullSequence = config.initMessage == null ? null
: HexUtils.hexToBytes(config.initMessage.replaceAll("\\s+", ""));
int baudrate = config.baudrate == null ? Baudrate.AUTO.getBaudrate()
: Baudrate.fromString(config.baudrate).getBaudrate();
this.conformity = config.conformity == null ? Conformity.NONE : Conformity.valueOf(config.conformity);
String initMessage = config.initMessage;
byte[] pullSequence = initMessage == null ? null : HexUtils.hexToBytes(initMessage.replaceAll("\\s+", ""));
int baudrate = Baudrate.fromString(config.baudrate).getBaudrate();
this.conformity = Conformity.valueOf(config.conformity);
this.smlDevice = MeterDeviceFactory.getDevice(serialPortManagerSupplier, config.mode,
this.thing.getUID().getAsString(), port, pullSequence, baudrate, config.baudrateChangeDelay);
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.HANDLER_CONFIGURATION_PENDING,
@ -158,53 +156,58 @@ public class SmartMeterHandler extends BaseThingHandler {
String obisChannelString = SmartMeterBindingConstants.getObisChannelId(obis);
Channel channel = thing.getChannel(obisChannelString);
ChannelTypeUID channelTypeId = channelTypeProvider.getChannelTypeIdForObis(obis);
if (channelTypeId == null) {
logger.warn("No ChannelTypeId found for OBIS {}", obis);
return;
}
ChannelType channelType = channelTypeProvider.getChannelType(channelTypeId, null);
if (channelType != null) {
String itemType = channelType.getItemType();
State state = getStateForObisValue(value, channel);
if (channel == null) {
logger.debug("Adding channel: {} with item type: {}", obisChannelString, itemType);
// channel has not been created yet
ChannelBuilder channelBuilder = ChannelBuilder
.create(new ChannelUID(thing.getUID(), obisChannelString), itemType)
.withType(channelTypeId);
Configuration configuration = new Configuration();
configuration.put(SmartMeterBindingConstants.CONFIGURATION_CONVERSION, 1);
channelBuilder.withConfiguration(configuration);
channelBuilder.withLabel(obis);
Map<String, String> channelProps = new HashMap<>();
channelProps.put(SmartMeterBindingConstants.CHANNEL_PROPERTY_OBIS, obis);
channelBuilder.withProperties(channelProps);
channelBuilder.withDescription(
MessageFormat.format("Value for OBIS code: {0} with Unit: {1}", obis, value.getUnit()));
channel = channelBuilder.build();
ChannelUID channelId = channel.getUID();
// add all valid channels to the thing builder
List<Channel> channels = new ArrayList<>(getThing().getChannels());
if (channels.stream().filter((element) -> element.getUID().equals(channelId)).count() == 0) {
channels.add(channel);
thingBuilder.withChannels(channels);
updateThing(thingBuilder.build());
}
}
if (!channel.getProperties().containsKey(SmartMeterBindingConstants.CHANNEL_PROPERTY_OBIS)) {
addObisPropertyToChannel(obis, channel);
}
if (state != null) {
updateState(channel.getUID(), state);
}
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
} else {
if (channelType == null) {
logger.warn("No ChannelType found for OBIS {}", obis);
return;
}
String itemType = channelType.getItemType();
State state = getStateForObisValue(value, channel);
if (channel == null) {
logger.debug("Adding channel: {} with item type: {}", obisChannelString, itemType);
// channel has not been created yet
ChannelBuilder channelBuilder = ChannelBuilder
.create(new ChannelUID(thing.getUID(), obisChannelString), itemType)
.withType(channelTypeId);
Configuration configuration = new Configuration();
configuration.put(SmartMeterBindingConstants.CONFIGURATION_CONVERSION, 1);
channelBuilder.withConfiguration(configuration);
channelBuilder.withLabel(obis);
Map<String, String> channelProps = new HashMap<>();
channelProps.put(SmartMeterBindingConstants.CHANNEL_PROPERTY_OBIS, obis);
channelBuilder.withProperties(channelProps);
channelBuilder.withDescription(
MessageFormat.format("Value for OBIS code: {0} with Unit: {1}", obis, value.getUnit()));
channel = channelBuilder.build();
ChannelUID channelId = channel.getUID();
// add all valid channels to the thing builder
List<Channel> channels = new ArrayList<>(getThing().getChannels());
if (channels.stream().filter((element) -> element.getUID().equals(channelId)).count() == 0) {
channels.add(channel);
thingBuilder.withChannels(channels);
updateThing(thingBuilder.build());
}
}
if (!channel.getProperties().containsKey(SmartMeterBindingConstants.CHANNEL_PROPERTY_OBIS)) {
addObisPropertyToChannel(obis, channel);
}
if (state != null) {
updateState(channel.getUID(), state);
}
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
}
private void addObisPropertyToChannel(String obis, Channel channel) {
@ -238,8 +241,7 @@ public class SmartMeterHandler extends BaseThingHandler {
this.smlDevice.addValueChangeListener(valueChangeListener);
SmartMeterConfiguration config = getConfigAs(SmartMeterConfiguration.class);
int delay = config.refresh != null ? config.refresh : DEFAULT_REFRESH_PERIOD;
valueReader = this.smlDevice.readValues(DEFAULT_TIMEOUT, this.scheduler, Duration.ofSeconds(delay));
valueReader = this.smlDevice.readValues(DEFAULT_TIMEOUT, this.scheduler, Duration.ofSeconds(config.refresh));
}
private void updateOBISChannel(ChannelUID channelId) {

View File

@ -28,7 +28,6 @@ import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
@ -89,7 +88,8 @@ public enum Conformity {
}
}
} catch (Exception e) {
logger.warn("Failed to check negate status for obis {}", obis, e);
LoggerFactory.getLogger(Conformity.class)
.warn("Failed to check negate status for obis {}", obis, e);
}
}
}
@ -99,8 +99,6 @@ public enum Conformity {
}
};
private static final Logger logger = LoggerFactory.getLogger(Conformity.class);
/**
* Applies the overwritten negation setting for the channel.
*

View File

@ -17,7 +17,6 @@ import java.util.function.Function;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.smartmeter.internal.MeterValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
@ -28,7 +27,6 @@ import org.slf4j.LoggerFactory;
*/
@NonNullByDefault
public class NegateHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(NegateHandler.class);
/**
* Gets whether negation should be applied for the given <code>negateProperty</code> and the {@link MeterValue}
@ -71,7 +69,8 @@ public class NegateHandler {
try {
longValue = (long) Double.parseDouble(value);
} catch (NumberFormatException e) {
LOGGER.warn("Failed to parse value: {} when determining isNegateSet, assuming false", value);
LoggerFactory.getLogger(NegateHandler.class)
.warn("Failed to parse value: {} when determining isNegateSet, assuming false", value);
return false;
}
return (longValue & (1L << negatePosition)) != 0;

View File

@ -16,7 +16,6 @@ import java.util.function.Supplier;
import javax.measure.Quantity;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.smartmeter.connectors.IMeterReaderConnector;
@ -34,11 +33,10 @@ import org.openmuc.j62056.DataSet;
*
*/
@NonNullByDefault
public class Iec62056_21MeterReader extends MeterDevice<DataMessage> {
public class MeterReader extends MeterDevice<DataMessage> {
public Iec62056_21MeterReader(Supplier<SerialPortManager> serialPortManagerSupplier, String deviceId,
String serialPort, byte @Nullable [] initMessage, int baudrate, int baudrateChangeDelay,
ProtocolMode protocolMode) {
public MeterReader(Supplier<SerialPortManager> serialPortManagerSupplier, String deviceId, String serialPort,
byte @Nullable [] initMessage, int baudrate, int baudrateChangeDelay, ProtocolMode protocolMode) {
super(serialPortManagerSupplier, deviceId, serialPort, initMessage, baudrate, baudrateChangeDelay,
protocolMode);
}
@ -46,17 +44,15 @@ public class Iec62056_21MeterReader extends MeterDevice<DataMessage> {
@Override
protected IMeterReaderConnector<DataMessage> createConnector(Supplier<SerialPortManager> serialPortManagerSupplier,
String serialPort, int baudrate, int baudrateChangeDelay, ProtocolMode protocolMode) {
return new Iec62056_21SerialConnector(serialPortManagerSupplier, serialPort, baudrate, baudrateChangeDelay,
protocolMode);
return new SerialConnector(serialPortManagerSupplier, serialPort, baudrate, baudrateChangeDelay, protocolMode);
}
@Override
protected <Q extends @NonNull Quantity<Q>> void populateValueCache(DataMessage smlFile) {
protected <Q extends Quantity<Q>> void populateValueCache(DataMessage smlFile) {
for (DataSet dataSet : smlFile.getDataSets()) {
String address = dataSet.getAddress();
if (address != null && !address.isEmpty()) {
addObisCache(new MeterValue<Q>(address, dataSet.getValue(),
Iec62056_21UnitConversion.getUnit(dataSet.getUnit())));
addObisCache(new MeterValue<Q>(address, dataSet.getValue(), UnitConversion.getUnit(dataSet.getUnit())));
}
}
}

View File

@ -40,17 +40,17 @@ import io.reactivex.FlowableEmitter;
*
*/
@NonNullByDefault
public class Iec62056_21SerialConnector extends ConnectorBase<DataMessage> {
public class SerialConnector extends ConnectorBase<DataMessage> {
private final Logger logger = LoggerFactory.getLogger(Iec62056_21SerialConnector.class);
private final Logger logger = LoggerFactory.getLogger(SerialConnector.class);
private int baudrate;
private int baudrateChangeDelay;
private ProtocolMode protocolMode;
@Nullable
private Iec21Port iec21Port;
public Iec62056_21SerialConnector(Supplier<SerialPortManager> serialPortManagerSupplier, String portName,
int baudrate, int baudrateChangeDelay, ProtocolMode protocolMode) {
public SerialConnector(Supplier<SerialPortManager> serialPortManagerSupplier, String portName, int baudrate,
int baudrateChangeDelay, ProtocolMode protocolMode) {
super(portName);
this.baudrate = baudrate;
this.baudrateChangeDelay = baudrateChangeDelay;
@ -78,6 +78,7 @@ public class Iec62056_21SerialConnector extends ConnectorBase<DataMessage> {
@Override
protected DataMessage readNext(byte @Nullable [] initMessage) throws IOException {
Iec21Port iec21Port = this.iec21Port;
if (iec21Port != null) {
DataMessage dataMessage = iec21Port.read();
logger.debug("Datamessage read: {}", dataMessage);
@ -94,6 +95,7 @@ public class Iec62056_21SerialConnector extends ConnectorBase<DataMessage> {
super.emitValues(initMessage, emitter);
break;
case D:
Iec21Port iec21Port = this.iec21Port;
if (iec21Port != null) {
iec21Port.listen(new ModeDListener() {
@ -108,6 +110,7 @@ public class Iec62056_21SerialConnector extends ConnectorBase<DataMessage> {
logger.warn("Exception while listening for mode D data message", e);
}
});
this.iec21Port = iec21Port;
}
break;
case SML:
@ -128,6 +131,7 @@ public class Iec62056_21SerialConnector extends ConnectorBase<DataMessage> {
@Override
public void closeConnection() {
Iec21Port iec21Port = this.iec21Port;
if (iec21Port != null) {
iec21Port.close();
}

View File

@ -18,7 +18,6 @@ import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.types.util.UnitUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
@ -28,9 +27,7 @@ import org.slf4j.LoggerFactory;
*
*/
@NonNullByDefault
public class Iec62056_21UnitConversion {
private static final Logger logger = LoggerFactory.getLogger(Iec62056_21UnitConversion.class);
public class UnitConversion {
@SuppressWarnings("unchecked")
public static @Nullable <Q extends Quantity<Q>> Unit<Q> getUnit(String unit) {
@ -38,7 +35,7 @@ public class Iec62056_21UnitConversion {
try {
return (Unit<Q>) UnitUtils.parseUnit(" " + unit);
} catch (Exception e) {
logger.warn("Failed to parse unit {}: {}", unit, e.getMessage());
LoggerFactory.getLogger(UnitConversion.class).warn("Failed to parse unit {}: {}", unit, e.getMessage());
return null;
}
}

View File

@ -105,48 +105,48 @@ public class SmlFileDebugOutput {
private static void parseGetListResponse(SmlMessage smlMessage, Consumer<String> consumer) {
consumer.accept("Got GetListResponse");
SmlGetListRes sml_listRes = (SmlGetListRes) smlMessage.getMessageBody().getChoice();
SmlGetListRes smlListRes = (SmlGetListRes) smlMessage.getMessageBody().getChoice();
// consumer.accept(sml_listRes.toString());
consumer.accept(sml_listRes.toStringIndent(" "));
consumer.accept(smlListRes.toStringIndent(" "));
}
private static void parseAttentionResponse(SmlMessage smlMessage, Consumer<String> consumer) {
consumer.accept("Got AttentionResponse");
SmlAttentionRes sml_attentionRes = (SmlAttentionRes) smlMessage.getMessageBody().getChoice();
consumer.accept(sml_attentionRes.toString());
SmlAttentionRes smlAttentionRes = (SmlAttentionRes) smlMessage.getMessageBody().getChoice();
consumer.accept(smlAttentionRes.toString());
}
private static void parseGetProcParameterResponse(SmlMessage smlMessage, Consumer<String> consumer) {
consumer.accept("Got GetProcParameterResponse");
SmlGetProcParameterRes sml_getProcParameterRes = (SmlGetProcParameterRes) smlMessage.getMessageBody()
SmlGetProcParameterRes smlGetProcParameterRes = (SmlGetProcParameterRes) smlMessage.getMessageBody()
.getChoice();
consumer.accept(sml_getProcParameterRes.toString());
consumer.accept(smlGetProcParameterRes.toString());
}
private static void parseGetProfileListResponse(SmlMessage smlMessage, Consumer<String> consumer) {
consumer.accept("Got GetProfileListResponse");
SmlGetProfileListRes sml_getProfileListRes = (SmlGetProfileListRes) smlMessage.getMessageBody().getChoice();
consumer.accept(sml_getProfileListRes.toString());
SmlGetProfileListRes smlGetProfileListRes = (SmlGetProfileListRes) smlMessage.getMessageBody().getChoice();
consumer.accept(smlGetProfileListRes.toString());
}
private static void parseOpenResponse(SmlMessage smlMessage, Consumer<String> consumer) {
consumer.accept("Got OpenResponse");
SmlPublicOpenRes sml_PublicOpenRes = (SmlPublicOpenRes) smlMessage.getMessageBody().getChoice();
consumer.accept(sml_PublicOpenRes.toString());
SmlPublicOpenRes smlPublicOpenRes = (SmlPublicOpenRes) smlMessage.getMessageBody().getChoice();
consumer.accept(smlPublicOpenRes.toString());
}
private static void parseCloseResponse(SmlMessage smlMessage, Consumer<String> consumer) {
consumer.accept("Got CloseResponse");
SmlPublicCloseRes sml_PublicCloseRes = (SmlPublicCloseRes) smlMessage.getMessageBody().getChoice();
consumer.accept(sml_PublicCloseRes.toString());
SmlPublicCloseRes smlPublicCloseRes = (SmlPublicCloseRes) smlMessage.getMessageBody().getChoice();
consumer.accept(smlPublicCloseRes.toString());
}
private static void parseGetProfilePackResponse(SmlMessage smlMessage, Consumer<String> consumer) {
consumer.accept("Got GetProfilePackResponse");
SmlGetProfilePackRes sml_getProfilePackRes = (SmlGetProfilePackRes) smlMessage.getMessageBody().getChoice();
consumer.accept(sml_getProfilePackRes.toString());
SmlGetProfilePackRes smlGetProfilePackRes = (SmlGetProfilePackRes) smlMessage.getMessageBody().getChoice();
consumer.accept(smlGetProfilePackRes.toString());
}
// ========================= Requests =================================

View File

@ -81,6 +81,7 @@ public final class SmlSerialConnector extends ConnectorBase<SmlFile> {
protected SmlFile readNext(byte @Nullable [] initMessage) throws IOException {
if (initMessage != null) {
logger.debug("Writing init message: {}", HexUtils.bytesToHex(initMessage, " "));
DataOutputStream os = this.os;
if (os != null) {
os.write(initMessage);
os.flush();
@ -89,6 +90,7 @@ public final class SmlSerialConnector extends ConnectorBase<SmlFile> {
// read out the whole buffer. We are only interested in the most recent SML file.
Stack<SmlFile> smlFiles = new Stack<>();
DataInputStream is = this.is;
do {
logger.trace("Reading {}. SML message", smlFiles.size() + 1);
smlFiles.push(TRANSPORT.getSMLFile(is));
@ -137,12 +139,10 @@ public final class SmlSerialConnector extends ConnectorBase<SmlFile> {
}
}
/**
* {@inheritDoc}
*/
@Override
public void closeConnection() {
try {
DataInputStream is = this.is;
if (is != null) {
is.close();
is = null;
@ -151,6 +151,7 @@ public final class SmlSerialConnector extends ConnectorBase<SmlFile> {
logger.error("Failed to close serial input stream", e);
}
try {
DataOutputStream os = this.os;
if (os != null) {
os.close();
os = null;

View File

@ -15,6 +15,8 @@ package org.openhab.binding.smartmeter;
import java.io.IOException;
import java.util.function.Supplier;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.smartmeter.connectors.ConnectorBase;
/**
@ -22,6 +24,7 @@ import org.openhab.binding.smartmeter.connectors.ConnectorBase;
* @author Matthias Steigenberger - Initial contribution
*
*/
@NonNullByDefault
public class MockMeterReaderConnector extends ConnectorBase<Object> {
private boolean applyRetry;
@ -42,12 +45,12 @@ public class MockMeterReaderConnector extends ConnectorBase<Object> {
}
@Override
protected Object readNext(byte[] initMessage) throws IOException {
protected Object readNext(byte @Nullable [] initMessage) throws IOException {
try {
return readNextSupplier.get();
} catch (RuntimeException e) {
if (e.getCause() instanceof IOException) {
throw (IOException) e.getCause();
if (e.getCause() instanceof IOException cause) {
throw cause;
}
throw e;
}

View File

@ -23,7 +23,7 @@ import java.util.function.Supplier;
import javax.measure.Quantity;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
@ -44,6 +44,7 @@ import io.reactivex.plugins.RxJavaPlugins;
* @author Matthias Steigenberger - Initial contribution
*
*/
@NonNullByDefault
public class TestMeterReading {
@Test
@ -118,6 +119,7 @@ public class TestMeterReading {
throw new RuntimeException(new IOException("fucked up"));
}));
MeterDevice<Object> meter = getMeterDevice(connector);
@SuppressWarnings("unchecked")
Consumer<Throwable> errorHandler = mock(Consumer.class);
RxJavaPlugins.setErrorHandler(errorHandler);
MeterValueListener changeListener = Mockito.mock(MeterValueListener.class);
@ -139,14 +141,15 @@ public class TestMeterReading {
return new MeterDevice<>(() -> mock(SerialPortManager.class), "id", "port", null, 9600, 0, ProtocolMode.SML) {
@Override
protected @NonNull IMeterReaderConnector<Object> createConnector(
@NonNull Supplier<@NonNull SerialPortManager> serialPortManagerSupplier, @NonNull String serialPort,
int baudrate, int baudrateChangeDelay, @NonNull ProtocolMode protocolMode) {
protected IMeterReaderConnector<Object> createConnector(
Supplier<SerialPortManager> serialPortManagerSupplier, String serialPort, int baudrate,
int baudrateChangeDelay, ProtocolMode protocolMode) {
return connector;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
protected <Q extends @NonNull Quantity<Q>> void populateValueCache(Object smlFile) {
protected <Q extends Quantity<Q>> void populateValueCache(Object smlFile) {
addObisCache(new MeterValue("123", "333", null));
}
};

View File

@ -14,6 +14,7 @@ package org.openhab.binding.smartmeter;
import static org.junit.jupiter.api.Assertions.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.openhab.binding.smartmeter.internal.MeterValue;
import org.openhab.binding.smartmeter.internal.conformity.negate.NegateBitModel;
@ -25,6 +26,7 @@ import org.openhab.binding.smartmeter.internal.conformity.negate.NegateHandler;
* @author Matthias Steigenberger - Initial contribution
*
*/
@NonNullByDefault
public class TestNegateBit {
@Test