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

Sum: add Power and Energy distribution channels #2923

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,59 @@
return this.self();
}

/**
* Set {@link Sum.ChannelId#GRID_BUY_ACTIVE_ENERGY}.
*
* @param value the value
* @return myself
*/
public DummySum withGridBuyActiveEnergy(long value) {
withValue(this, Sum.ChannelId.GRID_BUY_ACTIVE_ENERGY, value);
return this.self();

Check warning on line 104 in io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java

View check run for this annotation

Codecov / codecov/patch

io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java#L103-L104

Added lines #L103 - L104 were not covered by tests
}

/**
* Set {@link Sum.ChannelId#GRID_SELL_ACTIVE_ENERGY}.
*
* @param value the value
* @return myself
*/
public DummySum withGridSellActiveEnergy(long value) {
withValue(this, Sum.ChannelId.GRID_SELL_ACTIVE_ENERGY, value);
return this.self();

Check warning on line 115 in io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java

View check run for this annotation

Codecov / codecov/patch

io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java#L114-L115

Added lines #L114 - L115 were not covered by tests
}

/**
* Set {@link Sum.ChannelId#ESS_ACTIVE_CHARGE_ENERGY}.
*
* @param value the value
* @return myself
*/
public DummySum withEssActiveChargeEnergy(long value) {
withValue(this, Sum.ChannelId.ESS_ACTIVE_CHARGE_ENERGY, value);
return this.self();

Check warning on line 126 in io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java

View check run for this annotation

Codecov / codecov/patch

io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java#L125-L126

Added lines #L125 - L126 were not covered by tests
}

/**
* Set {@link Sum.ChannelId#ESS_ACTIVE_DISCHARGE_ENERGY}.
*
* @param value the value
* @return myself
*/
public DummySum withEssActiveDischargeEnergy(long value) {
withValue(this, Sum.ChannelId.ESS_ACTIVE_DISCHARGE_ENERGY, value);
return this.self();

Check warning on line 137 in io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java

View check run for this annotation

Codecov / codecov/patch

io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java#L136-L137

Added lines #L136 - L137 were not covered by tests
}

