Skip to content

Commit

Permalink
Core.Sum: persist maximum ever values (#2476)
Browse files Browse the repository at this point in the history
Before this change calculation of maximum channels was always reset after restart. Configuration is a proper place to store this data, as there is no history required (i.e. Timedata does not fit) and it's easy to adjust values by customer service.

- drop respective channels from Electricity Meter
- mark Channels RESERVED in modbus registers
  • Loading branch information
sfeilmeier authored Dec 30, 2023
1 parent 08cfbb2 commit eac2153
Show file tree
Hide file tree
Showing 9 changed files with 324 additions and 259 deletions.
108 changes: 2 additions & 106 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 @@ -343,32 +343,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
PRODUCTION_MAX_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: Maximum Ever AC Active Power.
*
* <ul>
* <li>Interface: Sum (origin: ElectricityMeter))
* <li>Type: Integer
* <li>Unit: W
* <li>Range: positive values or '0'
* </ul>
*/
PRODUCTION_MAX_AC_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: Maximum Ever DC Actual Power.
*
* <ul>
* <li>Interface: Sum (origin: EssDcCharger}))
* <li>Type: Integer
* <li>Unit: W
* <li>Range: positive values or '0'
* </ul>
*/
PRODUCTION_MAX_DC_ACTUAL_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
.persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Consumption: Active Power.
*
Expand Down Expand Up @@ -656,11 +630,11 @@ public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode access
.channel(25, ChannelId.PRODUCTION_ACTIVE_POWER, ModbusType.FLOAT32) //
.channel(27, ChannelId.PRODUCTION_MAX_ACTIVE_POWER, ModbusType.FLOAT32) //
.channel(29, ChannelId.PRODUCTION_AC_ACTIVE_POWER, ModbusType.FLOAT32) //
.channel(31, ChannelId.PRODUCTION_MAX_AC_ACTIVE_POWER, ModbusType.FLOAT32) //
.float32Reserved(31) // ChannelId.PRODUCTION_MAX_AC_ACTIVE_POWER
.float32Reserved(33) // ChannelId.PRODUCTION_AC_REACTIVE_POWER
.float32Reserved(35) // ChannelId.PRODUCTION_MAX_AC_REACTIVE_POWER
.channel(37, ChannelId.PRODUCTION_DC_ACTUAL_POWER, ModbusType.FLOAT32) //
.channel(39, ChannelId.PRODUCTION_MAX_DC_ACTUAL_POWER, ModbusType.FLOAT32) //
.float32Reserved(39) // ChannelId.PRODUCTION_MAX_DC_ACTUAL_POWER
.channel(41, ChannelId.CONSUMPTION_ACTIVE_POWER, ModbusType.FLOAT32) //
.channel(43, ChannelId.CONSUMPTION_MAX_ACTIVE_POWER, ModbusType.FLOAT32) //
.float32Reserved(45) // ChannelId.CONSUMPTION_REACTIVE_POWER
Expand Down Expand Up @@ -1503,84 +1477,6 @@ public default void _setProductionMaxActivePower(int value) {
this.getProductionMaxActivePowerChannel().setNextValue(value);
}

/**
* Gets the Channel for {@link ChannelId#PRODUCTION_MAX_AC_ACTIVE_POWER}.
*
* @return the Channel
*/
public default IntegerReadChannel getProductionMaxAcActivePowerChannel() {
return this.channel(ChannelId.PRODUCTION_MAX_AC_ACTIVE_POWER);
}

/**
* Gets the Total Maximum Ever AC Production Active Power in [W]. See
* {@link ChannelId#PRODUCTION_MAX_AC_ACTIVE_POWER}.
*
* @return the Channel {@link Value}
*/
public default Value<Integer> getProductionMaxAcActivePower() {
return this.getProductionMaxAcActivePowerChannel().value();
}

/**
* Internal method to set the 'nextValue' on
* {@link ChannelId#PRODUCTION_MAX_AC_ACTIVE_POWER} Channel.
*
* @param value the next value
*/
public default void _setProductionMaxAcActivePower(Integer value) {
this.getProductionMaxAcActivePowerChannel().setNextValue(value);
}

/**
* Internal method to set the 'nextValue' on
* {@link ChannelId#PRODUCTION_MAX_AC_ACTIVE_POWER} Channel.
*
* @param value the next value
*/
public default void _setProductionMaxAcActivePower(int value) {
this.getProductionMaxAcActivePowerChannel().setNextValue(value);
}

/**
* Gets the Channel for {@link ChannelId#PRODUCTION_MAX_DC_ACTUAL_POWER}.
*
* @return the Channel
*/
public default IntegerReadChannel getProductionMaxDcActualPowerChannel() {
return this.channel(ChannelId.PRODUCTION_MAX_DC_ACTUAL_POWER);
}

