[modbus] Modbus register array backed by bytes and other simplifications (#8865)

Signed-off-by: Sami Salonen <ssalonen@gmail.com>
This commit is contained in:
Sami Salonen
2020-11-26 19:07:49 +02:00
committed by GitHub
parent ff038bc9bb
commit b806ed45d0
32 changed files with 2140 additions and 655 deletions

View File

@@ -12,11 +12,12 @@
*/
package org.openhab.binding.modbus.e3dc.internal.dto;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.BitSet;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.io.transport.modbus.ModbusBitUtilities;
import org.openhab.io.transport.modbus.ValueBuffer;
/**
* The {@link DataConverter} Helper class to convert bytes from modbus into desired data format
@@ -25,27 +26,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
*/
@NonNullByDefault
public class DataConverter {
private static final long MAX_INT32 = (long) Math.pow(2, Integer.SIZE);
/**
* Get unit16 value from 2 bytes
*
* @param wrap
* @return int
*/
public static int getUInt16Value(ByteBuffer wrap) {
return Short.toUnsignedInt(wrap.getShort());
}
/**
* Get unit32 value from 4 bytes
*
* @param wrap
* @return long
*/
public static long getLongValue(ByteBuffer wrap) {
return Integer.toUnsignedLong(wrap.getInt());
}
/**
* Get double value from 2 bytes with correction factor
@@ -53,28 +33,12 @@ public class DataConverter {
* @param wrap
* @return double
*/
public static double getUDoubleValue(ByteBuffer wrap, double factor) {
return round(getUInt16Value(wrap) * factor, 2);
}
/**
* Conversion done according to E3DC Modbus Specification V1.7
*
* @param wrap
* @return decoded long value, Long.MIN_VALUE otherwise
*/
public static long getInt32Swap(ByteBuffer wrap) {
long a = getUInt16Value(wrap);
long b = getUInt16Value(wrap);
if (b < 32768) {
return b * 65536 + a;
} else {
return (MAX_INT32 - b * 65536 - a) * -1;
}
public static double getUDoubleValue(ValueBuffer wrap, double factor) {
return round(wrap.getUInt16() * factor, 2);
}
public static String getString(byte[] bArray) {
return new String(bArray, StandardCharsets.US_ASCII).trim();
return ModbusBitUtilities.extractStringFromBytes(bArray, 0, bArray.length, StandardCharsets.US_ASCII).trim();
}
public static int toInt(BitSet bitSet) {
@@ -93,8 +57,7 @@ public class DataConverter {
}
long factor = (long) Math.pow(10, places);
value = value * factor;
long tmp = Math.round(value);
long tmp = Math.round(value * factor);
return (double) tmp / factor;
}
}

View File

@@ -14,13 +14,13 @@ package org.openhab.binding.modbus.e3dc.internal.dto;
import static org.openhab.binding.modbus.e3dc.internal.modbus.E3DCModbusConstans.*;
import java.nio.ByteBuffer;
import java.util.BitSet;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
import org.openhab.io.transport.modbus.ModbusBitUtilities;
/**
* The {@link EmergencyBlock} Data object for E3DC Info Block
@@ -55,7 +55,7 @@ public class EmergencyBlock implements Data {
*/
public EmergencyBlock(byte[] bArray) {
// uint16 status register 40084 - possible Status Strings are defined in Constants above
int status = DataConverter.getUInt16Value(ByteBuffer.wrap(bArray));
int status = ModbusBitUtilities.extractUInt16(bArray, 0);
if (status >= 0 && status < 5) {
epStatus = EP_STATUS_ARRAY[status];
} else {

View File

@@ -12,13 +12,12 @@
*/
package org.openhab.binding.modbus.e3dc.internal.dto;
import java.nio.ByteBuffer;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.util.HexUtils;
import org.openhab.io.transport.modbus.ValueBuffer;
/**
* The {@link InfoBlock} Data object for E3DC Info Block
@@ -43,7 +42,7 @@ public class InfoBlock implements Data {
*/
public InfoBlock(byte[] bArray) {
// index handling to calculate the correct start index
ByteBuffer wrapper = ByteBuffer.wrap(bArray);
ValueBuffer wrapper = ValueBuffer.wrap(bArray);
// first uint16 = 2 bytes - decode magic byte
byte[] magicBytes = new byte[2];
@@ -52,11 +51,11 @@ public class InfoBlock implements Data {
// first uint16 = 2 bytes - decode magic byte
// unit8 (Modbus Major Version) + uint8 Modbus minor Version
String modbusVersion = wrapper.get() + "." + wrapper.get();
String modbusVersion = wrapper.getSInt8() + "." + wrapper.getSInt8();
this.modbusVersion = new StringType(modbusVersion);
// unit16 - supported registers
short supportedRegisters = wrapper.getShort();
short supportedRegisters = wrapper.getSInt16();
this.supportedRegisters = new DecimalType(supportedRegisters);
byte[] buffer = new byte[32];

View File

@@ -12,8 +12,6 @@
*/
package org.openhab.binding.modbus.e3dc.internal.dto;
import java.nio.ByteBuffer;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Power;
@@ -21,6 +19,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.io.transport.modbus.ValueBuffer;
/**
* The {@link PowerBlock} Data object for E3DC Info Block
@@ -49,10 +48,10 @@ public class PowerBlock implements Data {
*/
public PowerBlock(byte[] bArray) {
// index handling to calculate the correct start index
ByteBuffer wrap = ByteBuffer.wrap(bArray);
ValueBuffer wrap = ValueBuffer.wrap(bArray);
// int32_swap value = 4 byte
long pvPowerSupplyL = DataConverter.getInt32Swap(wrap);
long pvPowerSupplyL = wrap.getSInt32Swap();
/*
* int32_swap value don't provide negative values!
@@ -60,7 +59,7 @@ public class PowerBlock implements Data {
* Negative value - Battery is discharging = Power supplier
*/
pvPowerSupply = QuantityType.valueOf(pvPowerSupplyL, SmartHomeUnits.WATT);
long batteryPower = DataConverter.getInt32Swap(wrap);
long batteryPower = wrap.getSInt32Swap();
if (batteryPower > 0) {
// Battery is charging so Power is consumed by Battery
batteryPowerSupply = QuantityType.valueOf(0, SmartHomeUnits.WATT);
@@ -72,7 +71,7 @@ public class PowerBlock implements Data {
}
// int32_swap value = 4 byte
long householdPowerConsumptionL = DataConverter.getInt32Swap(wrap);
long householdPowerConsumptionL = wrap.getSInt32Swap();
householdPowerConsumption = QuantityType.valueOf(householdPowerConsumptionL, SmartHomeUnits.WATT);
/*
@@ -80,7 +79,7 @@ public class PowerBlock implements Data {
* Positive value - Power provided towards Grid = Power consumer
* Negative value - Power requested from Grid = Power supplier
*/
long gridPower = DataConverter.getInt32Swap(wrap);
long gridPower = wrap.getSInt32Swap();
if (gridPower > 0) {
// Power is provided by Grid
gridPowerSupply = QuantityType.valueOf(gridPower, SmartHomeUnits.WATT);
@@ -92,19 +91,19 @@ public class PowerBlock implements Data {
}
// int32_swap value = 4 byte
externalPowerSupply = QuantityType.valueOf(DataConverter.getInt32Swap(wrap), SmartHomeUnits.WATT);
externalPowerSupply = QuantityType.valueOf(wrap.getSInt32Swap(), SmartHomeUnits.WATT);
// int32_swap value = 4 byte
wallboxPowerConsumption = QuantityType.valueOf(DataConverter.getInt32Swap(wrap), SmartHomeUnits.WATT);
wallboxPowerConsumption = QuantityType.valueOf(wrap.getSInt32Swap(), SmartHomeUnits.WATT);
// int32_swap value = 4 byte
wallboxPVPowerConsumption = QuantityType.valueOf(DataConverter.getInt32Swap(wrap), SmartHomeUnits.WATT);
wallboxPVPowerConsumption = QuantityType.valueOf(wrap.getSInt32Swap(), SmartHomeUnits.WATT);
// unit8 + uint8 - one register with split value for Autarky & Self Consumption
autarky = QuantityType.valueOf(wrap.get(), SmartHomeUnits.PERCENT);
selfConsumption = QuantityType.valueOf(wrap.get(), SmartHomeUnits.PERCENT);
autarky = QuantityType.valueOf(wrap.getSInt8(), SmartHomeUnits.PERCENT);
selfConsumption = QuantityType.valueOf(wrap.getSInt8(), SmartHomeUnits.PERCENT);
// uint16 for Battery State of Charge
batterySOC = QuantityType.valueOf(wrap.getShort(), SmartHomeUnits.PERCENT);
batterySOC = QuantityType.valueOf(wrap.getSInt16(), SmartHomeUnits.PERCENT);
}
}

View File

@@ -12,8 +12,6 @@
*/
package org.openhab.binding.modbus.e3dc.internal.dto;
import java.nio.ByteBuffer;
import javax.measure.quantity.ElectricCurrent;
import javax.measure.quantity.ElectricPotential;
import javax.measure.quantity.Power;
@@ -22,6 +20,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.io.transport.modbus.ValueBuffer;
/**
* The {@link StringBlock} Data object for E3DC Info Block
@@ -46,17 +45,17 @@ public class StringBlock implements Data {
* @param bArray - Modbus Registers as bytes from 40096 to 40104
*/
public StringBlock(byte[] bArray) {
ByteBuffer wrap = ByteBuffer.wrap(bArray);
ValueBuffer wrap = ValueBuffer.wrap(bArray);
// straight forward - for each String the values Volt, Ampere and then Watt. All unt16 = 2 bytes values
string1Volt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.VOLT);
string2Volt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.VOLT);
string3Volt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.VOLT);
string1Volt = QuantityType.valueOf(wrap.getUInt16(), SmartHomeUnits.VOLT);
string2Volt = QuantityType.valueOf(wrap.getUInt16(), SmartHomeUnits.VOLT);
string3Volt = QuantityType.valueOf(wrap.getUInt16(), SmartHomeUnits.VOLT);
// E3DC Modbus Spec chapter 3.1.2, page 16 - Ampere values shall be handled with factor 0.01
string1Ampere = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.01), SmartHomeUnits.AMPERE);
string2Ampere = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.01), SmartHomeUnits.AMPERE);
string3Ampere = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.01), SmartHomeUnits.AMPERE);
string1Watt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.WATT);
string2Watt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.WATT);
string3Watt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.WATT);
string1Watt = QuantityType.valueOf(wrap.getUInt16(), SmartHomeUnits.WATT);
string2Watt = QuantityType.valueOf(wrap.getUInt16(), SmartHomeUnits.WATT);
string3Watt = QuantityType.valueOf(wrap.getUInt16(), SmartHomeUnits.WATT);
}
}

View File

@@ -25,7 +25,6 @@ import org.openhab.binding.modbus.e3dc.internal.dto.StringBlock;
import org.openhab.binding.modbus.e3dc.internal.dto.WallboxArray;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data.DataType;
import org.openhab.io.transport.modbus.AsyncModbusReadResult;
import org.openhab.io.transport.modbus.ModbusRegister;
import org.openhab.io.transport.modbus.ModbusRegisterArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,17 +58,10 @@ public class Parser {
}
public void handle(AsyncModbusReadResult result) {
byte[] newArray = new byte[size];
long startTime = System.currentTimeMillis();
Optional<ModbusRegisterArray> opt = result.getRegisters();
if (opt.isPresent()) {
ModbusRegisterArray registers = opt.get();
int i = 0;
for (ModbusRegister reg : registers) {
System.arraycopy(reg.getBytes(), 0, newArray, i, 2);
i += 2;
}
setArray(newArray);
setArray(opt.get().getBytes());
long duration = System.currentTimeMillis() - startTime;
avgDuration += duration;