diff --git a/bms-to-inverter-main/pom.xml b/bms-to-inverter-main/pom.xml index 80201b0c..662bf294 100644 --- a/bms-to-inverter-main/pom.xml +++ b/bms-to-inverter-main/pom.xml @@ -276,6 +276,13 @@ ${project.version} + + + com.ai-republic.bms-to-inverter + inverter-growatt-hv-can + ${project.version} + + com.ai-republic.bms-to-inverter diff --git a/configurator/pom.xml b/configurator/pom.xml index 9a6d6075..1cfa3561 100644 --- a/configurator/pom.xml +++ b/configurator/pom.xml @@ -245,6 +245,13 @@ ${project.version} + + + com.ai-republic.bms-to-inverter + inverter-growatt-hv-can + ${project.version} + + com.ai-republic.bms-to-inverter diff --git a/configurator/src/main/resources/META-INF/services/com.airepublic.bmstoinverter.core.InverterDescriptor b/configurator/src/main/resources/META-INF/services/com.airepublic.bmstoinverter.core.InverterDescriptor index ccf50795..fb7f8b34 100644 --- a/configurator/src/main/resources/META-INF/services/com.airepublic.bmstoinverter.core.InverterDescriptor +++ b/configurator/src/main/resources/META-INF/services/com.airepublic.bmstoinverter.core.InverterDescriptor @@ -3,6 +3,7 @@ com.airepublic.bmstoinverter.inverter.deye.can.DeyeInverterCANDescriptor com.airepublic.bmstoinverter.inverter.huawei.modbus.HuaweiInverterModbusDescriptor com.airepublic.bmstoinverter.inverter.goodwe.can.GoodweInverterCANDescriptor com.airepublic.bmstoinverter.inverter.growatt.can.GrowattInverterCANDescriptor +com.airepublic.bmstoinverter.inverter.growatthv.can.GrowattHVInverterCANProcessor com.airepublic.bmstoinverter.inverter.growatt.modbus.GrowattInverterModbusDescriptor com.airepublic.bmstoinverter.inverter.pylon.can.PylonInverterCANDescriptor com.airepublic.bmstoinverter.inverter.pylonhv.can.PylonHVInverterCANDescriptor diff --git a/core-api/src/main/java/com/airepublic/bmstoinverter/core/bms/data/BatteryPack.java b/core-api/src/main/java/com/airepublic/bmstoinverter/core/bms/data/BatteryPack.java index b3c739ea..624e5fa2 100644 --- a/core-api/src/main/java/com/airepublic/bmstoinverter/core/bms/data/BatteryPack.java +++ b/core-api/src/main/java/com/airepublic/bmstoinverter/core/bms/data/BatteryPack.java @@ -23,28 +23,25 @@ */ public class BatteryPack { public final Map alarms = new HashMap<>(); - // data from 0x53 /** Battery type: 0=lithium iron, 1=ternary lithium, 2=lithium titanate */ public int type; - // data from 0x50 /** Capacity of each cell (1mAh) */ public int ratedCapacitymAh; /** Nominal cell voltage (1mV) */ public int ratedCellmV; - // data from 0x5A /** Maximum total voltage (0.1V) */ public int maxPackVoltageLimit; /** Minimum total voltage (0.1V) */ public int minPackVoltageLimit; - // data from 0x5B /** Maximum total charge current (0.1A) */ public int maxPackChargeCurrent; /** Maximum total discharge current (-0.1A) */ public int maxPackDischargeCurrent; + /** Maximum total charge voltage (0.1V) */ + public int maxChargeVoltage; - // data from 0x90 /** Total pack voltage (0.1 V) */ public int packVoltage; /** Current in (+) or out (-) of pack (0.1 A) */ @@ -193,6 +190,12 @@ public final void setAlarm(final Alarm alarm, final AlarmLevel level) { * @return the {@link AlarmLevel} or null if not present */ public AlarmLevel getAlarmLevel(final Alarm alarm) { - return alarms.get(alarm); + final AlarmLevel level = alarms.get(alarm); + + if (level == null) { + return AlarmLevel.NONE; + } + + return level; } } diff --git a/inverter-growatt-hv-can/pom.xml b/inverter-growatt-hv-can/pom.xml new file mode 100644 index 00000000..b761823d --- /dev/null +++ b/inverter-growatt-hv-can/pom.xml @@ -0,0 +1,35 @@ + + 4.0.0 + + com.ai-republic.bms-to-inverter + bms-to-inverter-parent + 0.0.1-SNAPSHOT + + + inverter-growatt-hv-can + + ${project.artifactId}-${project.version} + Module for the Growatt high voltage inverter CAN support + + + UTF-8 + UTF-8 + + + + + com.ai-republic.bms-to-inverter + core-api + ${project.version} + + + + com.ai-republic.bms-to-inverter + protocol-can + ${project.version} + + + + \ No newline at end of file diff --git a/inverter-growatt-hv-can/src/main/java/com/airepublic/bmstoinverter/inverter/growatthv/can/GrowattHVInverterCANDescriptor.java b/inverter-growatt-hv-can/src/main/java/com/airepublic/bmstoinverter/inverter/growatthv/can/GrowattHVInverterCANDescriptor.java new file mode 100644 index 00000000..d31e91ba --- /dev/null +++ b/inverter-growatt-hv-can/src/main/java/com/airepublic/bmstoinverter/inverter/growatthv/can/GrowattHVInverterCANDescriptor.java @@ -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.inverter.growatthv.can; + +import com.airepublic.bmstoinverter.core.Inverter; +import com.airepublic.bmstoinverter.core.InverterConfig; +import com.airepublic.bmstoinverter.core.InverterDescriptor; +import com.airepublic.bmstoinverter.core.Port; +import com.airepublic.bmstoinverter.protocol.can.JavaCANPort; + +/** + * The {@link InverterDescriptor} for the Growatt HV {@link Inverter} using the CAN protocol. + */ +public class GrowattHVInverterCANDescriptor implements InverterDescriptor { + @Override + public String getName() { + return "GROWATT_HV_CAN"; + } + + + @Override + public int getDefaultBaudRate() { + return 500000; + } + + + @Override + public Class getInverterClass() { + return GrowattHVInverterCANProcessor.class; + } + + + @Override + public Port createPort(final InverterConfig config) { + final Port port = new JavaCANPort(config.getPortLocator(), config.getBaudRate()); + return port; + } + +} diff --git a/inverter-growatt-hv-can/src/main/java/com/airepublic/bmstoinverter/inverter/growatthv/can/GrowattHVInverterCANProcessor.java b/inverter-growatt-hv-can/src/main/java/com/airepublic/bmstoinverter/inverter/growatthv/can/GrowattHVInverterCANProcessor.java new file mode 100644 index 00000000..52f4cec1 --- /dev/null +++ b/inverter-growatt-hv-can/src/main/java/com/airepublic/bmstoinverter/inverter/growatthv/can/GrowattHVInverterCANProcessor.java @@ -0,0 +1,347 @@ +/** + * 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.inverter.growatthv.can; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.airepublic.bmstoinverter.core.AlarmLevel; +import com.airepublic.bmstoinverter.core.Inverter; +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.protocol.can.CANPort; +import com.airepublic.bmstoinverter.core.util.BitUtil; + +import jakarta.enterprise.context.ApplicationScoped; + +/** + * The class to handle CAN messages for a Growatt HV {@link Inverter}. + */ +@ApplicationScoped +public class GrowattHVInverterCANProcessor extends Inverter { + private final static Logger LOG = LoggerFactory.getLogger(GrowattHVInverterCANProcessor.class); + + @Override + protected ByteBuffer readRequest(final Port port) throws IOException { + return port.receiveFrame(); + } + + + @Override + protected void sendFrame(final Port port, final ByteBuffer frame) throws IOException { + ((CANPort) port).sendExtendedFrame(frame); + } + + + @Override + protected List createSendFrames(final ByteBuffer requestFrame, final BatteryPack aggregatedPack) { + final List sendFrames = new ArrayList<>(); + + try { + // 0x3110 + sendFrames.add(sendChargeDischargeLimits(aggregatedPack)); + // 0x3120 + sendFrames.add(sendAlarms(aggregatedPack)); + // 0x3130 + sendFrames.add(sendBatteryStatus(aggregatedPack)); + // 0x3140 + sendFrames.add(sendBatteryCapacity(aggregatedPack)); + // 0x3150 + sendFrames.add(sendWorkingParams(aggregatedPack)); + // 0x3160 + sendFrames.add(sendFaultAndVoltageNumbers(aggregatedPack)); + // 0x3170 + sendFrames.add(sendMinMaxCellTemperatures(aggregatedPack)); + + } catch (final Throwable e) { + LOG.error("Error creating send frames: ", e); + } + + return sendFrames; + } + + + protected ByteBuffer prepareSendFrame(final int frameId) { + final ByteBuffer sendFrame = ByteBuffer.allocateDirect(16).order(ByteOrder.BIG_ENDIAN); + sendFrame.putInt(frameId); + + // header + sendFrame.put((byte) 0x08) // data length + .put((byte) 0) // flags + .putShort((short) 0); // skip 2 bytes + + return sendFrame; + } + + + // 0x3110 + private ByteBuffer sendChargeDischargeLimits(final BatteryPack pack) throws IOException { + final ByteBuffer frame = prepareSendFrame(0x00003110); + + // Charge cutoff voltage (0.1V) + frame.putChar((char) (pack.maxChargeVoltage != 0 ? pack.maxChargeVoltage : pack.maxPackVoltageLimit)); + // Max charge current (0.1A) offset 0A + frame.putChar((char) pack.maxPackChargeCurrent); + // Max discharge current (0.1A) offset -3000A + frame.putChar((char) (pack.maxPackDischargeCurrent * -1)); + + // Battery status + short status = 0x0000; + switch (pack.chargeDischargeStatus) { + case 0: { + // standby/idle + status = BitUtil.setBit(status, 0, false); // Byte 7 bit 0 + status = BitUtil.setBit(status, 1, true); // Byte 7 bit 1 + } + break; + case 1: { + // discharging + status = BitUtil.setBit(status, 0, true); // Byte 7 bit 0 + status = BitUtil.setBit(status, 1, false); // Byte 7 bit 1 + } + break; + case 2: { + // charging + status = BitUtil.setBit(status, 0, true); // Byte 7 bit 0 + status = BitUtil.setBit(status, 1, true); // Byte 7 bit 1 + } + break; + case 3: { + // battery sleeping state + status = BitUtil.setBit(status, 4, true); // Byte 7 bit 4 + } + break; + } + + // fault flag + status = BitUtil.setBit(status, 2, false); // Byte 7 bit 2 + // cell balancing state + status = BitUtil.setBit(status, 3, pack.cellBalanceActive); // Byte 7 bit 3 + + LOG.debug("Sending max/min charge and discharge voltage and current limits: {}", Port.printBuffer(frame)); + return frame; + } + + + // 0x3120 + private ByteBuffer sendAlarms(final BatteryPack pack) throws IOException { + final ByteBuffer frame = prepareSendFrame(0x00003120); + + // Protection + int protection = 0x00000000; + protection = BitUtil.setBit(protection, 1, pack.getAlarmLevel(Alarm.PACK_VOLTAGE_LOW) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 2, pack.getAlarmLevel(Alarm.PACK_VOLTAGE_HIGH) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 3, pack.getAlarmLevel(Alarm.CELL_VOLTAGE_LOW) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 4, pack.getAlarmLevel(Alarm.CELL_VOLTAGE_HIGH) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 5, pack.getAlarmLevel(Alarm.FAILURE_SHORT_CIRCUIT_PROTECTION) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 6, pack.getAlarmLevel(Alarm.CHARGE_CURRENT_HIGH) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 7, pack.getAlarmLevel(Alarm.DISCHARGE_CURRENT_HIGH) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 8, pack.getAlarmLevel(Alarm.DISCHARGE_VOLTAGE_LOW) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 9, pack.getAlarmLevel(Alarm.CHARGE_VOLTAGE_HIGH) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 10, pack.getAlarmLevel(Alarm.CELL_VOLTAGE_DIFFERENCE_HIGH) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 11, pack.getAlarmLevel(Alarm.FAILURE_OTHER) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 12, pack.getAlarmLevel(Alarm.CHARGE_TEMPERATURE_LOW) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 13, pack.getAlarmLevel(Alarm.DISCHARGE_TEMPERATURE_LOW) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 14, pack.getAlarmLevel(Alarm.CHARGE_TEMPERATURE_HIGH) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 15, pack.getAlarmLevel(Alarm.DISCHARGE_TEMPERATURE_HIGH) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 16, pack.getAlarmLevel(Alarm.SOC_LOW) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 17, pack.getAlarmLevel(Alarm.TEMPERATURE_SENSOR_DIFFERENCE_HIGH) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 18, pack.getAlarmLevel(Alarm.CHARGE_MODULE_TEMPERATURE_HIGH) == AlarmLevel.ALARM); + protection = BitUtil.setBit(protection, 19, pack.getAlarmLevel(Alarm.ENCASING_TEMPERATURE_HIGH) == AlarmLevel.ALARM); + + frame.putInt(protection); + + // Alarm + int alarm = 0x00000000; + alarm = BitUtil.setBit(alarm, 0, pack.getAlarmLevel(Alarm.FAILURE_COMMUNICATION_INTERNAL) == AlarmLevel.WARNING); + + alarm = BitUtil.setBit(alarm, 2, pack.getAlarmLevel(Alarm.CELL_VOLTAGE_DIFFERENCE_HIGH) == AlarmLevel.WARNING); + + alarm = BitUtil.setBit(alarm, 4, pack.getAlarmLevel(Alarm.CHARGE_TEMPERATURE_LOW) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 5, pack.getAlarmLevel(Alarm.DISCHARGE_TEMPERATURE_LOW) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 6, pack.getAlarmLevel(Alarm.CHARGE_TEMPERATURE_HIGH) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 7, pack.getAlarmLevel(Alarm.DISCHARGE_TEMPERATURE_HIGH) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 8, pack.getAlarmLevel(Alarm.DISCHARGE_VOLTAGE_LOW) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 9, pack.getAlarmLevel(Alarm.PACK_VOLTAGE_LOW) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 10, pack.getAlarmLevel(Alarm.PACK_VOLTAGE_HIGH) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 11, pack.getAlarmLevel(Alarm.CELL_VOLTAGE_LOW) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 12, pack.getAlarmLevel(Alarm.CELL_VOLTAGE_HIGH) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 13, pack.getAlarmLevel(Alarm.CHARGE_VOLTAGE_HIGH) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 14, pack.getAlarmLevel(Alarm.CHARGE_CURRENT_HIGH) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 15, pack.getAlarmLevel(Alarm.DISCHARGE_CURRENT_HIGH) == AlarmLevel.WARNING); + + alarm = BitUtil.setBit(alarm, 17, pack.getAlarmLevel(Alarm.SOC_LOW) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 18, pack.getAlarmLevel(Alarm.TEMPERATURE_SENSOR_DIFFERENCE_HIGH) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 19, pack.getAlarmLevel(Alarm.CHARGE_MODULE_TEMPERATURE_HIGH) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 20, pack.getAlarmLevel(Alarm.ENCASING_TEMPERATURE_HIGH) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 21, pack.getAlarmLevel(Alarm.FAILURE_COMMUNICATION_EXTERNAL) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 22, pack.getAlarmLevel(Alarm.FAILURE_COMMUNICATION_INTERNAL) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 23, pack.getAlarmLevel(Alarm.FAILURE_SHORT_CIRCUIT_PROTECTION) == AlarmLevel.WARNING); + alarm = BitUtil.setBit(alarm, 24, pack.getAlarmLevel(Alarm.SOC_LOW) == AlarmLevel.WARNING); + + frame.putInt(alarm); + + LOG.debug("Sending alarms: {}", Port.printBuffer(frame)); + return frame; + } + + + // 0x3130 + private ByteBuffer sendBatteryStatus(final BatteryPack pack) throws IOException { + final ByteBuffer frame = prepareSendFrame(0x00003130); + + // Battery voltage (0.1V) + frame.putChar((char) pack.packVoltage); + // Battery current (0.1A) offset -3000A + frame.putShort((short) pack.packCurrent); + // second level temperature (0.1 Celcius) offset -100C + frame.putShort((short) pack.tempAverage); + // Battery SOC (1%) + frame.put((byte) (pack.packSOC / 10)); + // Battery SOH (1%) + frame.put((byte) (pack.packSOH / 10)); + + LOG.debug("Sending battery status: {}", Port.printBuffer(frame)); + return frame; + } + + + // 0x3140 + private ByteBuffer sendBatteryCapacity(final BatteryPack pack) { + final ByteBuffer frame = prepareSendFrame(0x00003140); + + // Current battery energy (10mAH) + frame.putChar((char) (pack.remainingCapacitymAh / 10)); + // Rated battery energy (10mAH) + frame.putChar((char) (pack.ratedCapacitymAh / 10)); + // manufacturer code + frame.putChar(pack.manufacturerCode.charAt(0)); + // cycle count + frame.putChar((char) pack.bmsCycles); + + LOG.debug("Sending battery capacity: {}", Port.printBuffer(frame)); + return frame; + } + + + // 0x3150 + private ByteBuffer sendWorkingParams(final BatteryPack pack) { + final ByteBuffer frame = prepareSendFrame(0x00003150); + + // max discharge voltage (0.1V) + frame.putChar((char) pack.minPackVoltageLimit); + // case temperature (0.1C) + frame.putChar((char) pack.tempAverage); + // number of cells + frame.putChar((char) getEnergyStorage().getBatteryPacks().stream().mapToInt(p -> p.numberOfCells).sum()); + // number of packs + frame.putChar((char) getEnergyStorage().getBatteryPacks().size()); + + LOG.debug("Sending working params: {}", Port.printBuffer(frame)); + return frame; + } + + + // 0x3160 + private ByteBuffer sendFaultAndVoltageNumbers(final BatteryPack pack) { + final ByteBuffer frame = prepareSendFrame(0x00003160); + short faultFlags = 0x0000; + + faultFlags = BitUtil.setBit(faultFlags, 0, pack.getAlarmLevel(Alarm.FAILURE_SENSOR_PACK_VOLTAGE) != AlarmLevel.NONE); + faultFlags = BitUtil.setBit(faultFlags, 1, pack.getAlarmLevel(Alarm.FAILURE_SENSOR_CELL_TEMPERATURE) != AlarmLevel.NONE); + faultFlags = BitUtil.setBit(faultFlags, 2, pack.getAlarmLevel(Alarm.FAILURE_COMMUNICATION_INTERNAL) != AlarmLevel.NONE); + + // fault flags + frame.putShort(faultFlags); + + int minCellmV = Integer.MAX_VALUE; + int maxCellmV = Integer.MIN_VALUE; + byte maxVBatteryPackNumber = 0; + byte minVBatteryPackNumber = 0; + + for (int i = 0; i < getEnergyStorage().getBatteryPacks().size(); i++) { + final BatteryPack p = getEnergyStorage().getBatteryPacks().get(i); + final int packMaxCellmV = Arrays.stream(p.cellVmV).max().orElse(Integer.MIN_VALUE); + final int packMinCellmV = Arrays.stream(p.cellVmV).min().orElse(Integer.MAX_VALUE); + + if (packMinCellmV < minCellmV) { + minCellmV = packMinCellmV; + minVBatteryPackNumber = (byte) i; + } + + if (packMaxCellmV > maxCellmV) { + maxCellmV = packMaxCellmV; + maxVBatteryPackNumber = (byte) i; + } + } + + // number of module with max cell voltage + frame.put(maxVBatteryPackNumber); + // cell number with max voltage + frame.put((byte) pack.maxCellVNum); + // number of module with min cell voltage + frame.put(minVBatteryPackNumber); + // cell number with min voltage + frame.put((byte) pack.minCellVNum); + // min cell temperature + frame.put((byte) pack.tempMin); + + LOG.debug("Sending fault and voltage numbers: {}", Port.printBuffer(frame)); + return frame; + } + + + // 0x3170 + private ByteBuffer sendMinMaxCellTemperatures(final BatteryPack pack) { + final ByteBuffer frame = prepareSendFrame(0x00003170); + + int minTemp = Integer.MAX_VALUE; + int maxTemp = Integer.MIN_VALUE; + byte minCellNo = 0; + byte maxCellNo = 0; + byte minTempPackNumber = 0; + byte maxTempPackNumber = 0; + + for (int i = 0; i < getEnergyStorage().getBatteryPacks().size(); i++) { + final BatteryPack p = getEnergyStorage().getBatteryPacks().get(i); + + if (p.tempMin < minTemp) { + minTemp = p.tempMin; + minCellNo = (byte) p.tempMinCellNum; + minTempPackNumber = (byte) i; + } + + if (p.tempMax > maxTemp) { + maxTemp = p.tempMax; + maxCellNo = (byte) p.tempMaxCellNum; + maxTempPackNumber = (byte) i; + } + } + + frame.put(maxTempPackNumber); + frame.put(maxCellNo); + frame.put(minTempPackNumber); + frame.put(minCellNo); + + LOG.debug("Sending min/max cell temperaturs: {}", Port.printBuffer(frame)); + + return frame; + } + +} diff --git a/inverter-growatt-hv-can/src/main/resources/META-INF/beans.xml b/inverter-growatt-hv-can/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000..e5609411 --- /dev/null +++ b/inverter-growatt-hv-can/src/main/resources/META-INF/beans.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/inverter-growatt-hv-can/src/main/resources/META-INF/services/com.airepublic.bmstoinverter.core.InverterDescriptor b/inverter-growatt-hv-can/src/main/resources/META-INF/services/com.airepublic.bmstoinverter.core.InverterDescriptor new file mode 100644 index 00000000..e6752559 --- /dev/null +++ b/inverter-growatt-hv-can/src/main/resources/META-INF/services/com.airepublic.bmstoinverter.core.InverterDescriptor @@ -0,0 +1 @@ +com.airepublic.bmstoinverter.inverter.growatthv.can.GrowattHVInverterCANProcessor diff --git a/pom.xml b/pom.xml index f5186075..ad4612e8 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,7 @@ inverter-dummy inverter-goodwe-can inverter-growatt-can + inverter-growatt-hv-can inverter-growatt-modbus inverter-growatt-rs485 inverter-pylon-can