mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-25 14:55:55 +01:00
[smartmeter] Fix Undelivered IOException (#17133)
Signed-off-by: Leo Siepel <leosiepel@gmail.com>
This commit is contained in:
parent
e8190f69fb
commit
9f58f6ddbc
@ -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";
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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())));
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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 =================================
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user