Skip to content

Commit 09d79c5

Browse files
committed
added mpp solar BMS binding
1 parent f0eb9d9 commit 09d79c5

File tree

10 files changed

+361
-0
lines changed

10 files changed

+361
-0
lines changed

bms-mppsolar-modbus/.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/target/
2+
/.classpath
3+
/.project
4+
/.settings/

bms-mppsolar-modbus/pom.xml

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>com.ai-republic.bms-to-inverter</groupId>
8+
<artifactId>bms-to-inverter-parent</artifactId>
9+
<version>0.0.1-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>bms-mppsolar-modbus</artifactId>
13+
14+
<name>${project.artifactId}-${project.version}</name>
15+
<description>Module for the MPP Solar BMS ModBus support</description>
16+
17+
<properties>
18+
<encoding>UTF-8</encoding>
19+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>com.ai-republic.bms-to-inverter</groupId>
25+
<artifactId>protocol-modbus</artifactId>
26+
<version>${project.version}</version>
27+
</dependency>
28+
</dependencies>
29+
30+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* This software is free to use and to distribute in its unchanged form for private use.
3+
* Commercial use is prohibited without an explicit license agreement of the copyright holder.
4+
* Any changes to this software must be made solely in the project repository at https://github.com/ai-republic/bms-to-inverter.
5+
* The copyright holder is not liable for any damages in whatever form that may occur by using this software.
6+
*
7+
* (c) Copyright 2022 and onwards - Torsten Oltmanns
8+
*
9+
* @author Torsten Oltmanns - bms-to-inverter''AT''gmail.com
10+
*/
11+
package com.airepublic.bmstoinverter.bms.mppsolar.modbus;
12+
13+
import com.airepublic.bmstoinverter.core.BMS;
14+
import com.airepublic.bmstoinverter.core.BMSConfig;
15+
import com.airepublic.bmstoinverter.core.BMSDescriptor;
16+
import com.airepublic.bmstoinverter.core.Port;
17+
import com.airepublic.bmstoinverter.protocol.modbus.J2ModMasterPort;
18+
19+
/**
20+
* The {@link BMSDescriptor} for the MPP Solar BMS using the Modbus protocol.
21+
*/
22+
public class MppSolarBmsModbusDescriptor implements BMSDescriptor {
23+
@Override
24+
public String getName() {
25+
return "MPPSOLAR_MODBUS";
26+
}
27+
28+
29+
@Override
30+
public int getDefaultBaudRate() {
31+
return 9600;
32+
}
33+
34+
35+
@Override
36+
public Class<? extends BMS> getBMSClass() {
37+
return MppSolarBmsModbusProcessor.class;
38+
}
39+
40+
41+
@Override
42+
public Port createPort(final BMSConfig config) {
43+
final Port port = new J2ModMasterPort(config.getPortLocator(), config.getBaudRate());
44+
return port;
45+
}
46+
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/**
2+
* This software is free to use and to distribute in its unchanged form for private use.
3+
* Commercial use is prohibited without an explicit license agreement of the copyright holder.
4+
* Any changes to this software must be made solely in the project repository at https://github.com/ai-republic/bms-to-inverter.
5+
* The copyright holder is not liable for any damages in whatever form that may occur by using this software.
6+
*
7+
* (c) Copyright 2022 and onwards - Torsten Oltmanns
8+
*
9+
* @author Torsten Oltmanns - bms-to-inverter''AT''gmail.com
10+
*/
11+
package com.airepublic.bmstoinverter.bms.mppsolar.modbus;
12+
13+
import java.io.IOException;
14+
import java.nio.ByteBuffer;
15+
import java.util.function.Consumer;
16+
17+
import org.slf4j.Logger;
18+
import org.slf4j.LoggerFactory;
19+
20+
import com.airepublic.bmstoinverter.core.AlarmLevel;
21+
import com.airepublic.bmstoinverter.core.BMS;
22+
import com.airepublic.bmstoinverter.core.Port;
23+
import com.airepublic.bmstoinverter.core.bms.data.Alarm;
24+
import com.airepublic.bmstoinverter.core.bms.data.BatteryPack;
25+
import com.airepublic.bmstoinverter.core.util.BitUtil;
26+
import com.airepublic.bmstoinverter.protocol.modbus.ModbusUtil;
27+
import com.airepublic.bmstoinverter.protocol.modbus.ModbusUtil.RegisterCode;
28+
29+
/**
30+
* The class to handle Modbus messages from a MPP Solar {@link BMS}.
31+
*/
32+
public class MppSolarBmsModbusProcessor extends BMS {
33+
private final static Logger LOG = LoggerFactory.getLogger(MppSolarBmsModbusProcessor.class);
34+
private final static int BATTERY_NO = 0;
35+
36+
@Override
37+
protected void collectData(final Port port) {
38+
final int startRange = 0;
39+
40+
try {
41+
sendMessage(port, RegisterCode.READ_HOLDING_REGISTERS, startRange + 0x0010, 36, getBmsId(), this::readBatteryStatus);
42+
} catch (final IOException e) {
43+
LOG.error("Error reading from modbus!", e);
44+
}
45+
}
46+
47+
48+
protected void sendMessage(final Port port, final RegisterCode functionCode, final int startAddress, final int numRegisters, final int unitId, final Consumer<ByteBuffer> handler) throws IOException {
49+
port.sendFrame(ModbusUtil.createRequestBuffer(functionCode, startAddress, numRegisters, unitId));
50+
handler.accept(port.receiveFrame());
51+
}
52+
53+
54+
// read battery status
55+
protected void readBatteryStatus(final ByteBuffer frame) {
56+
frame.getInt(); // functionCode
57+
frame.getInt(); // numRegisters
58+
frame.getInt(); // unitId
59+
final BatteryPack pack = getBatteryPack(BATTERY_NO);
60+
61+
// no of cells
62+
pack.numberOfCells = frame.getChar();
63+
64+
// cell voltages (0.1V)
65+
for (int i = 0; i < 20; i++) {
66+
pack.cellVmV[i] = frame.getChar() * 100;
67+
}
68+
69+
pack.numOfTempSensors = frame.getChar();
70+
71+
for (int i = 0; i < 20; i++) {
72+
pack.cellTemperature[i] = (int) (frame.getChar() / 10f - 273.15f);
73+
}
74+
75+
// curernt (0.1A)
76+
pack.packCurrent = frame.getChar();
77+
78+
if (pack.packCurrent == 0) {
79+
pack.packCurrent = frame.getChar();
80+
} else {
81+
frame.getChar();
82+
}
83+
84+
// voltage (0.1V)
85+
pack.packVoltage = frame.getChar();
86+
87+
// SOC (1%)
88+
pack.packSOC = frame.getChar();
89+
90+
// rated capacity (1mAh)
91+
pack.ratedCapacitymAh = frame.getChar();
92+
93+
}
94+
95+
96+
// read alarms
97+
protected void readAlarms(final ByteBuffer frame) {
98+
frame.getInt(); // functionCode
99+
frame.getInt(); // numRegisters
100+
frame.getInt(); // unitId
101+
final BatteryPack pack = getBatteryPack(BATTERY_NO);
102+
pack.alarms.clear();
103+
104+
pack.packCurrent = frame.getShort() / 10;
105+
pack.ratedCapacitymAh = frame.getChar() * 10;
106+
pack.bmsCycles = frame.getChar();
107+
pack.packSOC = frame.getChar() / 10;
108+
pack.packSOH = frame.getChar() / 10;
109+
pack.numOfTempSensors = frame.getChar();
110+
111+
char alarms = frame.getChar();
112+
byte highByte = (byte) (alarms >> 8);
113+
pack.alarms.put(Alarm.CELL_VOLTAGE_LOW, BitUtil.bit(highByte, 3) ? AlarmLevel.WARNING : AlarmLevel.NONE);
114+
pack.alarms.put(Alarm.FAILURE_OTHER, BitUtil.bit(highByte, 4) || pack.alarms.containsKey(Alarm.FAILURE_OTHER) ? AlarmLevel.ALARM : AlarmLevel.NONE);
115+
pack.alarms.put(Alarm.FAILURE_CHARGE_BREAKER, BitUtil.bit(highByte, 5) ? AlarmLevel.ALARM : AlarmLevel.NONE);
116+
pack.alarms.put(Alarm.FAILURE_DISCHARGE_BREAKER, BitUtil.bit(highByte, 6) ? AlarmLevel.ALARM : AlarmLevel.NONE);
117+
pack.alarms.put(Alarm.FAILURE_OTHER, BitUtil.bit(highByte, 7) || pack.alarms.containsKey(Alarm.FAILURE_OTHER) ? AlarmLevel.ALARM : AlarmLevel.NONE);
118+
119+
byte lowByte = (byte) (alarms & 0xFF);
120+
pack.alarms.put(Alarm.FAILURE_CLOCK_MODULE, BitUtil.bit(lowByte, 0) ? AlarmLevel.ALARM : AlarmLevel.NONE);
121+
pack.alarms.put(Alarm.FAILURE_OTHER, BitUtil.bit(lowByte, 1) || pack.alarms.containsKey(Alarm.FAILURE_OTHER) ? AlarmLevel.ALARM : AlarmLevel.NONE);
122+
pack.alarms.put(Alarm.FAILURE_OTHER, BitUtil.bit(lowByte, 2) || pack.alarms.containsKey(Alarm.FAILURE_OTHER) ? AlarmLevel.ALARM : AlarmLevel.NONE);
123+
pack.alarms.put(Alarm.FAILURE_OTHER, BitUtil.bit(lowByte, 3) || pack.alarms.containsKey(Alarm.FAILURE_OTHER) ? AlarmLevel.ALARM : AlarmLevel.NONE);
124+
pack.alarms.put(Alarm.FAILURE_OTHER, BitUtil.bit(lowByte, 4) || pack.alarms.containsKey(Alarm.FAILURE_OTHER) ? AlarmLevel.ALARM : AlarmLevel.NONE);
125+
126+
alarms = frame.getChar();
127+
highByte = (byte) (alarms >> 8);
128+
pack.alarms.put(Alarm.FAILURE_SENSOR_DISCHARGE_MODULE_TEMPERATURE, BitUtil.bit(highByte, 0) ? AlarmLevel.ALARM : AlarmLevel.NONE);
129+
pack.alarms.put(Alarm.FAILURE_SENSOR_DISCHARGE_MODULE_TEMPERATURE, BitUtil.bit(highByte, 1) || pack.alarms.containsKey(Alarm.FAILURE_SENSOR_DISCHARGE_MODULE_TEMPERATURE) ? AlarmLevel.ALARM : AlarmLevel.NONE);
130+
pack.alarms.put(Alarm.PACK_VOLTAGE_HIGH, BitUtil.bit(highByte, 2) ? AlarmLevel.WARNING : AlarmLevel.NONE);
131+
pack.alarms.put(Alarm.FAILURE_OTHER, BitUtil.bit(lowByte, 3) || pack.alarms.containsKey(Alarm.FAILURE_OTHER) ? AlarmLevel.ALARM : AlarmLevel.NONE);
132+
pack.alarms.put(Alarm.FAILURE_OTHER, BitUtil.bit(lowByte, 4) || pack.alarms.containsKey(Alarm.FAILURE_OTHER) ? AlarmLevel.ALARM : AlarmLevel.NONE);
133+
pack.alarms.put(Alarm.FAILURE_OTHER, BitUtil.bit(lowByte, 5) || pack.alarms.containsKey(Alarm.FAILURE_OTHER) ? AlarmLevel.ALARM : AlarmLevel.NONE);
134+
135+
lowByte = (byte) (alarms & 0xFF);
136+
pack.chargeDischargeStatus = BitUtil.bit(lowByte, 0) ? 1 : BitUtil.bit(lowByte, 1) ? 2 : 0;
137+
pack.alarms.put(Alarm.FAILURE_SHORT_CIRCUIT_PROTECTION, BitUtil.bit(lowByte, 2) ? AlarmLevel.ALARM : AlarmLevel.NONE);
138+
pack.alarms.put(Alarm.PACK_VOLTAGE_HIGH, BitUtil.bit(lowByte, 4) || pack.alarms.containsKey(Alarm.PACK_VOLTAGE_HIGH) ? AlarmLevel.WARNING : AlarmLevel.NONE);
139+
pack.alarms.put(Alarm.PACK_VOLTAGE_LOW, BitUtil.bit(lowByte, 5) ? AlarmLevel.WARNING : AlarmLevel.NONE);
140+
pack.alarms.put(Alarm.CHARGE_TEMPERATURE_HIGH, BitUtil.bit(lowByte, 6) ? AlarmLevel.WARNING : AlarmLevel.NONE);
141+
pack.alarms.put(Alarm.DISCHARGE_TEMPERATURE_HIGH, BitUtil.bit(lowByte, 7) ? AlarmLevel.WARNING : AlarmLevel.NONE);
142+
143+
alarms = frame.getChar();
144+
highByte = (byte) (alarms >> 8);
145+
pack.alarms.put(Alarm.PACK_TEMPERATURE_LOW, BitUtil.bit(highByte, 0) ? AlarmLevel.WARNING : AlarmLevel.NONE);
146+
pack.alarms.put(Alarm.PACK_TEMPERATURE_HIGH, BitUtil.bit(highByte, 1) ? AlarmLevel.WARNING : AlarmLevel.NONE);
147+
148+
lowByte = (byte) (alarms & 0xFF);
149+
if (BitUtil.bit(lowByte, 0)) {
150+
pack.forceCharge = true;
151+
}
152+
153+
if (BitUtil.bit(lowByte, 1)) {
154+
pack.forceCharge = false;
155+
}
156+
157+
if (BitUtil.bit(lowByte, 2)) {
158+
pack.forceDischarge = true;
159+
}
160+
161+
if (BitUtil.bit(lowByte, 3)) {
162+
pack.forceDischarge = false;
163+
}
164+
165+
pack.alarms.put(Alarm.CHARGE_TEMPERATURE_HIGH, BitUtil.bit(lowByte, 5) || pack.alarms.containsKey(Alarm.CHARGE_TEMPERATURE_HIGH) ? AlarmLevel.WARNING : AlarmLevel.NONE);
166+
pack.alarms.put(Alarm.CHARGE_TEMPERATURE_LOW, BitUtil.bit(lowByte, 6) || pack.alarms.containsKey(Alarm.CHARGE_TEMPERATURE_LOW) ? AlarmLevel.WARNING : AlarmLevel.NONE);
167+
pack.alarms.put(Alarm.CHARGE_TEMPERATURE_LOW, BitUtil.bit(lowByte, 7) || pack.alarms.containsKey(Alarm.CHARGE_TEMPERATURE_LOW) ? AlarmLevel.WARNING : AlarmLevel.NONE);
168+
169+
alarms = frame.getChar();
170+
alarms = frame.getChar();
171+
highByte = (byte) (alarms >> 8);
172+
pack.alarms.put(Alarm.ENCASING_TEMPERATURE_HIGH, BitUtil.bit(highByte, 0) || pack.alarms.containsKey(Alarm.ENCASING_TEMPERATURE_HIGH) ? AlarmLevel.WARNING : AlarmLevel.NONE);
173+
pack.alarms.put(Alarm.ENCASING_TEMPERATURE_LOW, BitUtil.bit(highByte, 1) || pack.alarms.containsKey(Alarm.ENCASING_TEMPERATURE_LOW) ? AlarmLevel.WARNING : AlarmLevel.NONE);
174+
pack.alarms.put(Alarm.DISCHARGE_TEMPERATURE_HIGH, BitUtil.bit(highByte, 2) || pack.alarms.containsKey(Alarm.DISCHARGE_TEMPERATURE_HIGH) ? AlarmLevel.WARNING : AlarmLevel.NONE);
175+
pack.alarms.put(Alarm.SOC_LOW, BitUtil.bit(highByte, 3) ? AlarmLevel.WARNING : AlarmLevel.NONE);
176+
pack.alarms.put(Alarm.PACK_VOLTAGE_HIGH, BitUtil.bit(highByte, 4) || pack.alarms.containsKey(Alarm.PACK_VOLTAGE_HIGH) ? AlarmLevel.WARNING : AlarmLevel.NONE);
177+
pack.alarms.put(Alarm.PACK_TEMPERATURE_HIGH, BitUtil.bit(highByte, 5) || pack.alarms.containsKey(Alarm.PACK_TEMPERATURE_HIGH) ? AlarmLevel.WARNING : AlarmLevel.NONE);
178+
pack.alarms.put(Alarm.DISCHARGE_TEMPERATURE_LOW, BitUtil.bit(highByte, 5) || pack.alarms.containsKey(Alarm.DISCHARGE_TEMPERATURE_LOW) ? AlarmLevel.WARNING : AlarmLevel.NONE);
179+
180+
lowByte = (byte) (alarms & 0xFF);
181+
pack.alarms.put(Alarm.CELL_VOLTAGE_HIGH, BitUtil.bit(lowByte, 0) ? AlarmLevel.WARNING : AlarmLevel.NONE);
182+
pack.alarms.put(Alarm.CELL_VOLTAGE_LOW, BitUtil.bit(lowByte, 1) ? AlarmLevel.WARNING : AlarmLevel.NONE);
183+
pack.alarms.put(Alarm.PACK_VOLTAGE_HIGH, BitUtil.bit(lowByte, 2) || pack.alarms.containsKey(Alarm.PACK_VOLTAGE_HIGH) ? AlarmLevel.WARNING : AlarmLevel.NONE);
184+
pack.alarms.put(Alarm.PACK_VOLTAGE_LOW, BitUtil.bit(lowByte, 3) || pack.alarms.containsKey(Alarm.PACK_VOLTAGE_LOW) ? AlarmLevel.WARNING : AlarmLevel.NONE);
185+
pack.alarms.put(Alarm.SOC_HIGH, BitUtil.bit(lowByte, 4) ? AlarmLevel.WARNING : AlarmLevel.NONE);
186+
187+
pack.alarms.put(Alarm.CHARGE_TEMPERATURE_HIGH, BitUtil.bit(lowByte, 6) || pack.alarms.containsKey(Alarm.CHARGE_TEMPERATURE_HIGH) ? AlarmLevel.WARNING : AlarmLevel.NONE);
188+
pack.alarms.put(Alarm.CHARGE_TEMPERATURE_LOW, BitUtil.bit(lowByte, 7) || pack.alarms.containsKey(Alarm.CHARGE_TEMPERATURE_LOW) ? AlarmLevel.WARNING : AlarmLevel.NONE);
189+
190+
final char protection = frame.getChar();
191+
highByte = (byte) (protection >> 8);
192+
pack.alarms.put(Alarm.SOC_HIGH, BitUtil.bit(highByte, 0) || pack.alarms.containsKey(Alarm.SOC_HIGH) ? AlarmLevel.ALARM : AlarmLevel.NONE);
193+
194+
lowByte = (byte) (protection & 0xFF);
195+
pack.alarms.put(Alarm.CELL_VOLTAGE_HIGH, BitUtil.bit(lowByte, 0) || pack.alarms.containsKey(Alarm.CELL_VOLTAGE_HIGH) ? AlarmLevel.ALARM : AlarmLevel.NONE);
196+
pack.alarms.put(Alarm.PACK_VOLTAGE_HIGH, BitUtil.bit(lowByte, 1) || pack.alarms.containsKey(Alarm.PACK_VOLTAGE_HIGH) ? AlarmLevel.ALARM : AlarmLevel.NONE);
197+
pack.alarms.put(Alarm.CELL_VOLTAGE_LOW, BitUtil.bit(lowByte, 2) || pack.alarms.containsKey(Alarm.CELL_VOLTAGE_LOW) ? AlarmLevel.ALARM : AlarmLevel.NONE);
198+
pack.alarms.put(Alarm.PACK_VOLTAGE_LOW, BitUtil.bit(lowByte, 3) || pack.alarms.containsKey(Alarm.PACK_VOLTAGE_LOW) ? AlarmLevel.ALARM : AlarmLevel.NONE);
199+
pack.alarms.put(Alarm.CHARGE_CURRENT_HIGH, BitUtil.bit(lowByte, 4) || pack.alarms.containsKey(Alarm.CHARGE_CURRENT_HIGH) ? AlarmLevel.ALARM : AlarmLevel.NONE);
200+
pack.alarms.put(Alarm.CHARGE_CURRENT_HIGH, BitUtil.bit(lowByte, 5) || pack.alarms.containsKey(Alarm.CHARGE_CURRENT_HIGH) ? AlarmLevel.ALARM : AlarmLevel.NONE);
201+
pack.alarms.put(Alarm.DISCHARGE_CURRENT_HIGH, BitUtil.bit(lowByte, 6) || pack.alarms.containsKey(Alarm.DISCHARGE_CURRENT_HIGH) ? AlarmLevel.ALARM : AlarmLevel.NONE);
202+
pack.alarms.put(Alarm.DISCHARGE_CURRENT_HIGH, BitUtil.bit(lowByte, 7) || pack.alarms.containsKey(Alarm.DISCHARGE_CURRENT_HIGH) ? AlarmLevel.ALARM : AlarmLevel.NONE);
203+
204+
frame.getInt();
205+
pack.moduleRatedCapacityAh = frame.getInt();
206+
}
207+
208+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
3+
bean-discovery-mode="all" version="4.0">
4+
5+
</beans>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
com.airepublic.bmstoinverter.bms.mppsolar.modbus.MppSolarBmsModbusDescriptor
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* This software is free to use and to distribute in its unchanged form for private use.
3+
* Commercial use is prohibited without an explicit license agreement of the copyright holder.
4+
* Any changes to this software must be made solely in the project repository at https://github.com/ai-republic/bms-to-inverter.
5+
* The copyright holder is not liable for any damages in whatever form that may occur by using this software.
6+
*
7+
* (c) Copyright 2022 and onwards - Torsten Oltmanns
8+
*
9+
* @author Torsten Oltmanns - bms-to-inverter''AT''gmail.com
10+
*/
11+
package com.airepublic.bmstoinverter.bms.mppsolar.modbus;
12+
13+
import org.junit.jupiter.api.Assertions;
14+
import org.junit.jupiter.api.Test;
15+
import org.mockito.Mockito;
16+
17+
import com.airepublic.bmstoinverter.core.BMSConfig;
18+
import com.airepublic.bmstoinverter.core.BMSDescriptor;
19+
import com.airepublic.bmstoinverter.protocol.modbus.J2ModMasterPort;
20+
21+
/**
22+
* The unit test for the Shoto BMS {@link BMSDescriptor}.
23+
*/
24+
public class MppSolarBmsModbusDescriptorTest {
25+
private final MppSolarBmsModbusDescriptor descriptor = new MppSolarBmsModbusDescriptor();
26+
27+
@Test
28+
public void getName() {
29+
Assertions.assertEquals("MPPSOLAR_MODBUS", descriptor.getName());
30+
}
31+
32+
33+
@Test
34+
public void getDefaultBaudRate() {
35+
Assertions.assertEquals(9600, descriptor.getDefaultBaudRate());
36+
}
37+
38+
39+
@Test
40+
public void getBMSClass() {
41+
Assertions.assertEquals(MppSolarBmsModbusProcessor.class, descriptor.getBMSClass());
42+
}
43+
44+
45+
@Test
46+
public void createPort() {
47+
final BMSConfig config = Mockito.mock(BMSConfig.class);
48+
Assertions.assertInstanceOf(J2ModMasterPort.class, descriptor.createPort(config));
49+
}
50+
51+
}

bms-to-inverter-main/pom.xml

+7
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,13 @@
189189
<version>${project.version}</version>
190190
</dependency>
191191

192+
<!-- #################### MPP SOLAR (MODBUS) ################### -->
193+
<dependency>
194+
<groupId>com.ai-republic.bms-to-inverter</groupId>
195+
<artifactId>inverter-mppsolar-modbus</artifactId>
196+
<version>${project.version}</version>
197+
</dependency>
198+
192199
<!-- #################### NARADA (MODBUS) ################### -->
193200
<dependency>
194201
<groupId>com.ai-republic.bms-to-inverter</groupId>

configurator/pom.xml

+7
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@
151151
<version>${project.version}</version>
152152
</dependency>
153153

154+
<!-- #################### MPP SOLAR (MODBUS) ################### -->
155+
<dependency>
156+
<groupId>com.ai-republic.bms-to-inverter</groupId>
157+
<artifactId>inverter-mppsolar-modbus</artifactId>
158+
<version>${project.version}</version>
159+
</dependency>
160+
154161
<!-- #################### NARADA (MODBUS) ################### -->
155162
<dependency>
156163
<groupId>com.ai-republic.bms-to-inverter</groupId>

pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<module>bms-jk-modbus</module>
3131
<module>bms-jk-rs485</module>
3232
<module>bms-lia-can</module>
33+
<module>bms-mppsolar-modbus</module>
3334
<module>bms-narada-modbus</module>
3435
<module>bms-pace-can</module>
3536
<module>bms-pylon-can</module>

0 commit comments

Comments
 (0)