/**
* Gets the Total Maximum Ever DC Production Actual Power in [W]. See
* {@link ChannelId#PRODUCTION_MAX_DC_ACTUAL_POWER}.
*
* @return the Channel {@link Value}
*/
public default Value<Integer> getProductionMaxDcActualPower() {
return this.getProductionMaxDcActualPowerChannel().value();
}

/**
* Internal method to set the 'nextValue' on
* {@link ChannelId#PRODUCTION_MAX_DC_ACTUAL_POWER} Channel.
*
* @param value the next value
*/
public default void _setProductionMaxDcActualPower(Integer value) {
this.getProductionMaxDcActualPowerChannel().setNextValue(value);
}

/**
* Internal method to set the 'nextValue' on
* {@link ChannelId#PRODUCTION_MAX_DC_ACTUAL_POWER} Channel.
*
* @param value the next value
*/
public default void _setProductionMaxDcActualPower(int value) {
this.getProductionMaxDcActualPowerChannel().setNextValue(value);
}

/**
* Gets the Channel for {@link ChannelId#CONSUMPTION_ACTIVE_POWER}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ private Prediction24Hours getPredictionSum(Sum.ChannelId channelId) {

PRODUCTION_ACTIVE_ENERGY, PRODUCTION_AC_ACTIVE_ENERGY, PRODUCTION_AC_ACTIVE_POWER_L1,
PRODUCTION_AC_ACTIVE_POWER_L2, PRODUCTION_AC_ACTIVE_POWER_L3, PRODUCTION_DC_ACTIVE_ENERGY,
PRODUCTION_MAX_ACTIVE_POWER, PRODUCTION_MAX_AC_ACTIVE_POWER, PRODUCTION_MAX_DC_ACTUAL_POWER, //
PRODUCTION_MAX_ACTIVE_POWER, //

HAS_IGNORED_COMPONENT_STATES ->
Prediction24Hours.EMPTY;
Expand Down
12 changes: 12 additions & 0 deletions io.openems.edge.core/src/io/openems/edge/core/sum/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@
description = "The global OpenEMS Summary data.")
@interface Config {

@AttributeDefinition(name = "Maximum ever Sell-to-Grid power [W]", description = "Range: negative or zero")
int gridMinActivePower() default 0;

@AttributeDefinition(name = "Maximum ever Buy-from-Grid power [W]", description = "Range: positive or zero")
int gridMaxActivePower() default 0;

@AttributeDefinition(name = "Maximum ever Production power [W]", description = "Includes AC- and DC-side production. Range: positive or zero")
int productionMaxActivePower() default 0;

@AttributeDefinition(name = "Maximum ever Consumption power [W]", description = "Range: positive or zero")
int consumptionMaxActivePower() default 0;

@AttributeDefinition(name = "Ignore Component Warnings/Faults", description = "Component-IDs for which Fault or Warning Channels should be ignored.")
String[] ignoreStateComponents() default {};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package io.openems.edge.core.sum;

import java.util.Dictionary;

import org.osgi.service.component.ComponentContext;

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

/**
* Holds maximum/minimum ever experienced values, handles updating the Channel
* and the Core.Sum configuration for persistence.
*/
public class ExtremeEverValue {

public static enum Range {
NEGATIVE, POSTIVE;
}

private final Sum.ChannelId targetChannelId;
private final String configProperty;
private final Range range;
private final Sum.ChannelId sourceChannelId;

private int value = 0;

public ExtremeEverValue(Sum.ChannelId targetChannelId, String configProperty, Range range,
Sum.ChannelId sourceChannelId) {
this.targetChannelId = targetChannelId;
this.configProperty = configProperty;
this.range = range;
this.sourceChannelId = sourceChannelId;
}

/**
* Initializes the {@link #value} from {@link ComponentContext}.
*
* @param context the {@link ComponentContext}
*/
public synchronized void initializeFromContext(ComponentContext context) {
this.value = (int) context.getProperties().get(this.configProperty);
}

/**
* Updates the {@link #value} from {@link Sum}-Channels.
*
* @param sum the {@link Sum} component
* @return myself if the extreme value was updated
*/
public synchronized ExtremeEverValue updateFromChannel(Sum sum) {
final ExtremeEverValue result;
var source = ((IntegerReadChannel) sum.channel(this.sourceChannelId)).getNextValue().get();
if (source != null && switch (this.range) {
case NEGATIVE -> source < this.value;
case POSTIVE -> source > this.value;
}) {
// New extreme value appeared
this.value = source;
// Trigger config update by returning myself
result = this;

} else {
// No new extreme value appeared
result = null;
}

// Update target Channel
sum.channel(this.targetChannelId).setNextValue(this.value);

return result;
}

/**
* Updates a {@link Config} Dictionary of Properties with the extreme value.
*
* @param properties the Properties Dictionary
*/
public synchronized void updateConfig(Dictionary<String, Object> properties) {
properties.put(this.configProperty, this.value);
}
}
Loading

0 comments on commit eac2153

Please sign in to comment.