Skip to content

Commit

Permalink
added Narada BMS ModBus binding
Browse files Browse the repository at this point in the history
  • Loading branch information
ai-republic committed Oct 20, 2024
1 parent eb5eeb6 commit 2fafe32
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 0 deletions.
4 changes: 4 additions & 0 deletions bms-narada-modbus/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/target/
/.classpath
/.project
/.settings/
30 changes: 30 additions & 0 deletions bms-narada-modbus/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.ai-republic.bms-to-inverter</groupId>
<artifactId>bms-to-inverter-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

<artifactId>bms-narada-modbus</artifactId>

<name>${project.artifactId}-${project.version}</name>
<description>Module for the Narada BMS ModBus support</description>

<properties>
<encoding>UTF-8</encoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>com.ai-republic.bms-to-inverter</groupId>
<artifactId>protocol-modbus</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* This software is free to use and to distribute in its unchanged form for private use.
* Commercial use is prohibited without an explicit license agreement of the copyright holder.
* Any changes to this software must be made solely in the project repository at https://github.com/ai-republic/bms-to-inverter.
* The copyright holder is not liable for any damages in whatever form that may occur by using this software.
*
* (c) Copyright 2022 and onwards - Torsten Oltmanns
*
* @author Torsten Oltmanns - bms-to-inverter''AT''gmail.com
*/
package com.airepublic.bmstoinverter.bms.narada.modbus;

import com.airepublic.bmstoinverter.core.BMS;
import com.airepublic.bmstoinverter.core.BMSConfig;
import com.airepublic.bmstoinverter.core.BMSDescriptor;
import com.airepublic.bmstoinverter.core.Port;
import com.airepublic.bmstoinverter.protocol.modbus.J2ModMasterPort;

