Skip to content

Commit

Permalink
made the BMS processing more resilient by closing and reopening the port
Browse files Browse the repository at this point in the history
in case of too many no-bytes readings
  • Loading branch information
ai-republic committed Jan 13, 2024
1 parent 126a6b4 commit d953a1a
Show file tree
Hide file tree
Showing 15 changed files with 291 additions and 255 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.airepublic.bmstoinverter.core.Bms;
import com.airepublic.bmstoinverter.core.AbstractBMSProcessor;
import com.airepublic.bmstoinverter.core.BMS;
import com.airepublic.bmstoinverter.core.NoDataAvailableException;
import com.airepublic.bmstoinverter.core.Port;
import com.airepublic.bmstoinverter.core.TooManyInvalidFramesException;
import com.airepublic.bmstoinverter.core.bms.data.BatteryPack;
import com.airepublic.bmstoinverter.core.bms.data.EnergyStorage;
import com.airepublic.bmstoinverter.core.protocol.can.CAN;
Expand All @@ -23,10 +26,10 @@
import jakarta.inject.Inject;

/**
* An abstraction for the Daly {@link Bms} since the {@link RS485} and {@link CAN} communication is
* An abstraction for the Daly {@link BMS} since the {@link RS485} and {@link CAN} communication is
* very similar.
*/
public abstract class AbstractDalyBmsProcessor implements Bms {
public abstract class AbstractDalyBmsProcessor extends AbstractBMSProcessor implements BMS {
private final static Logger LOG = LoggerFactory.getLogger(AbstractDalyBmsProcessor.class);
@Inject
private EnergyStorage energyStorage;
Expand Down Expand Up @@ -65,36 +68,18 @@ public void initialize() {


@Override
public void process(final Runnable callback) {
try {
LOG.info("---------------------------------> Thread " + Thread.currentThread().getId());
clearBuffers();

for (int bmsNo = 0; bmsNo < energyStorage.getBatteryPackCount(); bmsNo++) {
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
sendMessage(bmsNo, DalyCommand.READ_DISCHARGE_CHARGE_MOS_STATUS, requestData); // 0x93
sendMessage(bmsNo, DalyCommand.READ_STATUS_INFO, requestData); // 0x94
sendMessage(bmsNo, DalyCommand.READ_CELL_VOLTAGES, requestData); // 0x95
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
}

// autoCalibrateSOC();
} catch (final NoDataAvailableException e) {
return;
} catch (final Throwable e) {
LOG.error("Error requesting data!", e);
return;
}
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
sendMessage(bmsNo, DalyCommand.READ_DISCHARGE_CHARGE_MOS_STATUS, requestData); // 0x93
sendMessage(bmsNo, DalyCommand.READ_STATUS_INFO, requestData); // 0x94
sendMessage(bmsNo, DalyCommand.READ_CELL_VOLTAGES, requestData); // 0x95
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

try {
callback.run();
} catch (final Throwable e) {
LOG.error("BMS process callback threw an exception!", e);
}
}


Expand Down Expand Up @@ -153,7 +138,7 @@ protected void autoCalibrateSOC() {
* @return
* @throws IOException
*/
protected abstract List<ByteBuffer> sendMessage(final int bmsNo, final DalyCommand cmd, final byte[] data) throws IOException;
protected abstract List<ByteBuffer> sendMessage(final int bmsNo, final DalyCommand cmd, final byte[] data) throws IOException, NoDataAvailableException, TooManyInvalidFramesException;


/**
Expand Down Expand Up @@ -195,13 +180,4 @@ protected int getResponseFrameCount(final DalyCommand cmd) {
*/
protected abstract DalyMessage convertReceiveFrameToDalyMessage(final ByteBuffer buffer);


/**
* Clears any buffers or queues on all associated ports to restart communication.
*/
protected void clearBuffers() {
for (final BatteryPack pack : energyStorage.getBatteryPacks()) {
pack.port.clearBuffers();
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
import com.airepublic.bmstoinverter.bms.daly.common.AbstractDalyBmsProcessor;
import com.airepublic.bmstoinverter.bms.daly.common.DalyCommand;
import com.airepublic.bmstoinverter.bms.daly.common.DalyMessage;
import com.airepublic.bmstoinverter.bms.daly.common.NoDataAvailableException;
import com.airepublic.bmstoinverter.core.NoDataAvailableException;
import com.airepublic.bmstoinverter.core.Port;
import com.airepublic.bmstoinverter.core.PortType;
import com.airepublic.bmstoinverter.core.Protocol;
import com.airepublic.bmstoinverter.core.TooManyInvalidFramesException;
import com.airepublic.bmstoinverter.core.bms.data.EnergyStorage;
import com.airepublic.bmstoinverter.core.protocol.rs485.RS485Port;

Expand All @@ -41,35 +42,49 @@ public class DalyBmsRS485Processor extends AbstractDalyBmsProcessor {
};

@Override
protected List<ByteBuffer> sendMessage(final int bmsNo, final DalyCommand cmd, final byte[] data) throws IOException {
protected List<ByteBuffer> sendMessage(final int bmsNo, final DalyCommand cmd, final byte[] data) throws IOException, TooManyInvalidFramesException, NoDataAvailableException {
final int address = bmsNo + 0x40;
final ByteBuffer sendBuffer = prepareSendFrame(address, cmd, data);
int framesToBeReceived = getResponseFrameCount(cmd);
final int frameCount = framesToBeReceived;
final List<ByteBuffer> readBuffers = new ArrayList<>();
final RS485Port port = (RS485Port) energyStorage.getBatteryPack(bmsNo).port;
int failureCount = 0;
int noDataReceived = 0;

// read frames until the requested frame is read
do {

// send the request command frame
port.sendFrame(sendBuffer);
LOG.debug("SEND: {}", Port.printBuffer(sendBuffer));

// read the expected response frame(s)
for (int i = 0; i < frameCount; i++) {
final ByteBuffer receiveBuffer = port.receiveFrame(validator);

// check if a valid frame was received or no bytes
if (receiveBuffer == null || receiveBuffer.capacity() < port.getFrameLength()) {
failureCount++;

// did we receive an invalid frame length
if (receiveBuffer != null && receiveBuffer.capacity() < port.getFrameLength()) {
// keep track of how often invalid frames were received
failureCount++;
LOG.debug("Wrong number of bytes received! {}", Port.printBuffer(receiveBuffer));
} else {
LOG.warn("No bytes received: " + failureCount + " times!");
}

if (failureCount >= 10) {
LOG.error("Received wrong number of bytes too many times - start new reading round!");
throw new NoDataAvailableException();
if (failureCount >= 10) {
throw new TooManyInvalidFramesException();
}
} else { // we received no bytes at all
// keep track of how often no bytes could be read
noDataReceived++;
LOG.warn("No bytes received: " + noDataReceived + " times!");

// if we received no bytes more than 10 times we stop and notify the handler
// to re-open the port
if (noDataReceived >= 10) {
throw new NoDataAvailableException();
}
}

// try and wait for the next message to arrive
Expand All @@ -79,25 +94,24 @@ protected List<ByteBuffer> sendMessage(final int bmsNo, final DalyCommand cmd, f
} catch (final InterruptedException e) {
}

// try to receive the response again
i--;
} else {
LOG.debug("RECEIVED: {}", Port.printBuffer(receiveBuffer));

continue;
}

LOG.debug("RECEIVED: {}", Port.printBuffer(receiveBuffer));

if (receiveBuffer.get(1) == (byte) (address - 0x40 + 1) && receiveBuffer.get(2) == (byte) cmd.id) {
framesToBeReceived--;
readBuffers.add(receiveBuffer);
}
if (receiveBuffer.get(1) == (byte) (address - 0x40 + 1) && receiveBuffer.get(2) == (byte) cmd.id) {
framesToBeReceived--;
readBuffers.add(receiveBuffer);
}

final DalyMessage dalyMsg = convertReceiveFrameToDalyMessage(receiveBuffer);
final DalyMessage dalyMsg = convertReceiveFrameToDalyMessage(receiveBuffer);

if (dalyMsg != null) {
getMessageHandler().handleMessage(dalyMsg);
} else {
LOG.warn("Message could not be interpreted " + Port.printBuffer(receiveBuffer));
return readBuffers;
if (dalyMsg != null) {
getMessageHandler().handleMessage(dalyMsg);
} else {
LOG.warn("Message could not be interpreted " + Port.printBuffer(receiveBuffer));
return readBuffers;
}
}
}
} while (framesToBeReceived > 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.airepublic.bmstoinverter.core.Bms;
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;
Expand All @@ -16,10 +17,10 @@
import jakarta.inject.Inject;

/**
* The class to handle {@link CAN} messages from a JK {@link Bms}.
* The class to handle {@link CAN} messages from a JK {@link BMS}.
*/
@PortType(Protocol.CAN)
public class JKBmsCANProcessor implements Bms {
public class JKBmsCANProcessor extends AbstractBMSProcessor {
private final static Logger LOG = LoggerFactory.getLogger(JKBmsCANProcessor.class);
@Inject
private EnergyStorage energyStorage;
Expand All @@ -30,40 +31,32 @@ public void initialize() {


@Override
public void process(final Runnable callback) {
for (int bmsNo = 0; bmsNo < energyStorage.getBatteryPackCount(); bmsNo++) {
try {
final Port port = energyStorage.getBatteryPack(bmsNo).port;
final ByteBuffer frame = port.receiveFrame(null);
final int frameId = frame.getInt();
final byte[] bytes = new byte[8];
frame.get(bytes);
final ByteBuffer data = ByteBuffer.wrap(bytes);

switch (frameId) {
case 0x2F4:
readBatteryStatus(bmsNo, data);
break;
case 0x4F4:
readCellVoltage(bmsNo, data);
break;
case 0x5F4:
readCellTemperature(bmsNo, data);
break;
case 0x7F4:
readAlarms(bmsNo, data);
break;
}

} catch (final IOException e) {
LOG.error("Error receiving frame!", e);
public void collectData(final int bmsNo) {
try {
final Port port = energyStorage.getBatteryPack(bmsNo).port;
final ByteBuffer frame = port.receiveFrame(null);
final int frameId = frame.getInt();
final byte[] bytes = new byte[8];
frame.get(bytes);
final ByteBuffer data = ByteBuffer.wrap(bytes);

switch (frameId) {
case 0x2F4:
readBatteryStatus(bmsNo, data);
break;
case 0x4F4:
readCellVoltage(bmsNo, data);
break;
case 0x5F4:
readCellTemperature(bmsNo, data);
break;
case 0x7F4:
readAlarms(bmsNo, data);
break;
}
}

try {
callback.run();
} catch (final Exception e) {
LOG.error("BMS process callback threw an exception!", e);
} catch (final IOException e) {
LOG.error("Error receiving frame!", e);
}
}

Expand Down
Loading

0 comments on commit d953a1a

Please sign in to comment.