/**
* Set {@link Sum.ChannelId#CONSUMPTION_ACTIVE_ENERGY}.
*
* @param value the value
* @return myself
*/
public DummySum withConsumptionActiveEnergy(long value) {
withValue(this, Sum.ChannelId.CONSUMPTION_ACTIVE_ENERGY, value);
return this.self();

Check warning on line 148 in io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java

View check run for this annotation

Codecov / codecov/patch

io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java#L147-L148

Added lines #L147 - L148 were not covered by tests
}

}
162 changes: 162 additions & 0 deletions io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,168 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
CONSUMPTION_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) //
.unit(Unit.CUMULATED_WATT_HOURS) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production to Consumption: Power.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Integer
* <li>Unit: W
* <li>Range: only positive
* </ul>
*/
PRODUCTION_TO_CONSUMPTION_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production to Consumption: Energy.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Long
* <li>Unit: Wh_Σ
* </ul>
*/
PRODUCTION_TO_CONSUMPTION_ENERGY(Doc.of(OpenemsType.LONG) //
.unit(Unit.CUMULATED_WATT_HOURS) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production to Grid: Power.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Integer
* <li>Unit: W
* <li>Range: only positive
* </ul>
*/
PRODUCTION_TO_GRID_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production to Grid: Energy.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Long
* <li>Unit: Wh_Σ
* </ul>
*/
PRODUCTION_TO_GRID_ENERGY(Doc.of(OpenemsType.LONG) //
.unit(Unit.CUMULATED_WATT_HOURS) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production to ESS: Power.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Integer
* <li>Unit: Wh_W
* <li>Range: only positive
* </ul>
*/
PRODUCTION_TO_ESS_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production to ESS: Energy.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Long
* <li>Unit: Wh_Σ
* </ul>
*/
PRODUCTION_TO_ESS_ENERGY(Doc.of(OpenemsType.LONG) //
.unit(Unit.CUMULATED_WATT_HOURS) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Grid to Consumption: Power.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Integer
* <li>Unit: W
* <li>Range: only positive
* </ul>
*/
GRID_TO_CONSUMPTION_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Grid to Consumption: Energy.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Long
* <li>Unit: Wh_Σ
* </ul>
*/
GRID_TO_CONSUMPTION_ENERGY(Doc.of(OpenemsType.LONG) //
.unit(Unit.CUMULATED_WATT_HOURS) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* ESS to Consumption: Power.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Integer
* <li>Unit: W
* <li>Range: only positive
* </ul>
*/
ESS_TO_CONSUMPTION_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* ESS to Consumption: Energy.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Long
* <li>Unit: Wh_Σ
* </ul>
*/
ESS_TO_CONSUMPTION_ENERGY(Doc.of(OpenemsType.LONG) //
.unit(Unit.CUMULATED_WATT_HOURS) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Grid to ESS: Power.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Integer
* <li>Unit: W
* <li>Range: discharge-to-grid negative, charge-from-grid positive
* </ul>
*/
GRID_TO_ESS_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Grid to ESS: Energy.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Long
* <li>Unit: Wh_Σ
* </ul>
*/
GRID_TO_ESS_ENERGY(Doc.of(OpenemsType.LONG) //
.unit(Unit.CUMULATED_WATT_HOURS) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* ESS to Grid: Energy.
*
* <ul>
* <li>Interface: Sum
* <li>Type: Long
* <li>Unit: Wh_Σ
* </ul>
*/
ESS_TO_GRID_ENERGY(Doc.of(OpenemsType.LONG) //
.unit(Unit.CUMULATED_WATT_HOURS) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //

/**
* Is there any Component Info/Warning/Fault that is getting ignored/hidden
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ public Prediction getPrediction(ChannelAddress channelAddress) {
private Prediction getPredictionSum(Sum.ChannelId channelId) {
return switch (channelId) {
case CONSUMPTION_ACTIVE_ENERGY, //
CONSUMPTION_ACTIVE_POWER_L1, CONSUMPTION_ACTIVE_POWER_L2, CONSUMPTION_ACTIVE_POWER_L3,
CONSUMPTION_MAX_ACTIVE_POWER, //
CONSUMPTION_ACTIVE_POWER, CONSUMPTION_ACTIVE_POWER_L1, CONSUMPTION_ACTIVE_POWER_L2,
CONSUMPTION_ACTIVE_POWER_L3, CONSUMPTION_MAX_ACTIVE_POWER, //

ESS_ACTIVE_CHARGE_ENERGY, ESS_ACTIVE_DISCHARGE_ENERGY, ESS_ACTIVE_POWER, ESS_ACTIVE_POWER_L1,
ESS_ACTIVE_POWER_L2, ESS_ACTIVE_POWER_L3, ESS_CAPACITY, ESS_DC_CHARGE_ENERGY, ESS_DC_DISCHARGE_ENERGY,
Expand All @@ -135,6 +135,11 @@ private Prediction getPredictionSum(Sum.ChannelId channelId) {
PRODUCTION_AC_ACTIVE_POWER_L2, PRODUCTION_AC_ACTIVE_POWER_L3, PRODUCTION_DC_ACTIVE_ENERGY,
PRODUCTION_MAX_ACTIVE_POWER, //

ESS_TO_CONSUMPTION_POWER, ESS_TO_CONSUMPTION_ENERGY, GRID_TO_CONSUMPTION_POWER,
GRID_TO_CONSUMPTION_ENERGY, GRID_TO_ESS_POWER, GRID_TO_ESS_ENERGY, ESS_TO_GRID_ENERGY,
PRODUCTION_TO_CONSUMPTION_POWER, PRODUCTION_TO_CONSUMPTION_ENERGY, PRODUCTION_TO_ESS_POWER,
PRODUCTION_TO_ESS_ENERGY, PRODUCTION_TO_GRID_POWER, PRODUCTION_TO_GRID_ENERGY,

HAS_IGNORED_COMPONENT_STATES ->
EMPTY_PREDICTION;

Expand All @@ -143,9 +148,6 @@ private Prediction getPredictionSum(Sum.ChannelId channelId) {
// ConsumptionActivePower by default
this.getPrediction(new ChannelAddress("_sum", "ConsumptionActivePower"));

// TODO
case CONSUMPTION_ACTIVE_POWER -> EMPTY_PREDICTION;

case PRODUCTION_DC_ACTUAL_POWER -> {
// Sum up "ActualPower" prediction of all EssDcChargers
List<EssDcCharger> chargers = this.componentManager.getEnabledComponentsOfType(EssDcCharger.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package io.openems.edge.core.sum;

import static java.lang.Math.max;
import static java.lang.Math.min;

import io.openems.edge.common.sum.Sum;

/**
* Calculates power distribution.
*/
public record PowerDistribution(//
Integer productionToConsumption, /* positive */
Integer productionToGrid, /* positive */
Integer productionToEss, /* positive */
Integer gridToConsumption, /* positive */
Integer essToConsumption, /* positive */
Integer gridToEss /* discharge-to-grid negative, charge-from-grid positive */
) {

public static final PowerDistribution EMPTY = new PowerDistribution(null, null, null, null, null, null);

/**
* Creates a {@link PowerDistribution}.
*
* @param grid the gridActivePower; possibly null
* @param production the productionActivePower; possibly null
* @param ess the essActivePower; possibly null
* @return a {@link PowerDistribution}; possibly {@link PowerDistribution#EMPTY}
*/
public static PowerDistribution of(Integer grid, Integer production, Integer ess) {
final PowerDistribution result;
if (grid != null && production != null && ess != null) {
result = of(grid.intValue(), production.intValue(), ess.intValue());

} else if (grid != null) {
if (production == null && ess == null) {
result = of(grid.intValue());
} else {
result = of(grid.intValue(), production != null ? production : 0, ess != null ? ess : 0);
}

} else {
result = EMPTY;
}
return result;
}

private static PowerDistribution of(int grid, int production, int ess) {
if (production < 0) { // invalid data
return EMPTY;
}
var consumption = ess + grid + production;
var essToConsumption = ess > 0 //
? /* discharge */ min(ess, consumption) //
: /* charge */ 0;
var productionToEss = ess > 0 //
? /* discharge */ 0 //
: /* charge */ min(-ess, production);
var productionToConsumption = min(production - productionToEss, consumption - essToConsumption);
var productionToGrid = max(0, production - productionToConsumption - productionToEss);
var gridToConsumption = max(0, consumption - essToConsumption - productionToConsumption);
var gridToEss = grid - gridToConsumption + productionToGrid;
return new PowerDistribution(productionToConsumption, productionToGrid, productionToEss, gridToConsumption,
essToConsumption, gridToEss);
}

private static PowerDistribution of(int grid) {
if (grid < 0) { // invalid data
return EMPTY;
}
// Grid Buy to Consumption
return new PowerDistribution(null, null, null, grid, null, null);
}

protected void updateChannels(SumImpl sum) {
// Power
sum.channel(Sum.ChannelId.PRODUCTION_TO_CONSUMPTION_POWER).setNextValue(this.productionToConsumption);
sum.channel(Sum.ChannelId.PRODUCTION_TO_GRID_POWER).setNextValue(this.productionToGrid);
sum.channel(Sum.ChannelId.PRODUCTION_TO_ESS_POWER).setNextValue(this.productionToEss);
sum.channel(Sum.ChannelId.GRID_TO_CONSUMPTION_POWER).setNextValue(this.gridToConsumption);
sum.channel(Sum.ChannelId.ESS_TO_CONSUMPTION_POWER).setNextValue(this.essToConsumption);
sum.channel(Sum.ChannelId.GRID_TO_ESS_POWER).setNextValue(this.gridToEss);

// Energy
sum.calculateProductionToConsumptionEnergy.update(this.productionToConsumption);
sum.calculateProductionToGridEnergy.update(this.productionToGrid);
sum.calculateProductionToEssEnergy.update(this.productionToEss);
sum.calculateGridToConsumptionEnergy.update(this.gridToConsumption);
sum.calculateEssToConsumptionEnergy.update(this.essToConsumption);
if (this.gridToEss == null) {
sum.calculateGridToEssEnergy.update(null);
sum.calculateEssToGridEnergy.update(null);

Check warning on line 92 in io.openems.edge.core/src/io/openems/edge/core/sum/PowerDistribution.java

View check run for this annotation

Codecov / codecov/patch

io.openems.edge.core/src/io/openems/edge/core/sum/PowerDistribution.java#L91-L92

Added lines #L91 - L92 were not covered by tests
} else if (this.gridToEss > 0) {
sum.calculateGridToEssEnergy.update(this.gridToEss);
sum.calculateEssToGridEnergy.update(0);

Check warning on line 95 in io.openems.edge.core/src/io/openems/edge/core/sum/PowerDistribution.java

View check run for this annotation

Codecov / codecov/patch

io.openems.edge.core/src/io/openems/edge/core/sum/PowerDistribution.java#L94-L95

Added lines #L94 - L95 were not covered by tests
} else {
sum.calculateGridToEssEnergy.update(0);
sum.calculateEssToGridEnergy.update(-this.gridToEss);
}
}
}
Loading
Loading