/**
* The {@link BMSDescriptor} for the Narada BMS using the Modbus protocol.
*/
public class NaradaBmsModbusDescriptor implements BMSDescriptor {
@Override
public String getName() {
return "NARADA_MODBUS";
}


@Override
public int getDefaultBaudRate() {
return 9600;
}


@Override
public Class<? extends BMS> getBMSClass() {
return NaradaBmsModbusProcessor.class;
}


@Override
public Port createPort(final BMSConfig config) {
final Port port = new J2ModMasterPort(config.getPortLocator(), config.getBaudRate());
return port;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/**
* This software is free to use and to distribute in its unchanged form for private use.
* Commercial use is prohibited without an explicit license agreement of the copyright holder.
* Any changes to this software must be made solely in the project repository at https://github.com/ai-republic/bms-to-inverter.
* The copyright holder is not liable for any damages in whatever form that may occur by using this software.
*
* (c) Copyright 2022 and onwards - Torsten Oltmanns
*
* @author Torsten Oltmanns - bms-to-inverter''AT''gmail.com
*/
package com.airepublic.bmstoinverter.bms.narada.modbus;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.function.Consumer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.airepublic.bmstoinverter.core.AlarmLevel;
import com.airepublic.bmstoinverter.core.BMS;
import com.airepublic.bmstoinverter.core.Port;
import com.airepublic.bmstoinverter.core.bms.data.Alarm;
import com.airepublic.bmstoinverter.core.bms.data.BatteryPack;
import com.airepublic.bmstoinverter.core.bms.data.EnergyStorage;
import com.airepublic.bmstoinverter.core.util.Util;
import com.airepublic.bmstoinverter.protocol.modbus.ModbusUtil;
import com.airepublic.bmstoinverter.protocol.modbus.ModbusUtil.RegisterCode;

import jakarta.inject.Inject;

/**
* The class to handle Modbus messages from a Narada {@link BMS}.
*/
public class NaradaBmsModbusProcessor extends BMS {
private final static Logger LOG = LoggerFactory.getLogger(NaradaBmsModbusProcessor.class);
@Inject
private EnergyStorage energyStorage;

@Override
protected void collectData(final Port port) {
try {
sendMessage(port, RegisterCode.READ_INPUT_REGISTERS, 0x0FFF, 50, getBmsId(), this::readBatteryStatus);
} catch (final IOException e) {
LOG.error("Error reading from modbus!", e);
}
}


protected void sendMessage(final Port port, final RegisterCode functionCode, final int startAddress, final int numRegisters, final int unitId, final Consumer<ByteBuffer> handler) throws IOException {
port.sendFrame(ModbusUtil.createRequestBuffer(functionCode, startAddress, numRegisters, unitId));
handler.accept(port.receiveFrame());
}


protected void readBatteryStatus(final ByteBuffer frame) {
frame.getInt(); // functionCode
frame.getInt(); // numRegisters
final int unitId = frame.getInt();
final BatteryPack pack = energyStorage.getBatteryPack(unitId);

pack.packVoltage = frame.getShort() / 10; // 0.01V
pack.packCurrent = frame.getShort() - 10000; // 0.1A
pack.remainingCapacitymAh = frame.getShort() * 100; // 0.1A
pack.tempAverage = frame.getShort() - 400; // 0.1C - 400
frame.getShort(); // env temp 0.1C - 400
final int warningFlag = frame.getChar();
final int protectionFlag = frame.getShort();
final int statusFlag = frame.getShort();
pack.packSOC = frame.getShort() / 10; // 0.01%
pack.bmsCycles = frame.getShort();
pack.packSOH = frame.getShort() / 10; // 0.01%
frame.getShort(); // history discharge capacity 10A
pack.numberOfCells = frame.getShort();

// determine min/max cell voltages
for (int i = 0; i < 16; i++) {
if (i < pack.numberOfCells) {
pack.cellVmV[i] = frame.getShort();

if (pack.cellVmV[i] > pack.maxCellmV) {
pack.maxCellmV = pack.cellVmV[i];
pack.maxCellVNum = i;
} else if (pack.cellVmV[i] < pack.minCellmV) {
pack.minCellmV = pack.cellVmV[i];
pack.minCellVNum = i;
}
} else {
frame.getShort();
}
}

// calculate cell voltage difference
pack.cellDiffmV = pack.maxCellmV - pack.minCellmV;

pack.numOfTempSensors = frame.getShort();

for (int i = 0; i < 16; i++) {
if (i < pack.numOfTempSensors) {
pack.cellTemperature[i] = frame.getShort() - 400; // 0.1C - 400
} else {
frame.getShort();
}
}

pack.ratedCapacitymAh = frame.getShort() * 100; // 0.1A
frame.getShort(); // remaining charge time 1min
frame.getShort(); // remaining discharge time 1min
final int cellUVStatus = frame.getShort(); // Cell undervoltage state

readAlarms(pack, warningFlag, protectionFlag, statusFlag, cellUVStatus);
}


private void readAlarms(final BatteryPack pack, final int warningFlag, final int protectionFlag, final int faultStatus, final int cellUVStatus) {
// warnings
pack.alarms.put(Alarm.CELL_VOLTAGE_HIGH, Util.bit(warningFlag, 0) ? AlarmLevel.WARNING : AlarmLevel.NONE);
pack.alarms.put(Alarm.CELL_VOLTAGE_LOW, Util.bit(warningFlag, 1) ? AlarmLevel.WARNING : AlarmLevel.NONE);
pack.alarms.put(Alarm.PACK_VOLTAGE_HIGH, Util.bit(warningFlag, 2) ? AlarmLevel.WARNING : AlarmLevel.NONE);
pack.alarms.put(Alarm.PACK_VOLTAGE_LOW, Util.bit(warningFlag, 3) ? AlarmLevel.WARNING : AlarmLevel.NONE);
pack.alarms.put(Alarm.CHARGE_CURRENT_HIGH, Util.bit(warningFlag, 4) ? AlarmLevel.WARNING : AlarmLevel.NONE);
pack.alarms.put(Alarm.DISCHARGE_CURRENT_HIGH, Util.bit(warningFlag, 5) ? AlarmLevel.WARNING : AlarmLevel.NONE);
pack.alarms.put(Alarm.CELL_TEMPERATURE_HIGH, Util.bit(warningFlag, 6) ? AlarmLevel.WARNING : AlarmLevel.NONE);
pack.alarms.put(Alarm.CELL_TEMPERATURE_LOW, Util.bit(warningFlag, 7) ? AlarmLevel.WARNING : AlarmLevel.NONE);
pack.alarms.put(Alarm.ENCASING_TEMPERATURE_HIGH, Util.bit(warningFlag, 8) ? AlarmLevel.WARNING : AlarmLevel.NONE);

pack.alarms.put(Alarm.CHARGE_MODULE_TEMPERATURE_HIGH, Util.bit(warningFlag, 10) ? AlarmLevel.WARNING : AlarmLevel.NONE);
pack.alarms.put(Alarm.SOC_LOW, Util.bit(warningFlag, 11) ? AlarmLevel.WARNING : AlarmLevel.NONE);
pack.alarms.put(Alarm.CELL_VOLTAGE_DIFFERENCE_HIGH, Util.bit(warningFlag, 12) ? AlarmLevel.WARNING : AlarmLevel.NONE);

// alarms
pack.alarms.put(Alarm.CELL_VOLTAGE_HIGH, Util.bit(protectionFlag, 0) ? AlarmLevel.ALARM : AlarmLevel.NONE);
pack.alarms.put(Alarm.CELL_VOLTAGE_LOW, Util.bit(protectionFlag, 1) ? AlarmLevel.ALARM : AlarmLevel.NONE);
pack.alarms.put(Alarm.PACK_VOLTAGE_HIGH, Util.bit(protectionFlag, 2) ? AlarmLevel.ALARM : AlarmLevel.NONE);
pack.alarms.put(Alarm.PACK_VOLTAGE_LOW, Util.bit(protectionFlag, 3) ? AlarmLevel.ALARM : AlarmLevel.NONE);
pack.alarms.put(Alarm.FAILURE_SHORT_CIRCUIT_PROTECTION, Util.bit(protectionFlag, 4) ? AlarmLevel.ALARM : AlarmLevel.NONE);

pack.alarms.put(Alarm.CHARGE_TEMPERATURE_HIGH, Util.bit(protectionFlag, 6) ? AlarmLevel.ALARM : AlarmLevel.NONE);
pack.alarms.put(Alarm.CHARGE_TEMPERATURE_LOW, Util.bit(protectionFlag, 7) ? AlarmLevel.ALARM : AlarmLevel.NONE);
pack.alarms.put(Alarm.DISCHARGE_TEMPERATURE_HIGH, Util.bit(protectionFlag, 8) ? AlarmLevel.ALARM : AlarmLevel.NONE);
pack.alarms.put(Alarm.DISCHARGE_TEMPERATURE_LOW, Util.bit(protectionFlag, 9) ? AlarmLevel.ALARM : AlarmLevel.NONE);

// fault
pack.alarms.put(Alarm.FAILURE_COMMUNICATION_INTERNAL, Util.bit(faultStatus, 0) ? AlarmLevel.ALARM : AlarmLevel.NONE);
pack.alarms.put(Alarm.FAILURE_SENSOR_PACK_TEMPERATURE, Util.bit(faultStatus, 1) ? AlarmLevel.ALARM : AlarmLevel.NONE);

pack.chargeDischargeStatus = Util.bit(faultStatus, 8) ? 1 : Util.bit(faultStatus, 9) ? 2 : 0;
pack.chargeMOSState = Util.bit(faultStatus, 9);
pack.dischargeMOSState = Util.bit(faultStatus, 10);

}
}
5 changes: 5 additions & 0 deletions bms-narada-modbus/src/main/resources/META-INF/beans.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
bean-discovery-mode="all" version="4.0">

</beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.airepublic.bmstoinverter.bms.narada.modbus.NaradaBmsModbusDescriptor
7 changes: 7 additions & 0 deletions bms-to-inverter-main/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,13 @@
<version>${project.version}</version>
</dependency>

<!-- #################### NARADA (MODBUS) ################### -->
<dependency>
<groupId>com.ai-republic.bms-to-inverter</groupId>
<artifactId>bms-narada-modbus</artifactId>
<version>${project.version}</version>
</dependency>

<!-- #################### PACE (CAN) ################### -->
<dependency>
<groupId>com.ai-republic.bms-to-inverter</groupId>
Expand Down
7 changes: 7 additions & 0 deletions configurator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@
<artifactId>bms-jk-rs485</artifactId>
<version>${project.version}</version>
</dependency>

<!-- #################### NARADA (MODBUS) ################### -->
<dependency>
<groupId>com.ai-republic.bms-to-inverter</groupId>
<artifactId>bms-narada-modbus</artifactId>
<version>${project.version}</version>
</dependency>

<!-- #################### PACE (CAN) ################### -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ com.airepublic.bmstoinverter.bms.jbd.rs485.JBDBmsRS485Descriptor
com.airepublic.bmstoinverter.bms.jk.can.JKBmsCANDescriptor
com.airepublic.bmstoinverter.bms.jk.modbus.JKBmsModbusDescriptor
com.airepublic.bmstoinverter.bms.jk.rs485.JKBmsRS485Descriptor
com.airepublic.bmstoinverter.bms.narada.modbus.NaradaBmsModbusDescriptor
com.airepublic.bmstoinverter.bms.pace.can.PaceBmsCANDescriptor
com.airepublic.bmstoinverter.bms.pylon.can.PylonBmsCANDescriptor
com.airepublic.bmstoinverter.bms.pylon.hv.can.PylonHVBmsCANDescriptor
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<module>bms-jk-can</module>
<module>bms-jk-modbus</module>
<module>bms-jk-rs485</module>
<module>bms-narada-modbus</module>
<module>bms-pace-can</module>
<module>bms-pylon-can</module>
<module>bms-pylon-hv-can</module>
Expand Down

0 comments on commit 2fafe32

Please sign in to comment.