Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GoodWe battery remote control improvements. #1201

Merged
merged 26 commits into from
Nov 10, 2020
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d3720f0
Added config input to enter the max battery charging/discharging power.
venu-sagar Aug 12, 2020
5a29113
allowed charge and discharge values are auto adjusted based on the so…
venu-sagar Aug 12, 2020
ad1e929
restructured the code.
venu-sagar Aug 12, 2020
c0871e0
Latest Changes charge/discharge
venu-sagar Sep 24, 2020
6ad88f8
changed power limits
venu-sagar Oct 7, 2020
399035f
Adjusting in the static battery limits.
venu-sagar Oct 19, 2020
b7eff23
Merge branch 'develop' into feature/GoodWeFix
venu-sagar Oct 19, 2020
92a5e99
merge problems rectified
venu-sagar Oct 19, 2020
b7e5081
corrected null pointer exception
venu-sagar Oct 20, 2020
e6ac2dc
Fix typo 'bateryPower'
sfeilmeier Oct 20, 2020
522721e
Drop unused channels
sfeilmeier Oct 20, 2020
62edc9b
Align comments with code
sfeilmeier Oct 20, 2020
4bfac2b
Drop unused channels (2nd try)
sfeilmeier Oct 20, 2020
3bcf7a7
Add JUnit tests according to definition of scenarios
sfeilmeier Oct 20, 2020
b29a809
rework on apply power funtion and converting it into a state machine
venu-sagar Oct 22, 2020
6d67c0d
Integrate BT + refactoring
sfeilmeier Oct 27, 2020
5b67b1f
ATTENTION: Renaming bundle to GoodWe instead of GoodWe.ET.
sfeilmeier Oct 27, 2020
dfac5e9
Cleanup code
sfeilmeier Oct 27, 2020
6b6110d
Rename java package; remove "et" from name
sfeilmeier Oct 28, 2020
e94815b
Merge branch 'develop' into feature/GoodWeFix
sfeilmeier Nov 1, 2020
19195fe
Reset to develop
sfeilmeier Nov 1, 2020
c45c9ed
Update ESS names
sfeilmeier Nov 1, 2020
69a5889
Merge branch 'develop' into feature/GoodWeFix
sfeilmeier Nov 10, 2020
807cac9
Fix Eclipse working set
sfeilmeier Nov 10, 2020
70bd217
Update readme
sfeilmeier Nov 10, 2020
c1a9385
Fix calculate Energy + improve modbus register priorities
sfeilmeier Nov 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion io.openems.edge.goodwe.et/bnd.bnd
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ Bundle-Version: 1.0.0.${tstamp}
io.openems.edge.timedata.api

-testpath: \
${testpath}
${testpath},\
com.ghgande.j2mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,8 @@
@AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus bridge.")
String modbus_id() default "modbus0";

@AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.")
String Modbus_target() default "";

String webconsole_configurationFactory_nameHint() default "GoodWe ET Charger PV1 [{id}]";
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,8 @@
@AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus bridge.")
String modbus_id() default "modbus0";

@AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.")
String Modbus_target() default "";

String webconsole_configurationFactory_nameHint() default "GoodWe ET Charger PV2 [{id}]";
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@

@AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus brige.")
String modbus_id() default "modbus0";
@AttributeDefinition(name = "Capacity", description = "Capacity of the battery in Wh")

@AttributeDefinition(name = "Capacity", description = "Capacity of the battery in [Wh]")
int capacity() default 9_000;

@AttributeDefinition(name = "Maximum power", description = "Maximum charge/discharge power in [W]")
int maxBatteryPower() default 5_200;

@AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.")
String Modbus_target() default "";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,34 +393,26 @@ protected ModbusProtocol defineModbusProtocol() {
public void applyPower(int activePower, int reactivePower) throws OpenemsNamedException {
final PowerModeEms nextPowerMode;

System.out.println("Active power:" + activePower);

if (this.config.readOnlyMode()) {
// Read-Only-Mode: fall-back to internal self-consumption optimization
nextPowerMode = PowerModeEms.AUTO;
activePower = 0;
} else {
if (activePower <= 0) {
// ActivePower is negative or zero -> CHARGE
if (activePower < 0) {
// ActivePower is negative -> CHARGE
sfeilmeier marked this conversation as resolved.
Show resolved Hide resolved
System.out.println(" Setting Charging");
nextPowerMode = PowerModeEms.CHARGE_BAT;

} else {
// ActivePower is positive -> DISCHARGE

/*
* Check if PV is available. Discharge mode changes according to availability of
* PV
*
* TODO PV mode is not working, need an update from GoodWe for this.
*/
Integer productionPower = null;
for (AbstractGoodWeEtCharger charger : this.chargers) {
productionPower = TypeUtils.sum(productionPower, charger.getActualPower().get());
}
if (productionPower == null) {
// No PV-Power -> required to put on SELL_POWER
nextPowerMode = PowerModeEms.SELL_POWER;
// ActivePower is positive or zero -> DISCHARGE
System.out.println(" Setting Discharging");
Integer soc = this.getSoc().get();
sfeilmeier marked this conversation as resolved.
Show resolved Hide resolved
if (soc == 100 || activePower == 0) {
nextPowerMode = PowerModeEms.EXPORT_AC;
} else {
// PV-Power exists -> set DISCHARGE_BAT
nextPowerMode = PowerModeEms.DISCHARGE_BAT;
nextPowerMode = PowerModeEms.DISCHARGE_PV;
}
}
}
Expand Down Expand Up @@ -482,7 +474,9 @@ private void updatechannels() {
*/
final Channel<Integer> batteryPower = this.channel(EssChannelId.P_BATTERY1);
Integer activePower = batteryPower.getNextValue().get();
Integer productionPower = null;
for (AbstractGoodWeEtCharger charger : this.chargers) {
productionPower = TypeUtils.sum(productionPower, charger.getActualPower().get());
activePower = TypeUtils.sum(activePower, charger.getActualPowerChannel().getNextValue().get());
sfeilmeier marked this conversation as resolved.
Show resolved Hide resolved
}
this._setActivePower(activePower);
Expand All @@ -507,19 +501,49 @@ private void updatechannels() {
/*
* Update Allowed charge and Allowed discharge
*/

// System.out.println(
// "Allowed Charge power: " + allowedChargePower + " Allowed Discharge Power: " + allowedDischargePower);

Integer soc = this.getSoc().get();
Integer maxApparentPower = this.getMaxApparentPower().get();
Integer maxBatteryPower = this.config.maxBatteryPower();

if (soc == null || soc >= 99) {
this._setAllowedChargePower(0);
} else {
this._setAllowedChargePower(TypeUtils.multiply(maxApparentPower, -1));
Integer allowedCharge = null;
Integer allowedDischarge = null;

if (productionPower == null) {
productionPower = 0;
sfeilmeier marked this conversation as resolved.
Show resolved Hide resolved
}
if (soc == null || soc <= 0) {
this._setAllowedDischargePower(0);
} else {
this._setAllowedDischargePower(maxApparentPower);

if (soc == null) {

allowedCharge = 0;
allowedDischarge = 0;

} else if (soc == 100) {

allowedDischarge = maxBatteryPower + productionPower;
allowedCharge = 0;

} else if (soc > 0) {

allowedDischarge = maxBatteryPower + productionPower;
allowedCharge = maxBatteryPower;

} else if (soc == 0) {

allowedDischarge = productionPower;
allowedCharge = maxBatteryPower;

}

// to avoid charging when production is greater than maximum battery power.
if (allowedCharge < 0) {
sfeilmeier marked this conversation as resolved.
Show resolved Hide resolved
allowedCharge = 0;
}

this._setAllowedChargePower(TypeUtils.multiply(allowedCharge * -1));
this._setAllowedDischargePower(allowedDischarge);
sfeilmeier marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
Expand All @@ -541,6 +565,7 @@ public Constraint[] getStaticConstraints() throws OpenemsNamedException {
this.createPowerConstraint("Read-Only-Mode", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, 0) //
};
}

return Power.NO_CONSTRAINTS;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package io.openems.edge.goodwe.et.charger;

import io.openems.common.utils.ConfigUtils;
import io.openems.edge.common.test.AbstractComponentConfig;

@SuppressWarnings("all")
public class MyConfig extends AbstractComponentConfig implements ConfigPV1 {

public static class Builder {
private String id = null;
public String essId;
public int unitId;
public String modbusId;

private Builder() {

}

public Builder setId(String id) {
this.id = id;
return this;
}

public Builder setEssId(String essId) {
this.essId = essId;
return this;
}

public Builder setModbusId(String modbusId) {
this.modbusId = modbusId;
return this;
}

public Builder setUnitId(int unitId) {
this.unitId = unitId;
return this;
}

public MyConfig build() {
return new MyConfig(this);
}
}

/**
* Create a Config builder.
*
* @return a {@link Builder}
*/
public static Builder create() {
return new Builder();
}

private final Builder builder;

private MyConfig(Builder builder) {
super(ConfigPV1.class, builder.id);
this.builder = builder;
}

@Override
public int unit_id() {
return this.builder.unitId;
}

@Override
public String modbus_id() {
return this.builder.modbusId;
}

@Override
public String Modbus_target() {
return ConfigUtils.generateReferenceTargetFilter(this.id(), this.modbus_id());
}

@Override
public String ess_id() {
return this.builder.essId;
}

@Override
public String Ess_target() {
return ConfigUtils.generateReferenceTargetFilter(this.id(), this.ess_id());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package io.openems.edge.goodwe.et.ess;

import org.junit.Test;

import io.openems.common.types.ChannelAddress;
import io.openems.edge.bridge.modbus.test.DummyModbusBridge;
import io.openems.edge.common.test.AbstractComponentTest.TestCase;
import io.openems.edge.common.test.ComponentTest;
import io.openems.edge.common.test.DummyConfigurationAdmin;
import io.openems.edge.ess.test.DummyPower;
import io.openems.edge.ess.test.ManagedSymmetricEssTest;
import io.openems.edge.goodwe.et.GoodWeEtConstants;
import io.openems.edge.goodwe.et.charger.GoodWeEtChargerPv1;

public class GoodWeEtBatteryInverterImplTest {

private static final String MODBUS_ID = "modbus0";

private static final String ESS_ID = "ess0";
private static final ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID,
"SetActivePowerEquals");
private static final ChannelAddress ESS_SOC = new ChannelAddress(ESS_ID, "Soc");
private static final ChannelAddress ESS_EMS_POWER_MODE = new ChannelAddress(ESS_ID, "EmsPowerMode");
private static final ChannelAddress ESS_EMS_POWER_SET = new ChannelAddress(ESS_ID, "EmsPowerSet");

private static final String CHARGER_ID = "charger0";
private static final ChannelAddress CHARGER_ACTUAL_POWER = new ChannelAddress(CHARGER_ID, "ActualPower");

@Test
public void test() throws Exception {
GoodWeEtChargerPv1 charger = new GoodWeEtChargerPv1();
new ComponentTest(charger) //
.addReference("cm", new DummyConfigurationAdmin()) //
.addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) //
.activate(io.openems.edge.goodwe.et.charger.MyConfig.create() //
.setId(CHARGER_ID) //
.setEssId(ESS_ID) //
.setModbusId(MODBUS_ID) //
.setUnitId(GoodWeEtConstants.DEFAULT_UNIT_ID) //
.build());

GoodWeEtBatteryInverterImpl ess = new GoodWeEtBatteryInverterImpl();
ess.addCharger(charger);
new ManagedSymmetricEssTest(ess) //
.addReference("power", new DummyPower()) //
.addReference("cm", new DummyConfigurationAdmin()) //
.addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) //
.addComponent(charger) //
.activate(MyConfig.create() //
.setId(ESS_ID) //
.setModbusId(MODBUS_ID) //
.setUnitId(GoodWeEtConstants.DEFAULT_UNIT_ID) //
.setCapacity(9_000) //
.setMaxBatteryPower(5_200) //
.setReadOnlyMode(false) //
.build()) //
.next(new TestCase("Scenario 1: (set-point is positive && set-point is lower than pv production)") //
sfeilmeier marked this conversation as resolved.
Show resolved Hide resolved
.input(CHARGER_ACTUAL_POWER, 5_000) //
.input(ESS_SOC, 50) //
.input(ESS_SET_ACTIVE_POWER_EQUALS, 3_000) //
.output(ESS_EMS_POWER_MODE, PowerModeEms.CHARGE_BAT) //
.output(ESS_EMS_POWER_SET, 2000)) //
.next(new TestCase("Scenario 2: (set-point is positive && set-Point is bigger than pv production)") //
.input(CHARGER_ACTUAL_POWER, 5_000) //
.input(ESS_SOC, 50) //
.input(ESS_SET_ACTIVE_POWER_EQUALS, 8_000) //
.output(ESS_EMS_POWER_MODE, PowerModeEms.DISCHARGE_PV) //
.output(ESS_EMS_POWER_SET, 3000)) //
.next(new TestCase(
"Scenario 3: (set-point is negative && PV-Power is smaller than max charge power of the battery)") //
.input(CHARGER_ACTUAL_POWER, 3_000) //
.input(ESS_SOC, 50) //
.input(ESS_SET_ACTIVE_POWER_EQUALS, -2_000) //
.output(ESS_EMS_POWER_MODE, PowerModeEms.CHARGE_BAT) //
.output(ESS_EMS_POWER_SET, 5_000)) //
.next(new TestCase(
"Scenario 4: (set-point is negative && PV-Power equals max charge power of the battery)") //
.input(CHARGER_ACTUAL_POWER, 3_000) //
.input(ESS_SOC, 50) //
.input(ESS_SET_ACTIVE_POWER_EQUALS, -4_000)) //
// TODO .output(ESS_EMS_POWER_MODE, PowerModeEms.DISCHARGE_PV) //
// TODO .output(ESS_EMS_POWER_SET, 3000)) //
.next(new TestCase("Scenario 5: (set-point is positive && set-point is higher than pv production)") //
.input(CHARGER_ACTUAL_POWER, 3_000) //
.input(ESS_SOC, 100) //
.input(ESS_SET_ACTIVE_POWER_EQUALS, 8_000) //
.output(ESS_EMS_POWER_MODE, PowerModeEms.DISCHARGE_BAT) //
.output(ESS_EMS_POWER_SET, 5_000)) //
.next(new TestCase("Scenario 6: (set-point is positive && set-point is lower than pv production)") //
.input(CHARGER_ACTUAL_POWER, 5_000) //
.input(ESS_SOC, 100) //
.input(ESS_SET_ACTIVE_POWER_EQUALS, 3_000)) //
// TODO .output(ESS_EMS_POWER_MODE, PowerModeEms.DISCHARGE_BAT) //
// TODO .output(ESS_EMS_POWER_SET, 5_000)) //
;
}

}
Loading