From 5f6dca590568cca540094ac245f22f5e43f0c779 Mon Sep 17 00:00:00 2001 From: Torsten Oltmanns Date: Mon, 15 Jan 2024 11:01:17 +0800 Subject: [PATCH] created abstraction level for BMSes --- .../bms/daly/can/DalyBmsCANProcessor.java | 10 +- .../daly/common/AbstractDalyBmsProcessor.java | 5 +- .../bms/daly/rs485/DalyBmsRS485Processor.java | 1 + .../bms/jk/can/JKBmsCANProcessor.java | 90 ++++++++------- .../bms/pylon/can/PylonBmsCANProcessor.java | 108 +++++++++--------- .../bms/seplos/can/SeplosBmsCANProcessor.java | 107 ++++++++--------- .../core/AbstractBMSProcessor.java | 72 ------------ .../airepublic/bmstoinverter/core/BMS.java | 84 +++++++++++++- protocol-can/pom.xml | 7 ++ 9 files changed, 250 insertions(+), 234 deletions(-) delete mode 100644 core-api/src/main/java/com/airepublic/bmstoinverter/core/AbstractBMSProcessor.java diff --git a/bms-daly-can/src/main/java/com/airepublic/bmstoinverter/bms/daly/can/DalyBmsCANProcessor.java b/bms-daly-can/src/main/java/com/airepublic/bmstoinverter/bms/daly/can/DalyBmsCANProcessor.java index fe68379c..8bfbb13a 100644 --- a/bms-daly-can/src/main/java/com/airepublic/bmstoinverter/bms/daly/can/DalyBmsCANProcessor.java +++ b/bms-daly-can/src/main/java/com/airepublic/bmstoinverter/bms/daly/can/DalyBmsCANProcessor.java @@ -38,10 +38,11 @@ protected List sendMessage(final int bmsNo, final DalyCommand cmd, f final int frameCount = framesToBeReceived; int skip = 20; final List readBuffers = new ArrayList<>(); - final Port port = energyStorage.getBatteryPack(bmsNo).port; + @SuppressWarnings("resource") + final CANPort port = (CANPort) energyStorage.getBatteryPack(bmsNo).port; LOG.debug("SEND: {}", Port.printBuffer(sendFrame)); - ((CANPort) port).sendExtendedFrame(sendFrame); + port.sendExtendedFrame(sendFrame); // read frames until the requested frame is read do { @@ -91,6 +92,11 @@ protected ByteBuffer prepareSendFrame(final int address, final DalyCommand cmd, frameId += 0x40; sendFrame.putInt((int) frameId); + // sendFrame.put((byte) 0x40); + // sendFrame.put((byte) address); + // sendFrame.put((byte) cmd.id); + // sendFrame.put((byte) 0x18); + // header sendFrame.put((byte) 0x08) // data length .put((byte) 0) // flags diff --git a/bms-daly-common/src/main/java/com/airepublic/bmstoinverter/bms/daly/common/AbstractDalyBmsProcessor.java b/bms-daly-common/src/main/java/com/airepublic/bmstoinverter/bms/daly/common/AbstractDalyBmsProcessor.java index 3fb8db28..b7ea4a19 100644 --- a/bms-daly-common/src/main/java/com/airepublic/bmstoinverter/bms/daly/common/AbstractDalyBmsProcessor.java +++ b/bms-daly-common/src/main/java/com/airepublic/bmstoinverter/bms/daly/common/AbstractDalyBmsProcessor.java @@ -13,7 +13,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.airepublic.bmstoinverter.core.AbstractBMSProcessor; import com.airepublic.bmstoinverter.core.BMS; import com.airepublic.bmstoinverter.core.NoDataAvailableException; import com.airepublic.bmstoinverter.core.Port; @@ -29,7 +28,7 @@ * An abstraction for the Daly {@link BMS} since the {@link RS485} and {@link CAN} communication is * very similar. */ -public abstract class AbstractDalyBmsProcessor extends AbstractBMSProcessor implements BMS { +public abstract class AbstractDalyBmsProcessor extends BMS { private final static Logger LOG = LoggerFactory.getLogger(AbstractDalyBmsProcessor.class); @Inject private EnergyStorage energyStorage; @@ -69,7 +68,6 @@ public void initialize() { @Override public void collectData(final int bmsNo) throws IOException, TooManyInvalidFramesException, NoDataAvailableException { - sendMessage(bmsNo, DalyCommand.READ_VOUT_IOUT_SOC, requestData); // 0x90 sendMessage(bmsNo, DalyCommand.READ_MIN_MAX_CELL_VOLTAGE, requestData); // 0x91 sendMessage(bmsNo, DalyCommand.READ_MIN_MAX_TEMPERATURE, requestData); // 0x92 @@ -79,7 +77,6 @@ public void collectData(final int bmsNo) throws IOException, TooManyInvalidFrame sendMessage(bmsNo, DalyCommand.READ_CELL_TEMPERATURE, requestData); // 0x96 sendMessage(bmsNo, DalyCommand.READ_CELL_BALANCE_STATE, requestData); // 0x97 sendMessage(bmsNo, DalyCommand.READ_FAILURE_CODES, requestData); // 0x98 - } diff --git a/bms-daly-rs485/src/main/java/com/airepublic/bmstoinverter/bms/daly/rs485/DalyBmsRS485Processor.java b/bms-daly-rs485/src/main/java/com/airepublic/bmstoinverter/bms/daly/rs485/DalyBmsRS485Processor.java index 6b97fdb8..5c6defc0 100644 --- a/bms-daly-rs485/src/main/java/com/airepublic/bmstoinverter/bms/daly/rs485/DalyBmsRS485Processor.java +++ b/bms-daly-rs485/src/main/java/com/airepublic/bmstoinverter/bms/daly/rs485/DalyBmsRS485Processor.java @@ -48,6 +48,7 @@ protected List sendMessage(final int bmsNo, final DalyCommand cmd, f int framesToBeReceived = getResponseFrameCount(cmd); final int frameCount = framesToBeReceived; final List readBuffers = new ArrayList<>(); + @SuppressWarnings("resource") final RS485Port port = (RS485Port) energyStorage.getBatteryPack(bmsNo).port; int failureCount = 0; int noDataReceived = 0; diff --git a/bms-jk-can/src/main/java/com/airepublic/bmstoinverter/bms/jk/can/JKBmsCANProcessor.java b/bms-jk-can/src/main/java/com/airepublic/bmstoinverter/bms/jk/can/JKBmsCANProcessor.java index 57ab073d..93f06600 100644 --- a/bms-jk-can/src/main/java/com/airepublic/bmstoinverter/bms/jk/can/JKBmsCANProcessor.java +++ b/bms-jk-can/src/main/java/com/airepublic/bmstoinverter/bms/jk/can/JKBmsCANProcessor.java @@ -6,11 +6,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.airepublic.bmstoinverter.core.AbstractBMSProcessor; import com.airepublic.bmstoinverter.core.BMS; import com.airepublic.bmstoinverter.core.Port; import com.airepublic.bmstoinverter.core.PortType; import com.airepublic.bmstoinverter.core.Protocol; +import com.airepublic.bmstoinverter.core.bms.data.BatteryPack; import com.airepublic.bmstoinverter.core.bms.data.EnergyStorage; import com.airepublic.bmstoinverter.core.protocol.can.CAN; @@ -20,7 +20,7 @@ * The class to handle {@link CAN} messages from a JK {@link BMS}. */ @PortType(Protocol.CAN) -public class JKBmsCANProcessor extends AbstractBMSProcessor { +public class JKBmsCANProcessor extends BMS { private final static Logger LOG = LoggerFactory.getLogger(JKBmsCANProcessor.class); @Inject private EnergyStorage energyStorage; @@ -33,7 +33,8 @@ public void initialize() { @Override public void collectData(final int bmsNo) { try { - final Port port = energyStorage.getBatteryPack(bmsNo).port; + final BatteryPack pack = energyStorage.getBatteryPack(bmsNo); + final Port port = pack.port; final ByteBuffer frame = port.receiveFrame(null); final int frameId = frame.getInt(); final byte[] bytes = new byte[8]; @@ -42,16 +43,16 @@ public void collectData(final int bmsNo) { switch (frameId) { case 0x2F4: - readBatteryStatus(bmsNo, data); + readBatteryStatus(pack, data); break; case 0x4F4: - readCellVoltage(bmsNo, data); + readCellVoltage(pack, data); break; case 0x5F4: - readCellTemperature(bmsNo, data); + readCellTemperature(pack, data); break; case 0x7F4: - readAlarms(bmsNo, data); + readAlarms(pack, data); break; } @@ -61,14 +62,14 @@ public void collectData(final int bmsNo) { } - private void readBatteryStatus(final int bmsNo, final ByteBuffer data) { + private void readBatteryStatus(final BatteryPack pack, final ByteBuffer data) { // frame id is already read, so start at the first data byte // Battery voltage (0.1V) - energyStorage.getBatteryPack(bmsNo).packVoltage = data.getShort(); + pack.packVoltage = data.getShort(); // Battery current (0.1A) offset 4000 - energyStorage.getBatteryPack(bmsNo).packCurrent = data.getShort() - 4000; + pack.packCurrent = data.getShort() - 4000; // Battery SOC (1%) - energyStorage.getBatteryPack(bmsNo).packSOC = data.get(); + pack.packSOC = data.get(); // skip 1 byte data.get(); // discharge time, e.g. 100h (not mapped) @@ -76,57 +77,58 @@ private void readBatteryStatus(final int bmsNo, final ByteBuffer data) { } - private void readCellVoltage(final int bmsNo, final ByteBuffer data) { + private void readCellVoltage(final BatteryPack pack, final ByteBuffer data) { // frame id is already read, so start at the first data byte // Maximum cell voltage (1mV) - energyStorage.getBatteryPack(bmsNo).maxCellmV = data.getShort(); + pack.maxCellmV = data.getShort(); // Maximum cell voltage cell number - energyStorage.getBatteryPack(bmsNo).maxCellVNum = data.get(); + pack.maxCellVNum = data.get(); // Minimum cell voltage (1mV) - energyStorage.getBatteryPack(bmsNo).minCellmV = data.getShort(); + pack.minCellmV = data.getShort(); // Minimum cell voltage cell number - energyStorage.getBatteryPack(bmsNo).minCellVNum = data.get(); + pack.minCellVNum = data.get(); } - private void readCellTemperature(final int bmsNo, final ByteBuffer data) { + private void readCellTemperature(final BatteryPack pack, final ByteBuffer data) { // frame id is already read, so start at the first data byte // Maximum cell temperature (C) offset -50 - energyStorage.getBatteryPack(bmsNo).tempMax = data.get(); + pack.tempMax = data.get(); // Maximum cell temperature cell number data.get(); // Minimum cell temperature (C) offset -50 - energyStorage.getBatteryPack(bmsNo).tempMin = data.get(); + pack.tempMin = data.get(); // Minimum cell temperature cell number data.get(); // Average cell temperature (C) offset -50 - energyStorage.getBatteryPack(bmsNo).tempAverage = data.get(); + pack.tempAverage = data.get(); } - private void readAlarms(final int bmsNo, final ByteBuffer data) { + @SuppressWarnings("resource") + private void readAlarms(final BatteryPack pack, final ByteBuffer data) { // read first 8 bits byte value = data.get(); // unit overvoltage int bits = read2Bits(value, 0); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneCellVoltageTooHigh.value = bits == 1; - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoCellVoltageTooHigh.value = bits >= 2; + pack.alarms.levelOneCellVoltageTooHigh.value = bits == 1; + pack.alarms.levelTwoCellVoltageTooHigh.value = bits >= 2; // unit undervoltage bits = read2Bits(value, 2); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneCellVoltageTooLow.value = bits == 1; - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoCellVoltageTooLow.value = bits >= 2; + pack.alarms.levelOneCellVoltageTooLow.value = bits == 1; + pack.alarms.levelTwoCellVoltageTooLow.value = bits >= 2; // total voltage overvoltage bits = read2Bits(value, 4); - energyStorage.getBatteryPack(bmsNo).alarms.levelOnePackVoltageTooHigh.value = bits == 1; - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoPackVoltageTooHigh.value = bits >= 2; + pack.alarms.levelOnePackVoltageTooHigh.value = bits == 1; + pack.alarms.levelTwoPackVoltageTooHigh.value = bits >= 2; // total voltage undervoltage bits = read2Bits(value, 6); - energyStorage.getBatteryPack(bmsNo).alarms.levelOnePackVoltageTooLow.value = bits == 1; - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoPackVoltageTooLow.value = bits >= 2; + pack.alarms.levelOnePackVoltageTooLow.value = bits == 1; + pack.alarms.levelTwoPackVoltageTooLow.value = bits >= 2; // read next 8 bits value = data.get(); @@ -136,36 +138,36 @@ private void readAlarms(final int bmsNo, final ByteBuffer data) { // discharge overcurrent bits = read2Bits(value, 2); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneDischargeCurrentTooHigh.value = bits == 1; - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoDischargeCurrentTooHigh.value = bits >= 2; + pack.alarms.levelOneDischargeCurrentTooHigh.value = bits == 1; + pack.alarms.levelTwoDischargeCurrentTooHigh.value = bits >= 2; // charge overcurrent bits = read2Bits(value, 4); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneChargeCurrentTooHigh.value = bits == 1; - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoChargeCurrentTooHigh.value = bits >= 2; + pack.alarms.levelOneChargeCurrentTooHigh.value = bits == 1; + pack.alarms.levelTwoChargeCurrentTooHigh.value = bits >= 2; // temperature too high bits = read2Bits(value, 6); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneChargeTempTooHigh.value = bits == 1; - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoChargeTempTooHigh.value = bits >= 2; + pack.alarms.levelOneChargeTempTooHigh.value = bits == 1; + pack.alarms.levelTwoChargeTempTooHigh.value = bits >= 2; // read next 8 bits value = data.get(); // temperature too low bits = read2Bits(value, 0); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneChargeTempTooLow.value = bits == 1; - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoChargeTempTooLow.value = bits >= 2; + pack.alarms.levelOneChargeTempTooLow.value = bits == 1; + pack.alarms.levelTwoChargeTempTooLow.value = bits >= 2; // excessive temperature difference bits = read2Bits(value, 2); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneTempSensorDifferenceTooHigh.value = bits == 1; - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoTempSensorDifferenceTooHigh.value = bits >= 2; + pack.alarms.levelOneTempSensorDifferenceTooHigh.value = bits == 1; + pack.alarms.levelTwoTempSensorDifferenceTooHigh.value = bits >= 2; // SOC too low bits = read2Bits(value, 4); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneStateOfChargeTooLow.value = bits == 1; - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoStateOfChargeTooLow.value = bits >= 2; + pack.alarms.levelOneStateOfChargeTooLow.value = bits == 1; + pack.alarms.levelTwoStateOfChargeTooLow.value = bits >= 2; // insulation too low (not mapped) bits = read2Bits(value, 6); @@ -175,15 +177,15 @@ private void readAlarms(final int bmsNo, final ByteBuffer data) { // high voltage interlock fault bits = read2Bits(value, 0); - energyStorage.getBatteryPack(bmsNo).alarms.failureOfVoltageSensorModule.value = bits != 0; + pack.alarms.failureOfVoltageSensorModule.value = bits != 0; // external communication failure bits = read2Bits(value, 2); - energyStorage.getBatteryPack(bmsNo).alarms.failureOfVehicleCommunicationModule.value = bits != 0; + pack.alarms.failureOfVehicleCommunicationModule.value = bits != 0; // internal communication failure bits = read2Bits(value, 4); - energyStorage.getBatteryPack(bmsNo).alarms.failureOfIntranetCommunicationModule.value = bits != 0; + pack.alarms.failureOfIntranetCommunicationModule.value = bits != 0; } diff --git a/bms-pylon-can/src/main/java/com/airepublic/bmstoinverter/bms/pylon/can/PylonBmsCANProcessor.java b/bms-pylon-can/src/main/java/com/airepublic/bmstoinverter/bms/pylon/can/PylonBmsCANProcessor.java index 099c3cb0..39dccd20 100644 --- a/bms-pylon-can/src/main/java/com/airepublic/bmstoinverter/bms/pylon/can/PylonBmsCANProcessor.java +++ b/bms-pylon-can/src/main/java/com/airepublic/bmstoinverter/bms/pylon/can/PylonBmsCANProcessor.java @@ -6,11 +6,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.airepublic.bmstoinverter.core.AbstractBMSProcessor; import com.airepublic.bmstoinverter.core.BMS; import com.airepublic.bmstoinverter.core.Port; import com.airepublic.bmstoinverter.core.PortType; import com.airepublic.bmstoinverter.core.Protocol; +import com.airepublic.bmstoinverter.core.bms.data.BatteryPack; import com.airepublic.bmstoinverter.core.bms.data.EnergyStorage; import com.airepublic.bmstoinverter.core.protocol.can.CAN; @@ -21,7 +21,7 @@ */ @PortType(Protocol.CAN) -public class PylonBmsCANProcessor extends AbstractBMSProcessor { +public class PylonBmsCANProcessor extends BMS { private final static Logger LOG = LoggerFactory.getLogger(PylonBmsCANProcessor.class); @Inject private EnergyStorage energyStorage; @@ -34,7 +34,9 @@ public void initialize() { @Override public void collectData(final int bmsNo) { try { - final Port port = energyStorage.getBatteryPack(bmsNo).port; + + final BatteryPack pack = energyStorage.getBatteryPack(bmsNo); + final Port port = pack.port; final ByteBuffer frame = port.receiveFrame(null); final int frameId = frame.getInt(); final byte[] bytes = new byte[8]; @@ -43,28 +45,28 @@ public void collectData(final int bmsNo) { switch (frameId) { case 0x351: - readChargeDischargeInfo(bmsNo, data); + readChargeDischargeInfo(pack, data); break; case 0x355: - readSOC(bmsNo, data); + readSOC(pack, data); break; case 0x356: - readBatteryVoltage(bmsNo, data); + readBatteryVoltage(pack, data); break; case 0x35C: - requestChargeDischargeConfigChange(bmsNo, data); + requestChargeDischargeConfigChange(pack, data); break; case 0x370: - readMinMaxTemperatureVoltage(bmsNo, data); + readMinMaxTemperatureVoltage(pack, data); break; case 0x371: - readTemperatureIds(bmsNo, data); + readTemperatureIds(pack, data); break; case 0x35E: - readManufacturer(bmsNo, data); + readManufacturer(pack, data); break; case 0x359: - readAlarms(bmsNo, data); + readAlarms(pack, data); break; } } catch (final IOException e) { @@ -74,41 +76,41 @@ public void collectData(final int bmsNo) { // 0x351 - private void readChargeDischargeInfo(final int bmsNo, final ByteBuffer data) { + private void readChargeDischargeInfo(final BatteryPack pack, final ByteBuffer data) { // Battery charge voltage (0.1V) - uint_16 - energyStorage.getBatteryPack(bmsNo).maxPackVoltageLimit = data.getChar(); + pack.maxPackVoltageLimit = data.getChar(); // Charge current limit (0.1A) - sint_16 - energyStorage.getBatteryPack(bmsNo).maxPackChargeCurrent = data.getShort(); + pack.maxPackChargeCurrent = data.getShort(); // Discharge current limit (0.1A) - sint_16 - energyStorage.getBatteryPack(bmsNo).maxPackDischargeCurrent = data.getShort(); + pack.maxPackDischargeCurrent = data.getShort(); // Battery discharge voltage (0.1V) - uint_16 - energyStorage.getBatteryPack(bmsNo).minPackVoltageLimit = data.getChar(); + pack.minPackVoltageLimit = data.getChar(); } // 0x355 - private void readSOC(final int bmsNo, final ByteBuffer data) { + private void readSOC(final BatteryPack pack, final ByteBuffer data) { // SOC (1%) - uint_16 - energyStorage.getBatteryPack(bmsNo).maxPackDischargeCurrent = data.getChar(); + pack.maxPackDischargeCurrent = data.getChar(); // SOH (1%) - uint_16 - energyStorage.getBatteryPack(bmsNo).packVoltage = data.getChar(); + pack.packVoltage = data.getChar(); } // 0x356 - private void readBatteryVoltage(final int bmsNo, final ByteBuffer data) { + private void readBatteryVoltage(final BatteryPack pack, final ByteBuffer data) { // Battery voltage (0.01V) - uint_16 - energyStorage.getBatteryPack(bmsNo).packVoltage = data.getShort(); + pack.packVoltage = data.getShort(); // Battery current (0.1A) - uint_16 - energyStorage.getBatteryPack(bmsNo).packCurrent = data.getShort(); + pack.packCurrent = data.getShort(); // Battery current (0.1C) - uint_16 - energyStorage.getBatteryPack(bmsNo).tempAverage = data.getShort(); + pack.tempAverage = data.getShort(); } // 0x35C - private void requestChargeDischargeConfigChange(final int bmsNo, final ByteBuffer data) { + private void requestChargeDischargeConfigChange(final BatteryPack pack, final ByteBuffer data) { final byte bits = data.get(); if (bitRead(bits, 4)) { @@ -130,64 +132,64 @@ private void requestChargeDischargeConfigChange(final int bmsNo, final ByteBuffe // 0x370 - private void readMinMaxTemperatureVoltage(final int bmsNo, final ByteBuffer data) { + private void readMinMaxTemperatureVoltage(final BatteryPack pack, final ByteBuffer data) { // Maximum cell temperature (0.1C) - uint_16 - energyStorage.getBatteryPack(bmsNo).tempMax = data.getShort(); + pack.tempMax = data.getShort(); // Minimum cell temperature (0.1C) - uint_16 - energyStorage.getBatteryPack(bmsNo).tempMin = data.getShort(); + pack.tempMin = data.getShort(); // Maximum cell voltage (0.1V) - uint_16 - energyStorage.getBatteryPack(bmsNo).maxCellmV = data.getShort(); + pack.maxCellmV = data.getShort(); // Minimum cell voltage (0.1V) - uint_16 - energyStorage.getBatteryPack(bmsNo).minCellmV = data.getShort(); + pack.minCellmV = data.getShort(); } // 0x371 - private void readTemperatureIds(final int bmsNo, final ByteBuffer data) { + private void readTemperatureIds(final BatteryPack pack, final ByteBuffer data) { // Maximum cell temperature (0.1C) - uint_16 - // energyStorage.getBatteryPack(bmsNo).tempMax = data.getShort(); + // pack.tempMax = data.getShort(); // Minimum cell temperature (0.1C) - uint_16 - // energyStorage.getBatteryPack(bmsNo).tempMin = data.getShort(); + // pack.tempMin = data.getShort(); // Maximum cell voltage id - uint_16 - energyStorage.getBatteryPack(bmsNo).maxCellVNum = data.getShort(); + pack.maxCellVNum = data.getShort(); // Minimum cell voltage id - uint_16 - energyStorage.getBatteryPack(bmsNo).minCellVNum = data.getShort(); + pack.minCellVNum = data.getShort(); } // 0x35E - private void readManufacturer(final int bmsNo, final ByteBuffer data) { + private void readManufacturer(final BatteryPack pack, final ByteBuffer data) { final char first = (char) data.get(); final char second = (char) data.get(); - energyStorage.getBatteryPack(bmsNo).manufacturerCode = "" + first + second; + pack.manufacturerCode = "" + first + second; } // 0x359 - private void readAlarms(final int bmsNo, final ByteBuffer data) { + private void readAlarms(final BatteryPack pack, final ByteBuffer data) { // read first 8 bits int value = data.getInt(); // protection alarms - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoCellVoltageTooHigh.value = bitRead(value, 1); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoCellVoltageTooLow.value = bitRead(value, 2); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoDischargeTempTooHigh.value = bitRead(value, 3); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoDischargeTempTooLow.value = bitRead(value, 4); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoDischargeCurrentTooHigh.value = bitRead(value, 7); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoChargeCurrentTooHigh.value = bitRead(value, 8); + pack.alarms.levelTwoCellVoltageTooHigh.value = bitRead(value, 1); + pack.alarms.levelTwoCellVoltageTooLow.value = bitRead(value, 2); + pack.alarms.levelTwoDischargeTempTooHigh.value = bitRead(value, 3); + pack.alarms.levelTwoDischargeTempTooLow.value = bitRead(value, 4); + pack.alarms.levelTwoDischargeCurrentTooHigh.value = bitRead(value, 7); + pack.alarms.levelTwoChargeCurrentTooHigh.value = bitRead(value, 8); // warning alarms - energyStorage.getBatteryPack(bmsNo).alarms.levelOneCellVoltageTooHigh.value = bitRead(value, 17); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneCellVoltageTooLow.value = bitRead(value, 18); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneChargeTempTooHigh.value = bitRead(value, 19); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneChargeTempTooLow.value = bitRead(value, 20); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneDischargeCurrentTooHigh.value = bitRead(value, 23); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneChargeCurrentTooHigh.value = bitRead(value, 24); - energyStorage.getBatteryPack(bmsNo).alarms.failureOfIntranetCommunicationModule.value = bitRead(value, 27); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoCellVoltageDifferenceTooHigh.value = bitRead(value, 28); - - energyStorage.getBatteryPack(bmsNo).numberOfCells = data.get(); + pack.alarms.levelOneCellVoltageTooHigh.value = bitRead(value, 17); + pack.alarms.levelOneCellVoltageTooLow.value = bitRead(value, 18); + pack.alarms.levelOneChargeTempTooHigh.value = bitRead(value, 19); + pack.alarms.levelOneChargeTempTooLow.value = bitRead(value, 20); + pack.alarms.levelOneDischargeCurrentTooHigh.value = bitRead(value, 23); + pack.alarms.levelOneChargeCurrentTooHigh.value = bitRead(value, 24); + pack.alarms.failureOfIntranetCommunicationModule.value = bitRead(value, 27); + pack.alarms.levelTwoCellVoltageDifferenceTooHigh.value = bitRead(value, 28); + + pack.numberOfCells = data.get(); // skip two bytes data.getShort(); diff --git a/bms-seplos-can/src/main/java/com/airepublic/bmstoinverter/bms/seplos/can/SeplosBmsCANProcessor.java b/bms-seplos-can/src/main/java/com/airepublic/bmstoinverter/bms/seplos/can/SeplosBmsCANProcessor.java index 475d7a01..68f0eaef 100644 --- a/bms-seplos-can/src/main/java/com/airepublic/bmstoinverter/bms/seplos/can/SeplosBmsCANProcessor.java +++ b/bms-seplos-can/src/main/java/com/airepublic/bmstoinverter/bms/seplos/can/SeplosBmsCANProcessor.java @@ -6,11 +6,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.airepublic.bmstoinverter.core.AbstractBMSProcessor; import com.airepublic.bmstoinverter.core.BMS; import com.airepublic.bmstoinverter.core.Port; import com.airepublic.bmstoinverter.core.PortType; import com.airepublic.bmstoinverter.core.Protocol; +import com.airepublic.bmstoinverter.core.bms.data.BatteryPack; import com.airepublic.bmstoinverter.core.bms.data.EnergyStorage; import com.airepublic.bmstoinverter.core.protocol.can.CAN; @@ -20,7 +20,7 @@ * The class to handle {@link CAN} messages from a Seplos {@link BMS}. */ @PortType(Protocol.CAN) -public class SeplosBmsCANProcessor extends AbstractBMSProcessor { +public class SeplosBmsCANProcessor extends BMS { private final static Logger LOG = LoggerFactory.getLogger(SeplosBmsCANProcessor.class); @Inject private EnergyStorage energyStorage; @@ -33,7 +33,8 @@ public void initialize() { @Override public void collectData(final int bmsNo) { try { - final Port port = energyStorage.getBatteryPack(bmsNo).port; + final BatteryPack pack = energyStorage.getBatteryPack(bmsNo); + final Port port = pack.port; final ByteBuffer frame = port.receiveFrame(null); final int frameId = frame.getInt(); final byte[] bytes = new byte[8]; @@ -42,28 +43,28 @@ public void collectData(final int bmsNo) { switch (frameId) { case 0x351: - readChargeDischargeInfo(bmsNo, data); + readChargeDischargeInfo(pack, data); break; case 0x355: - readSOC(bmsNo, data); + readSOC(pack, data); break; case 0x356: - readBatteryVoltage(bmsNo, data); + readBatteryVoltage(pack, data); break; case 0x35C: - requestChargeDischargeConfigChange(bmsNo, data); + requestChargeDischargeConfigChange(pack, data); break; case 0x370: - readMinMaxTemperatureVoltage(bmsNo, data); + readMinMaxTemperatureVoltage(pack, data); break; case 0x371: - readTemperatureIds(bmsNo, data); + readTemperatureIds(pack, data); break; case 0x35E: - readManufacturer(bmsNo, data); + readManufacturer(pack, data); break; case 0x359: - readAlarms(bmsNo, data); + readAlarms(pack, data); break; } } catch (final IOException e) { @@ -73,41 +74,41 @@ public void collectData(final int bmsNo) { // 0x351 - private void readChargeDischargeInfo(final int bmsNo, final ByteBuffer data) { + private void readChargeDischargeInfo(final BatteryPack pack, final ByteBuffer data) { // Battery charge voltage (0.1V) - uint_16 - energyStorage.getBatteryPack(bmsNo).maxPackVoltageLimit = data.getChar(); + pack.maxPackVoltageLimit = data.getChar(); // Charge current limit (0.1A) - sint_16 - energyStorage.getBatteryPack(bmsNo).maxPackChargeCurrent = data.getShort(); + pack.maxPackChargeCurrent = data.getShort(); // Discharge current limit (0.1A) - sint_16 - energyStorage.getBatteryPack(bmsNo).maxPackDischargeCurrent = data.getShort(); + pack.maxPackDischargeCurrent = data.getShort(); // Battery discharge voltage (0.1V) - uint_16 - energyStorage.getBatteryPack(bmsNo).minPackVoltageLimit = data.getChar(); + pack.minPackVoltageLimit = data.getChar(); } // 0x355 - private void readSOC(final int bmsNo, final ByteBuffer data) { + private void readSOC(final BatteryPack pack, final ByteBuffer data) { // SOC (1%) - uint_16 - energyStorage.getBatteryPack(bmsNo).maxPackDischargeCurrent = data.getChar(); + pack.maxPackDischargeCurrent = data.getChar(); // SOH (1%) - uint_16 - energyStorage.getBatteryPack(bmsNo).packVoltage = data.getChar(); + pack.packVoltage = data.getChar(); } // 0x356 - private void readBatteryVoltage(final int bmsNo, final ByteBuffer data) { + private void readBatteryVoltage(final BatteryPack pack, final ByteBuffer data) { // Battery voltage (0.01V) - uint_16 - energyStorage.getBatteryPack(bmsNo).packVoltage = data.getShort(); + pack.packVoltage = data.getShort(); // Battery current (0.1A) - uint_16 - energyStorage.getBatteryPack(bmsNo).packCurrent = data.getShort(); + pack.packCurrent = data.getShort(); // Battery current (0.1C) - uint_16 - energyStorage.getBatteryPack(bmsNo).tempAverage = data.getShort(); + pack.tempAverage = data.getShort(); } // 0x35C - private void requestChargeDischargeConfigChange(final int bmsNo, final ByteBuffer data) { + private void requestChargeDischargeConfigChange(final BatteryPack pack, final ByteBuffer data) { final byte bits = data.get(); if (bitRead(bits, 4)) { @@ -129,64 +130,64 @@ private void requestChargeDischargeConfigChange(final int bmsNo, final ByteBuffe // 0x370 - private void readMinMaxTemperatureVoltage(final int bmsNo, final ByteBuffer data) { + private void readMinMaxTemperatureVoltage(final BatteryPack pack, final ByteBuffer data) { // Maximum cell temperature (0.1C) - uint_16 - energyStorage.getBatteryPack(bmsNo).tempMax = data.getShort(); + pack.tempMax = data.getShort(); // Minimum cell temperature (0.1C) - uint_16 - energyStorage.getBatteryPack(bmsNo).tempMin = data.getShort(); + pack.tempMin = data.getShort(); // Maximum cell voltage (0.1V) - uint_16 - energyStorage.getBatteryPack(bmsNo).maxCellmV = data.getShort(); + pack.maxCellmV = data.getShort(); // Minimum cell voltage (0.1V) - uint_16 - energyStorage.getBatteryPack(bmsNo).minCellmV = data.getShort(); + pack.minCellmV = data.getShort(); } // 0x371 - private void readTemperatureIds(final int bmsNo, final ByteBuffer data) { + private void readTemperatureIds(final BatteryPack pack, final ByteBuffer data) { // Maximum cell temperature (0.1C) - uint_16 - // energyStorage.getBatteryPack(bmsNo).tempMax = data.getShort(); + // pack.tempMax = data.getShort(); // Minimum cell temperature (0.1C) - uint_16 - // energyStorage.getBatteryPack(bmsNo).tempMin = data.getShort(); + // pack.tempMin = data.getShort(); // Maximum cell voltage id - uint_16 - energyStorage.getBatteryPack(bmsNo).maxCellVNum = data.getShort(); + pack.maxCellVNum = data.getShort(); // Minimum cell voltage id - uint_16 - energyStorage.getBatteryPack(bmsNo).minCellVNum = data.getShort(); + pack.minCellVNum = data.getShort(); } // 0x35E - private void readManufacturer(final int bmsNo, final ByteBuffer data) { + private void readManufacturer(final BatteryPack pack, final ByteBuffer data) { final char first = (char) data.get(); final char second = (char) data.get(); - energyStorage.getBatteryPack(bmsNo).manufacturerCode = "" + first + second; + pack.manufacturerCode = "" + first + second; } // 0x359 - private void readAlarms(final int bmsNo, final ByteBuffer data) { + private void readAlarms(final BatteryPack pack, final ByteBuffer data) { // read first 8 bits int value = data.getInt(); // protection alarms - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoCellVoltageTooHigh.value = bitRead(value, 1); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoCellVoltageTooLow.value = bitRead(value, 2); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoDischargeTempTooHigh.value = bitRead(value, 3); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoDischargeTempTooLow.value = bitRead(value, 4); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoDischargeCurrentTooHigh.value = bitRead(value, 7); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoChargeCurrentTooHigh.value = bitRead(value, 8); + pack.alarms.levelTwoCellVoltageTooHigh.value = bitRead(value, 1); + pack.alarms.levelTwoCellVoltageTooLow.value = bitRead(value, 2); + pack.alarms.levelTwoDischargeTempTooHigh.value = bitRead(value, 3); + pack.alarms.levelTwoDischargeTempTooLow.value = bitRead(value, 4); + pack.alarms.levelTwoDischargeCurrentTooHigh.value = bitRead(value, 7); + pack.alarms.levelTwoChargeCurrentTooHigh.value = bitRead(value, 8); // warning alarms - energyStorage.getBatteryPack(bmsNo).alarms.levelOneCellVoltageTooHigh.value = bitRead(value, 17); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneCellVoltageTooLow.value = bitRead(value, 18); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneChargeTempTooHigh.value = bitRead(value, 19); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneChargeTempTooLow.value = bitRead(value, 20); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneDischargeCurrentTooHigh.value = bitRead(value, 23); - energyStorage.getBatteryPack(bmsNo).alarms.levelOneChargeCurrentTooHigh.value = bitRead(value, 24); - energyStorage.getBatteryPack(bmsNo).alarms.failureOfIntranetCommunicationModule.value = bitRead(value, 27); - energyStorage.getBatteryPack(bmsNo).alarms.levelTwoCellVoltageDifferenceTooHigh.value = bitRead(value, 28); - - energyStorage.getBatteryPack(bmsNo).numberOfCells = data.get(); + pack.alarms.levelOneCellVoltageTooHigh.value = bitRead(value, 17); + pack.alarms.levelOneCellVoltageTooLow.value = bitRead(value, 18); + pack.alarms.levelOneChargeTempTooHigh.value = bitRead(value, 19); + pack.alarms.levelOneChargeTempTooLow.value = bitRead(value, 20); + pack.alarms.levelOneDischargeCurrentTooHigh.value = bitRead(value, 23); + pack.alarms.levelOneChargeCurrentTooHigh.value = bitRead(value, 24); + pack.alarms.failureOfIntranetCommunicationModule.value = bitRead(value, 27); + pack.alarms.levelTwoCellVoltageDifferenceTooHigh.value = bitRead(value, 28); + + pack.numberOfCells = data.get(); // skip two bytes data.getShort(); diff --git a/core-api/src/main/java/com/airepublic/bmstoinverter/core/AbstractBMSProcessor.java b/core-api/src/main/java/com/airepublic/bmstoinverter/core/AbstractBMSProcessor.java deleted file mode 100644 index 5f908def..00000000 --- a/core-api/src/main/java/com/airepublic/bmstoinverter/core/AbstractBMSProcessor.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.airepublic.bmstoinverter.core; - -import java.io.IOException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.airepublic.bmstoinverter.core.bms.data.BatteryPack; -import com.airepublic.bmstoinverter.core.bms.data.EnergyStorage; - -import jakarta.inject.Inject; - -public abstract class AbstractBMSProcessor implements BMS { - private final static Logger LOG = LoggerFactory.getLogger(AbstractBMSProcessor.class); - @Inject - private EnergyStorage energyStorage; - - @Override - public void process(final Runnable callback) { - try { - LOG.info("---------------------------------> Thread " + Thread.currentThread().getId()); - clearBuffers(); - - for (int bmsNo = 0; bmsNo < energyStorage.getBatteryPackCount(); bmsNo++) { - final Port port = energyStorage.getBatteryPack(bmsNo).port; - - try { - port.ensureOpen(); - collectData(bmsNo); - } catch (final NoDataAvailableException e) { - LOG.error("Received no bytes too many times - trying to close and re-open port!"); - // try to close and re-open the port - port.close(); - port.open(); - } - } - // autoCalibrateSOC(); - } catch (final TooManyInvalidFramesException e) { - LOG.error("Received too many invalid frames - start new reading round!"); - return; - } catch (final Throwable e) { - LOG.error("Error requesting data!", e); - return; - } - - try { - callback.run(); - } catch (final Throwable e) { - LOG.error("BMS process callback threw an exception!", e); - } - } - - - protected abstract void collectData(int bmsNo) throws IOException, TooManyInvalidFramesException, NoDataAvailableException; - - - /** - * Clears any buffers or queues on all associated ports to restart communication. - */ - protected void clearBuffers() { - for (final BatteryPack pack : energyStorage.getBatteryPacks()) { - pack.port.clearBuffers(); - } - } - - - @Override - public void close() throws Exception { - energyStorage.close(); - } - -} diff --git a/core-api/src/main/java/com/airepublic/bmstoinverter/core/BMS.java b/core-api/src/main/java/com/airepublic/bmstoinverter/core/BMS.java index 9d5e3b53..d7cbba10 100644 --- a/core-api/src/main/java/com/airepublic/bmstoinverter/core/BMS.java +++ b/core-api/src/main/java/com/airepublic/bmstoinverter/core/BMS.java @@ -1,23 +1,95 @@ package com.airepublic.bmstoinverter.core; +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.airepublic.bmstoinverter.core.bms.data.BatteryPack; import com.airepublic.bmstoinverter.core.bms.data.EnergyStorage; +import jakarta.inject.Inject; + /** - * The interface to identify a BMS. + * The abstract class to identify a BMS. */ -public interface BMS extends AutoCloseable { +public abstract class BMS implements AutoCloseable { + private final static Logger LOG = LoggerFactory.getLogger(BMS.class); + @Inject + private EnergyStorage energyStorage; /** * Any on-startup neccessary code should go here. */ - void initialize(); + public abstract void initialize(); + + + /** + * Processes the collection of data for each configured {@link BatteryPack}. + * + * @param callback the function will be called after successfully collecting data from all + * {@link BatteryPack}s + */ + public final void process(final Runnable callback) { + try { + LOG.info("---------------------------------> Thread " + Thread.currentThread().getId()); + clearBuffers(); + + for (int bmsNo = 0; bmsNo < energyStorage.getBatteryPackCount(); bmsNo++) { + @SuppressWarnings("resource") + final Port port = energyStorage.getBatteryPack(bmsNo).port; + + try { + port.ensureOpen(); + collectData(bmsNo); + } catch (final NoDataAvailableException e) { + LOG.error("Received no bytes too many times - trying to close and re-open port!"); + // try to close and re-open the port + port.close(); + port.open(); + } + } + // autoCalibrateSOC(); + } catch (final TooManyInvalidFramesException e) { + LOG.error("Received too many invalid frames - start new reading round!"); + return; + } catch (final Throwable e) { + LOG.error("Error requesting data!", e); + return; + } + + try { + callback.run(); + } catch (final Throwable e) { + LOG.error("BMS process callback threw an exception!", e); + } + } /** - * Process data received by the port and update the {@link EnergyStorage} for a {@link BMS}. + * Processes the collection of data from the specified {@link BatteryPack}. * - * @param callback the code executed after successful processing + * @param bmsNo the index of the {@link BatteryPack} in the {@link EnergyStorage} + * @throws IOException if there is a problem with the port + * @throws TooManyInvalidFramesException when too many invalid frames were received + * @throws NoDataAvailableException when no data was received too many times + */ + protected abstract void collectData(int bmsNo) throws IOException, TooManyInvalidFramesException, NoDataAvailableException; + + + /** + * Clears any buffers or queues on all associated ports to restart communication. */ - void process(Runnable callback); + protected void clearBuffers() { + for (final BatteryPack pack : energyStorage.getBatteryPacks()) { + pack.port.clearBuffers(); + } + } + + + @Override + public void close() throws Exception { + energyStorage.close(); + } } diff --git a/protocol-can/pom.xml b/protocol-can/pom.xml index 087e8f68..db2ae522 100644 --- a/protocol-can/pom.xml +++ b/protocol-can/pom.xml @@ -61,5 +61,12 @@ 3.2.4 + + org.junit.jupiter + junit-jupiter + 5.9.3 + test + + \ No newline at end of file