From 78babefab5d4c8a4c3b7315d69f88e13c395c863 Mon Sep 17 00:00:00 2001 From: Wolfgang Gerbl Date: Tue, 1 Dec 2020 17:57:09 +0100 Subject: [PATCH 01/22] extends Battery API adds setting of default values and protection mechanism (only for B Version Single) removes unnecessary files --- .../io/openems/edge/battery/api/Battery.java | 108 +++++- .../edge/battery/test/DummyBattery.java | 36 ++ .../doc/~$ngle Rack MOD-BUS protocol V3.6.doc | Bin 162 -> 0 bytes ...ter RS-485 Communication protocol- En.docx | Bin 162 -> 0 bytes .../battery/soltaro/CellCharacteristic.java | 10 + .../soltaro/SoltaroCellCharacteristic.java | 25 ++ .../io/openems/edge/battery/soltaro/Util.java | 133 +++++++ .../controller/BatteryHandlingController.java | 104 ----- .../battery/soltaro/controller/ChannelId.java | 27 -- .../battery/soltaro/controller/Config.java | 65 ---- .../battery/soltaro/controller/IState.java | 30 -- .../battery/soltaro/controller/State.java | 35 -- .../soltaro/controller/state/BaseState.java | 119 ------ .../soltaro/controller/state/Check.java | 86 ----- .../soltaro/controller/state/ForceCharge.java | 75 ---- .../soltaro/controller/state/FullCharge.java | 51 --- .../soltaro/controller/state/Limit.java | 105 ----- .../soltaro/controller/state/Normal.java | 83 ---- .../controller/state/StateController.java | 42 -- .../soltaro/controller/state/Undefined.java | 38 -- .../versionb/SingleRackVersionBImpl.java | 35 +- .../single/versionb/statemachine/Context.java | 9 +- .../versionb/statemachine/RunningHandler.java | 68 +++- .../{controller/helper => }/DummyBattery.java | 95 ++++- .../soltaro/DummyCellCharacteristic.java | 30 ++ .../edge/battery/soltaro/UtilTest.java | 362 ++++++++++++++++++ .../soltaro/controller/TestController.java | 57 --- .../controller/TestStateController.java | 36 -- .../soltaro/controller/helper/Creator.java | 153 -------- .../helper/DummyComponentManager.java | 56 --- .../soltaro/controller/helper/DummyEss.java | 114 ------ .../controller/state/TestBaseState.java | 129 ------- .../soltaro/controller/state/TestCheck.java | 137 ------- .../controller/state/TestForceCharge.java | 111 ------ .../controller/state/TestFullCharge.java | 114 ------ .../soltaro/controller/state/TestLimit.java | 264 ------------- .../soltaro/controller/state/TestNormal.java | 197 ---------- .../controller/state/TestUndefinedState.java | 87 ----- .../ess/test/ManagedSymmetricEssTest.java | 18 +- .../ess/generic/symmetric/ChannelManager.java | 27 ++ .../symmetric/GenericManagedSymmetricEss.java | 6 + .../GenericManagedSymmetricEssTest.java | 32 ++ 42 files changed, 957 insertions(+), 2352 deletions(-) delete mode 100644 io.openems.edge.battery.soltaro/doc/~$ngle Rack MOD-BUS protocol V3.6.doc delete mode 100644 io.openems.edge.battery.soltaro/doc/~$ster RS-485 Communication protocol- En.docx create mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/CellCharacteristic.java create mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java create mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/BatteryHandlingController.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/ChannelId.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/Config.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/IState.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/State.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/BaseState.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Check.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/ForceCharge.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/FullCharge.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Limit.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Normal.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/StateController.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Undefined.java rename io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/{controller/helper => }/DummyBattery.java (52%) create mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/DummyCellCharacteristic.java create mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/TestController.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/TestStateController.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/Creator.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/DummyComponentManager.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/DummyEss.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestBaseState.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestCheck.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestForceCharge.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestFullCharge.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestLimit.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestNormal.java delete mode 100644 io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestUndefinedState.java diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java index 4f5cfe9c89c..0558322fcc3 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java @@ -3,10 +3,12 @@ import org.osgi.annotation.versioning.ProviderType; import io.openems.common.channel.AccessMode; +import io.openems.common.channel.Level; import io.openems.common.channel.Unit; import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; @@ -113,6 +115,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { *
  • Interface: Battery *
  • Type: Integer *
  • Unit: A + *
  • Usually positive, negative for force discharge mode; see + * {@link ChannelId#FORCE_DISCHARGE_ACTIVE} * */ CHARGE_MAX_CURRENT(Doc.of(OpenemsType.INTEGER) // @@ -137,6 +141,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { *
  • Interface: Battery *
  • Type: Integer *
  • Unit: A + *
  • Usually positive, negative for force charge mode; see + * {@link ChannelId#FORCE_CHARGE_ACTIVE} * */ DISCHARGE_MAX_CURRENT(Doc.of(OpenemsType.INTEGER) // @@ -189,7 +195,29 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { * */ MAX_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIVOLT)); + .unit(Unit.MILLIVOLT)), + + /** + * Force charge active. + * + * + */ + FORCE_CHARGE_ACTIVE(Doc.of(Level.INFO).text("Force charge mode is active")), // + + /** + * Force discharge active. + * + * + */ + FORCE_DISCHARGE_ACTIVE(Doc.of(Level.INFO).text("Force discharge mode is active")), // + + ; private final Doc doc; @@ -710,4 +738,82 @@ public default void _setMaxCellVoltage(Integer value) { public default void _setMaxCellVoltage(int value) { this.getMaxCellVoltageChannel().setNextValue(value); } + + /** + * Gets the Channel for {@link ChannelId#FORCE_CHARGE_ACTIVE}. + * + * @return the Channel + */ + public default StateChannel getForceChargeActiveChannel() { + return this.channel(ChannelId.FORCE_CHARGE_ACTIVE); + } + + /** + * Gets the State. See + * {@link ChannelId#FORCE_CHARGE_ACTIVE}. + * + * @return the Channel {@link Value} + */ + public default Value getForceChargeActive() { + return this.getForceChargeActiveChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#FORCE_CHARGE_ACTIVE} + * Channel. + * + * @param value the next value + */ + public default void _setForceChargeActive(Boolean value) { + this.getForceChargeActiveChannel().setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#FORCE_CHARGE_ACTIVE} + * Channel. + * + * @param value the next value + */ + public default void _setForceChargeActive(boolean value) { + this.getForceChargeActiveChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#FORCE_DISCHARGE_ACTIVE}. + * + * @return the Channel + */ + public default StateChannel getForceDischargeActiveChannel() { + return this.channel(ChannelId.FORCE_DISCHARGE_ACTIVE); + } + + /** + * Gets the State. See + * {@link ChannelId#FORCE_DISCHARGE_ACTIVE}. + * + * @return the Channel {@link Value} + */ + public default Value getForceDischargeActive() { + return this.getForceDischargeActiveChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#FORCE_DISCHARGE_ACTIVE} + * Channel. + * + * @param value the next value + */ + public default void _setForceDischargeActive(Boolean value) { + this.getForceDischargeActiveChannel().setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#FORCE_DISCHARGE_ACTIVE} + * Channel. + * + * @param value the next value + */ + public default void _setForceDischargeActive(boolean value) { + this.getForceDischargeActiveChannel().setNextValue(value); + } } diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/test/DummyBattery.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/test/DummyBattery.java index 2db7674869d..cb5a3e411ab 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/test/DummyBattery.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/test/DummyBattery.java @@ -31,4 +31,40 @@ public void setStartStop(StartStop value) throws OpenemsNamedException { this._setStartStop(value); } + public DummyBattery withCapacity(int value) { + this._setCapacity(value); + this.getCapacityChannel().nextProcessImage(); + return this; + } + + public DummyBattery withVoltage(int value) { + this._setVoltage(value); + this.getVoltageChannel().nextProcessImage(); + return this; + } + + public DummyBattery withDischargeMaxCurrent(int value) { + this._setDischargeMaxCurrent(value); + this.getDischargeMaxCurrentChannel().nextProcessImage(); + return this; + } + + public DummyBattery withChargeMaxCurrent(int value) { + this._setChargeMaxCurrent(value); + this.getChargeMaxCurrentChannel().nextProcessImage(); + return this; + } + + public DummyBattery withMinCellVoltage(int value) { + this._setMinCellVoltage(value); + this.getMinCellVoltageChannel().nextProcessImage(); + return this; + } + + public DummyBattery withMaxCellVoltage(int value) { + this._setMaxCellVoltage(value); + this.getMaxCellVoltageChannel().nextProcessImage(); + return this; + } + } diff --git a/io.openems.edge.battery.soltaro/doc/~$ngle Rack MOD-BUS protocol V3.6.doc b/io.openems.edge.battery.soltaro/doc/~$ngle Rack MOD-BUS protocol V3.6.doc deleted file mode 100644 index f163817ac33f1d71bad7911ede7df4a775ca1c4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162 zcmd-J&(BFqPs~eKa8E5t%3&Z5@G*ol cellCharacteristic.getFinalCellChargeVoltage_mV(); + } + + protected static boolean isVoltageHigherThanForceChargeVoltage(CellCharacteristic cellCharacteristic, + Battery battery) { + return battery.getMinCellVoltage().get() > cellCharacteristic.getForceChargeCellVoltage_mV(); + } + + protected static boolean isVoltageBelowFinalDischargingVoltage(CellCharacteristic cellCharacteristic, + Battery battery) { + return battery.getMinCellVoltage().get() < cellCharacteristic.getFinalCellDischargeVoltage_mV(); + } + + protected static boolean isFurtherDischargingNecessary(CellCharacteristic cellCharacteristic, Battery battery) { + if (!battery.getForceDischargeActive().isDefined()) { + return false; + } + return (battery.getForceDischargeActive().get() && battery.getMaxCellVoltage().get() > cellCharacteristic.getFinalCellChargeVoltage_mV()); + } + + protected static boolean isDischargingAlready(Battery battery) { + return (battery.getForceDischargeActive().isDefined() && battery.getForceDischargeActive().get()); + } + + protected static int calculateForceDischargeCurrent(Battery battery) { + return calculateForceCurrent(battery); + } + + protected static int calculateForceChargeCurrent(Battery battery) { + return calculateForceCurrent(battery); + } + + protected static int calculateForceCurrent(Battery battery) { + double capacity = battery.getCapacity().get(); + double voltage = battery.getVoltage().get(); + double power = capacity * CHARGE_DISCHARGE_FACTOR; + double current = power / voltage; + int value = - (int) Math.max(MINIMUM_CURRENT, current); + return value; + } + + protected static boolean isFurtherChargingNecessary(CellCharacteristic cellCharacteristic, Battery battery) { + if (!battery.getForceChargeActive().isDefined()) { + return false; + } + return battery.getForceChargeActive().get() && battery.getMinCellVoltage().get() < cellCharacteristic.getFinalCellDischargeVoltage_mV(); + } + + protected static boolean isChargingAlready(Battery battery) { + return (battery.getForceChargeActive().isDefined() && battery.getForceChargeActive().get()); + } + + protected static boolean areApiValuesPresent(Battery battery) { + return + battery.getCapacity().isDefined() && + battery.getVoltage().isDefined() && + battery.getMinCellVoltage().isDefined() && + battery.getMaxCellVoltage().isDefined(); + } + +} diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/BatteryHandlingController.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/BatteryHandlingController.java deleted file mode 100644 index 841d23674b3..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/BatteryHandlingController.java +++ /dev/null @@ -1,104 +0,0 @@ -package io.openems.edge.battery.soltaro.controller; - -import org.osgi.service.component.ComponentContext; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.ConfigurationPolicy; -import org.osgi.service.component.annotations.Deactivate; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.metatype.annotations.Designate; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.edge.battery.soltaro.controller.state.StateController; -import io.openems.edge.common.component.AbstractOpenemsComponent; -import io.openems.edge.common.component.ComponentManager; -import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.controller.api.Controller; -import io.openems.edge.ess.api.SymmetricEss; - -@Designate(ocd = Config.class, factory = true) -@Component(// - name = "Controller.Soltaro.Batteryhandling", // - immediate = true, // - configurationPolicy = ConfigurationPolicy.REQUIRE // -) -public class BatteryHandlingController extends AbstractOpenemsComponent implements Controller, OpenemsComponent { - - @Reference - protected ComponentManager componentManager; - - private IState stateObject = null; - private Config config; - - public BatteryHandlingController() { - super(// - OpenemsComponent.ChannelId.values(), // - Controller.ChannelId.values(), // - io.openems.edge.battery.soltaro.controller.ChannelId.values() // - ); - } - - @Activate - void activate(ComponentContext context, Config config) throws OpenemsNamedException { - super.activate(context, config.id(), config.alias(), config.enabled()); - - this.checkConfiguration(config); - this.config = config; - StateController.init(this.componentManager, config); - this.stateObject = StateController.getStateObject(State.UNDEFINED); - } - - @Deactivate - protected void deactivate() { - super.deactivate(); - } - - @Override - public void run() throws OpenemsNamedException { - State nextState = this.stateObject.getNextState(); - this.stateObject = StateController.getStateObject(nextState); - this.stateObject.act(); - this.writeChannelValues(); - } - - private void writeChannelValues() throws OpenemsNamedException { - this.channel(io.openems.edge.battery.soltaro.controller.ChannelId.STATE_MACHINE) - .setNextValue(this.stateObject.getState()); - - SymmetricEss ess = this.componentManager.getComponent(this.config.ess_id()); - - this.channel(io.openems.edge.battery.soltaro.controller.ChannelId.MIN_CELL_VOLTAGE) - .setNextValue(ess.getMinCellVoltage()); - this.channel(io.openems.edge.battery.soltaro.controller.ChannelId.MAX_CELL_VOLTAGE) - .setNextValue(ess.getMaxCellVoltage()); - this.channel(io.openems.edge.battery.soltaro.controller.ChannelId.MIN_CELL_TEMPERATURE) - .setNextValue(ess.getMinCellTemperature()); - this.channel(io.openems.edge.battery.soltaro.controller.ChannelId.MAX_CELL_TEMPERATURE) - .setNextValue(ess.getMaxCellTemperature()); - this.channel(io.openems.edge.battery.soltaro.controller.ChannelId.ESS_POWER).setNextValue(ess.getActivePower()); - this.channel(io.openems.edge.battery.soltaro.controller.ChannelId.ESS_SOC) // - .setNextValue(ess.getSoc()); - } - - @Override - public String debugLog() { - State currentState = this.stateObject.getState(); - State nextState = this.stateObject.getNextState(); - if (currentState == nextState) { - return "State:" + currentState.getName(); - } else { - return "Changing State from [" + currentState.getName() + "] to [" + nextState.getName() + "]"; - } - } - - protected void checkConfiguration(Config config) throws OpenemsException { - if (config.chargePowerPercent() <= 0 || config.chargePowerPercent() > 100) { - throw new OpenemsException("ForceCharge power percentage must be > 0 and < 100"); - } - if (config.criticalLowCellVoltage() >= config.warningLowCellVoltage()) { - throw new OpenemsException("Critical low cell voltage must be lower than warning low cell voltage"); - } - // TODO finish checks - } -} diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/ChannelId.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/ChannelId.java deleted file mode 100644 index 47610e95e35..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/ChannelId.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.openems.edge.battery.soltaro.controller; - -import io.openems.common.channel.Unit; -import io.openems.common.types.OpenemsType; -import io.openems.edge.common.channel.Doc; - -public enum ChannelId implements io.openems.edge.common.channel.ChannelId { - STATE_MACHINE(Doc.of(State.values()).text("Current State of State-Machine")), // - MIN_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER).unit(Unit.MILLIVOLT)), // - MAX_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER).unit(Unit.MILLIVOLT)), // - MIN_CELL_TEMPERATURE(Doc.of(OpenemsType.INTEGER).unit(Unit.DEGREE_CELSIUS)), // - MAX_CELL_TEMPERATURE(Doc.of(OpenemsType.INTEGER).unit(Unit.DEGREE_CELSIUS)), // - ESS_SOC(Doc.of(OpenemsType.INTEGER).unit(Unit.PERCENT)), // - ESS_POWER(Doc.of(OpenemsType.INTEGER).unit(Unit.WATT)), // - ; - - private final Doc doc; - - private ChannelId(Doc doc) { - this.doc = doc; - } - - @Override - public Doc doc() { - return this.doc; - } -} \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/Config.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/Config.java deleted file mode 100644 index 8f2dd923fa7..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/Config.java +++ /dev/null @@ -1,65 +0,0 @@ -package io.openems.edge.battery.soltaro.controller; - -import org.osgi.service.metatype.annotations.AttributeDefinition; -import org.osgi.service.metatype.annotations.ObjectClassDefinition; - -@ObjectClassDefinition(// - name = "Controller Soltaro Battery Handling", // - description = "Forces charging or stops discharging when limits are reached." // -) -public @interface Config { - - @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") - String id() default "ctrlSoltaroBatteryHandling0"; - - @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") - String alias() default ""; - - @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") - boolean enabled() default true; - - @AttributeDefinition(name = "Ess-ID", description = "ID of Ess device.") - String ess_id(); - - @AttributeDefinition(name = "Bms-ID", description = "ID of Bms device.") - String bms_id(); - - @AttributeDefinition(name = "Warning Low Cell Voltage [mV]", description = "If voltage is below this value discharging is stopped.") - int warningLowCellVoltage() default 2900; - - @AttributeDefinition(name = "Critical Low Cell Voltage [mV]", description = "Charging is forced when minimal cell voltage is below this value.") - int criticalLowCellVoltage() default 2800; - - @AttributeDefinition(name = "Critical High Cell Voltage [mV]", description = "Charging is stopped when maximal cell voltage is above this value.") - int criticalHighCellVoltage() default 3650; - - @AttributeDefinition(name = "Warning SoC [%]", description = "If SoC is below this value discharging is stopped.") - int warningSoC() default 10; - - @AttributeDefinition(name = "Critical SoC [%]", description = "Charging is forced when SoC is below this value.") - int criticalSoC() default 5; - - @AttributeDefinition(name = "Delta SoC [%]", description = "Defines how far the SoC has to increase until discharging is allowed.") - int deltaSoC() default 5; - - @AttributeDefinition(name = "Low temperature [°C]", description = "If min cell temperature is below this temperature charging/discharging is stopped.") - int lowTemperature() default 0; - - @AttributeDefinition(name = "High temperature [°C]", description = "If max cell temperature is above this temperature charging/discharging is stopped.") - int highTemperature() default 60; - - @AttributeDefinition(name = "ForceCharge Power Percent [%]", description = "The charge power in percent from the maximum output of the ess") - int chargePowerPercent() default 20; - - @AttributeDefinition(name = "ForceCharge Power Time [s]", description = "Defines how long force charging is executed in seconds") - int chargingTime() default 600; - - @AttributeDefinition(name = "ForceCharge Reachable Min Cell Voltage [mV]", description = "Defines the min cell voltage that should be reached until force charge is stopped") - int forceChargeReachableMinCellVoltage() default 3100; - - @AttributeDefinition(name = "Unused Time [s]", description = "Defines time period how long an ess is allowed to do nothing until full charge is triggered") - long unusedTime() default 60 * 60 * 24 * 14; // two weeks - - String webconsole_configurationFactory_nameHint() default "Controller Ess Limit Total Discharge [{id}]"; - -} \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/IState.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/IState.java deleted file mode 100644 index 6ebed876483..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/IState.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.openems.edge.battery.soltaro.controller; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; - -public interface IState { - - /** - * Returns the corresponding state. - * - * @return the state - */ - State getState(); - - /** - * Depending on the circumstances the next state according to the state machine - * is returned. - * - * @return the next state - */ - State getNextState(); - - /** - * in this method everything should be executed what there is to do in this - * state. - * - * @throws OpenemsNamedException on error - */ - void act() throws OpenemsNamedException; - -} diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/State.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/State.java deleted file mode 100644 index 7143ddd7644..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/State.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.openems.edge.battery.soltaro.controller; - -import io.openems.common.types.OptionsEnum; - -public enum State implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - NORMAL(0, "Normal"), // - LIMIT(1, "Limit"), // - FORCE_CHARGE(3, "ForceCharge"), // - FULL_CHARGE(4, "FullCharge"), // - CHECK(5, "Check"); - - private final int value; - private final String name; - - private State(int value, String name) { - this.value = value; - this.name = name; - } - - @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; - } -} \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/BaseState.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/BaseState.java deleted file mode 100644 index 78b5901908a..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/BaseState.java +++ /dev/null @@ -1,119 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.api.Battery; -import io.openems.edge.battery.soltaro.controller.BatteryHandlingController; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.common.channel.value.Value; -import io.openems.edge.ess.api.ManagedSymmetricEss; -import io.openems.edge.ess.power.api.Phase; -import io.openems.edge.ess.power.api.Pwr; - -public abstract class BaseState implements IState { - - private final Logger log = LoggerFactory.getLogger(BaseState.class); - private ManagedSymmetricEss ess; - private Battery bms; - - public BaseState(ManagedSymmetricEss ess, Battery bms) { - this.ess = ess; - this.bms = bms; - } - - protected void denyCharge() { - Integer calculatedPower = 0; - calculatedPower = this.ess.getPower().fitValueIntoMinMaxPower(BatteryHandlingController.class.getName(), this.ess, - Phase.ALL, Pwr.ACTIVE, calculatedPower); - try { - this.ess.setActivePowerGreaterOrEquals(calculatedPower); - } catch (OpenemsNamedException e) { - this.log.error(e.getMessage()); - } - } - - protected void denyDischarge() { - Integer calculatedPower = 0; - calculatedPower = this.ess.getPower().fitValueIntoMinMaxPower(BatteryHandlingController.class.getName(), this.ess, - Phase.ALL, Pwr.ACTIVE, calculatedPower); - try { - this.ess.setActivePowerLessOrEquals(calculatedPower); - } catch (OpenemsNamedException e) { - this.log.error(e.getMessage()); - } - } - - protected void chargeEssWithPercentOfMaxPower(int chargePowerPercent) { - int maxCharge = this.ess.getPower().getMinPower(this.ess, Phase.ALL, Pwr.ACTIVE); - int calculatedPower = maxCharge / 100 * chargePowerPercent; - try { - this.ess.setActivePowerLessOrEquals(calculatedPower); - } catch (OpenemsNamedException e) { - this.log.error(e.getMessage()); - } - } - - protected boolean bmsNeedsFullCharge(long timeInSeconds) { - return false; - } - - protected boolean isNextStateUndefined() { - if (this.ess == null || this.bms == null) { - return true; - } - - Value minCellVoltageOpt = this.bms.getMinCellVoltage(); - if (!minCellVoltageOpt.isDefined()) { - return true; - } - - Value maxCellVoltageOpt = this.bms.getMaxCellVoltage(); - if (!maxCellVoltageOpt.isDefined()) { - return true; - } - - Value maxCellTemperature = this.bms.getMaxCellTemperature(); - if (!maxCellTemperature.isDefined()) { - return true; - } - - Value minCellTemperature = this.bms.getMinCellTemperature(); - if (!minCellTemperature.isDefined()) { - return true; - } - - Value soc = this.bms.getSoc(); - if (!soc.isDefined()) { - return true; - } - - return false; - } - - protected int getBmsSoC() { - return this.bms.getSoc().get(); // TODO this will throw a NullPointerException! - } - - protected int getBmsMinCellTemperature() { - return this.bms.getMinCellTemperature().get(); // TODO this will throw a NullPointerException! - } - - protected int getBmsMaxCellTemperature() { - return this.bms.getMaxCellTemperature().get(); // TODO this will throw a NullPointerException! - } - - protected int getBmsMinCellVoltage() { - return this.bms.getMinCellVoltage().get(); // TODO this will throw a NullPointerException! - } - - protected int getBmsMaxCellVoltage() { - return this.bms.getMaxCellVoltage().get(); // TODO this will throw a NullPointerException! - } - - public ManagedSymmetricEss getEss() { - return this.ess; - } - -} \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Check.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Check.java deleted file mode 100644 index d0fb454ded9..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Check.java +++ /dev/null @@ -1,86 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.api.Battery; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.ess.api.ManagedSymmetricEss; - -public class Check extends BaseState implements IState { - - private final Logger log = LoggerFactory.getLogger(Check.class); - private static int UNDEFINED_VALUE = -1; - - private int deltaSoC; - private long unusedTime; - private int criticalLowCellVoltage; - private int startSoC = UNDEFINED_VALUE; - - public Check(ManagedSymmetricEss ess, Battery bms, int deltaSoC, long unusedTime, - int criticalLowCellVoltage) { - super(ess, bms); - this.deltaSoC = deltaSoC; - this.unusedTime = unusedTime; - this.criticalLowCellVoltage = criticalLowCellVoltage; - } - - @Override - public State getState() { - return State.CHECK; - } - - @Override - public State getNextState() { - // According to the state machine the next states can be: - // UNDEFINED: if at least one value is not available - // CHECK: the soc has not increased enough - // NORMAL: soc has increased enough - // FORCE_CHARGE: cell voltage is under limit - - if (isNextStateUndefined()) { - this.resetStartSoc(); - return State.UNDEFINED; - } - - if (this.startSoC == UNDEFINED_VALUE) { - this.startSoC = getBmsSoC(); - } - - if (getBmsMinCellVoltage() < criticalLowCellVoltage) { - this.resetStartSoc(); - return State.FORCE_CHARGE; - } - - if (bmsNeedsFullCharge(this.unusedTime)) { - this.resetStartSoc(); - return State.FULL_CHARGE; - } - - if (this.hasSoCIncreasedEnough()) { - this.resetStartSoc(); - return State.NORMAL; - } - - return State.CHECK; - } - - @Override - public void act() throws OpenemsNamedException { - this.log.info("deny discharging"); - denyDischarge(); - } - - private boolean hasSoCIncreasedEnough() { - int soc = getBmsSoC(); - int delta = soc - startSoC; - return delta >= deltaSoC; - } - - private void resetStartSoc() { - this.startSoC = -1; - } - -} \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/ForceCharge.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/ForceCharge.java deleted file mode 100644 index 8c598fed47f..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/ForceCharge.java +++ /dev/null @@ -1,75 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import java.time.LocalDateTime; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.api.Battery; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.ess.api.ManagedSymmetricEss; - -public class ForceCharge extends BaseState implements IState { - - private final Logger log = LoggerFactory.getLogger(ForceCharge.class); - private int chargePowerPercent; - private int chargingTime; - private int reachableMinCellVoltage; - private LocalDateTime startTime = null; - - public ForceCharge(ManagedSymmetricEss ess, Battery bms, int chargePowerPercent, int chargingTime, - int reachableMinCellVoltage) { - super(ess, bms); - this.chargePowerPercent = chargePowerPercent; - this.chargingTime = chargingTime; - this.reachableMinCellVoltage = reachableMinCellVoltage; - } - - @Override - public State getState() { - return State.FORCE_CHARGE; - } - - @Override - public State getNextState() { - // According to the state machine the next states can be CHECK, FORCE_CHARGE or - // UNDEFINED - - if (isNextStateUndefined()) { - this.resetStartTime(); - return State.UNDEFINED; - } - - if (this.startTime == null) { - this.startTime = LocalDateTime.now(); - } - - if (this.isMinCellVoltageReached() || this.isChargingTimeOver()) { - this.resetStartTime(); - return State.CHECK; - } - - return State.FORCE_CHARGE; - } - - private boolean isMinCellVoltageReached() { - return getBmsMinCellVoltage() > reachableMinCellVoltage; - } - - private boolean isChargingTimeOver() { - return this.startTime.plusSeconds(this.chargingTime).isBefore(LocalDateTime.now()); - } - - private void resetStartTime() { - this.startTime = null; - - } - - @Override - public void act() throws OpenemsNamedException { - this.log.info("act"); - chargeEssWithPercentOfMaxPower(this.chargePowerPercent); - } -} \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/FullCharge.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/FullCharge.java deleted file mode 100644 index 272a37ef54b..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/FullCharge.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.api.Battery; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.ess.api.ManagedSymmetricEss; - -public class FullCharge extends BaseState implements IState { - - private static final int MAX_POWER_PERCENT = 100; - - private final Logger log = LoggerFactory.getLogger(FullCharge.class); - - private int criticalHighCellVoltage; - - public FullCharge(ManagedSymmetricEss ess, Battery bms, int criticalHighCellVoltage) { - super(ess, bms); - this.criticalHighCellVoltage = criticalHighCellVoltage; - } - - @Override - public State getState() { - return State.FULL_CHARGE; - } - - @Override - public State getNextState() { - // According to the state machine the next state is UNDEFINED, FULL_CHARGE or - // NORMAL - if (isNextStateUndefined()) { - return State.UNDEFINED; - } - - if (getBmsMaxCellVoltage() >= criticalHighCellVoltage) { - return State.NORMAL; - } - - return State.FULL_CHARGE; - } - - @Override - public void act() throws OpenemsNamedException { - this.log.info("Set charge power to max"); - chargeEssWithPercentOfMaxPower(MAX_POWER_PERCENT); - } - -} \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Limit.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Limit.java deleted file mode 100644 index ce2c8538e57..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Limit.java +++ /dev/null @@ -1,105 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.openems.edge.battery.api.Battery; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.ess.api.ManagedSymmetricEss; - -public class Limit extends BaseState implements IState { - - private final Logger log = LoggerFactory.getLogger(Limit.class); - - int warningLowCellVoltage; - int criticalLowCellVoltage; - int criticalHighCellVoltage; - int warningSoC; - int lowTemperature; - int highTemperature; - long unusedTime; - - public Limit(// - ManagedSymmetricEss ess, // - Battery bms, // - int warningLowCellVoltage, // - int criticalLowCellVoltage, // - int criticalHighCellVoltage, // - int warningSoC, // - int lowTemperature, // - int highTemperature, // - long unusedTime) { - super(ess, bms); - this.warningLowCellVoltage = warningLowCellVoltage; - this.criticalLowCellVoltage = criticalLowCellVoltage; - this.criticalHighCellVoltage = criticalHighCellVoltage; - this.warningSoC = warningSoC; - this.lowTemperature = lowTemperature; - this.highTemperature = highTemperature; - this.unusedTime = unusedTime; - } - - @Override - public State getState() { - return State.LIMIT; - } - - @Override - public State getNextState() { - - // According to the state machine the next states can be: - // NORMAL: ess is under normal operation conditions - // FORCE_CHARGE: minimal cell voltage has been fallen under critical value - // UNDEFINED: at least one value is not available - // FULL_CHARGE: system has done nothing within the configured time - - if (isNextStateUndefined()) { - return State.UNDEFINED; - } - - if (getBmsMinCellVoltage() < criticalLowCellVoltage) { - return State.FORCE_CHARGE; - } - - if (bmsNeedsFullCharge(this.unusedTime)) { - return State.FULL_CHARGE; - } - - if (// - getBmsMinCellVoltage() > warningLowCellVoltage && // - getBmsMaxCellVoltage() < criticalHighCellVoltage && // - getBmsMinCellTemperature() > lowTemperature && // - getBmsMaxCellTemperature() < highTemperature && // - getBmsSoC() > warningSoC // && unused time - ) { - return State.NORMAL; - } - - return State.LIMIT; - } - - @Override - public void act() { - this.log.info("act"); - // Deny further discharging or charging - - if (getBmsMinCellTemperature() <= lowTemperature || getBmsMaxCellTemperature() >= highTemperature) { - denyCharge(); - denyDischarge(); - } - - if (getBmsMinCellVoltage() <= warningLowCellVoltage) { - denyDischarge(); - } - - if (getBmsMaxCellVoltage() >= criticalHighCellVoltage) { - denyCharge(); - } - - if (getBmsSoC() <= warningSoC) { - denyDischarge(); - } - } - -} \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Normal.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Normal.java deleted file mode 100644 index deff5b54c7f..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Normal.java +++ /dev/null @@ -1,83 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import io.openems.edge.battery.api.Battery; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.ess.api.ManagedSymmetricEss; - -public class Normal extends BaseState implements IState { - - int warningLowCellVoltage; - int criticalHighCellVoltage; - int warningSoC; - int lowTemperature; - int highTemperature; - long unusedTime; - - public Normal(// - ManagedSymmetricEss ess, // - Battery bms, // - int warningLowCellVoltage, // - int criticalHighCellVoltage, // - int warningSoC, // - int lowTemperature, // - int highTemperature, // - long unusedTime) { - super(ess, bms); - this.warningLowCellVoltage = warningLowCellVoltage; - this.criticalHighCellVoltage = criticalHighCellVoltage; - this.warningSoC = warningSoC; - this.lowTemperature = lowTemperature; - this.highTemperature = highTemperature; - this.unusedTime = unusedTime; - } - - @Override - public State getState() { - return State.NORMAL; - } - - @Override - public State getNextState() { - // According to the state machine the next states can be: - // NORMAL: Ess is still under normal operation conditions - // UNDEFINED: at least one important value (soc, cell voltages/temperatures) is - // not available - // LIMIT: one important values has reached its limit - // FULL_CHARGE: ess was not used for defined time - if (isNextStateUndefined()) { - return State.UNDEFINED; - } - - if (getBmsMinCellVoltage() < warningLowCellVoltage) { - return State.LIMIT; - } - - if (getBmsMaxCellVoltage() > criticalHighCellVoltage) { - return State.LIMIT; - } - - if (getBmsMinCellTemperature() < lowTemperature) { - return State.LIMIT; - } - - if (getBmsMaxCellTemperature() > highTemperature) { - return State.LIMIT; - } - - if (getBmsSoC() < warningSoC) { - return State.LIMIT; - } - - if (bmsNeedsFullCharge(this.unusedTime)) { - return State.FULL_CHARGE; - } - - return State.NORMAL; - } - - @Override - public void act() { - // nothing to do - } -} \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/StateController.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/StateController.java deleted file mode 100644 index a179576a36b..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/StateController.java +++ /dev/null @@ -1,42 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import java.util.HashMap; -import java.util.Map; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.api.Battery; -import io.openems.edge.battery.soltaro.controller.Config; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.common.component.ComponentManager; -import io.openems.edge.ess.api.ManagedSymmetricEss; - -public class StateController { - - private static Map stateObjects; - - public static void init(ComponentManager componentManager, Config c) throws OpenemsNamedException { - stateObjects = new HashMap(); - - ManagedSymmetricEss ess; - Battery bms; - - ess = componentManager.getComponent(c.ess_id()); - bms = componentManager.getComponent(c.bms_id()); - stateObjects.put(State.UNDEFINED, new Undefined(ess, bms)); - stateObjects.put(State.NORMAL, new Normal(ess, bms, c.warningLowCellVoltage(), c.criticalHighCellVoltage(), - c.warningSoC(), c.lowTemperature(), c.highTemperature(), c.unusedTime())); - stateObjects.put(State.LIMIT, new Limit(ess, bms, c.warningLowCellVoltage(), c.criticalLowCellVoltage(), - c.criticalHighCellVoltage(), c.warningSoC(), c.lowTemperature(), c.highTemperature(), c.unusedTime())); - stateObjects.put(State.FORCE_CHARGE, new ForceCharge(ess, bms, c.chargePowerPercent(), c.chargingTime(), - c.forceChargeReachableMinCellVoltage())); - stateObjects.put(State.FULL_CHARGE, new FullCharge(ess, bms, c.criticalHighCellVoltage())); - stateObjects.put(State.CHECK, new Check(ess, bms, c.deltaSoC(), c.unusedTime(), c.criticalLowCellVoltage())); - - } - - public static IState getStateObject(State state) { - return stateObjects.get(state); - } - -} \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Undefined.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Undefined.java deleted file mode 100644 index b65a0121e17..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/controller/state/Undefined.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.openems.edge.battery.api.Battery; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.ess.api.ManagedSymmetricEss; - -public class Undefined extends BaseState implements IState { - - private final Logger log = LoggerFactory.getLogger(Undefined.class); - - public Undefined(ManagedSymmetricEss ess, Battery bms) { - super(ess, bms); - } - - @Override - public State getState() { - return State.UNDEFINED; - } - - @Override - public State getNextState() { - // According to the state machine the next state can only be NORMAL - if (isNextStateUndefined()) { - return State.UNDEFINED; - } - - return State.NORMAL; - } - - @Override - public void act() { - this.log.info("Nothing to do!"); - } -} diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java index 0ce7c68f617..dc2b5e09dc2 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java @@ -28,8 +28,11 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.edge.battery.api.Battery; +import io.openems.edge.battery.soltaro.CellCharacteristic; import io.openems.edge.battery.soltaro.ChannelIdImpl; import io.openems.edge.battery.soltaro.ModuleParameters; +import io.openems.edge.battery.soltaro.SoltaroCellCharacteristic; +import io.openems.edge.battery.soltaro.Util; import io.openems.edge.battery.soltaro.single.versionb.statemachine.Context; import io.openems.edge.battery.soltaro.single.versionb.statemachine.ControlAndLogic; import io.openems.edge.battery.soltaro.single.versionb.statemachine.StateMachine; @@ -62,8 +65,10 @@ @Component(// name = "Bms.Soltaro.SingleRack.VersionB", // immediate = true, // - configurationPolicy = ConfigurationPolicy.REQUIRE, // - property = { EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // + configurationPolicy = ConfigurationPolicy.REQUIRE, // + property = { + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // }) public class SingleRackVersionBImpl extends AbstractOpenemsModbusComponent implements Battery, OpenemsComponent, EventHandler, ModbusSlave, StartStoppable, SingleRackVersionB { @@ -86,6 +91,8 @@ public class SingleRackVersionBImpl extends AbstractOpenemsModbusComponent private Config config; private Map> channelMap; + + private CellCharacteristic cellCharacteristic = new SoltaroCellCharacteristic(); public SingleRackVersionBImpl() { super(// @@ -127,7 +134,7 @@ private void handleStateMachine() { this._setStartStop(StartStop.UNDEFINED); // Prepare Context - Context context = new Context(this, this.config); + Context context = new Context(this, this.config, this.cellCharacteristic); // Call the StateMachine try { @@ -157,12 +164,29 @@ public void handleEvent(Event event) { } switch (event.getTopic()) { + + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: + + this.setAllowedCurrents(); + + break; + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: this.handleStateMachine(); break; } } + private void setAllowedCurrents() { + IntegerReadChannel maxChargeCurrentChannel = this.channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_CHARGE_CURRENT); + int maxChargeCurrentFromBMS = maxChargeCurrentChannel.value().orElse(0) / 1000; + + IntegerReadChannel maxDischargeChannel = this.channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_DISCHARGE_CURRENT); + int maxDischargeCurrentFromBMS = maxDischargeChannel.value().orElse(0) / 1000; + + Util.setMaxAllowedCurrents(cellCharacteristic, maxChargeCurrentFromBMS, maxDischargeCurrentFromBMS, this); + } + @Override public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { return new ModbusSlaveTable(// @@ -496,14 +520,11 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { m(new UnsignedWordElement(0x2160)) // .m(SingleRackVersionB.ChannelId.SYSTEM_MAX_CHARGE_CURRENT, - ElementToChannelConverter.SCALE_FACTOR_2) // - .m(Battery.ChannelId.CHARGE_MAX_CURRENT, ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // + ElementToChannelConverter.SCALE_FACTOR_2) // .build(), // m(new UnsignedWordElement(0x2161)) // .m(SingleRackVersionB.ChannelId.SYSTEM_MAX_DISCHARGE_CURRENT, ElementToChannelConverter.SCALE_FACTOR_2) // - .m(Battery.ChannelId.DISCHARGE_MAX_CURRENT, - ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // .build() // ), // diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/Context.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/Context.java index f630333adf2..ad732ee9b5d 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/Context.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/Context.java @@ -1,15 +1,18 @@ package io.openems.edge.battery.soltaro.single.versionb.statemachine; +import io.openems.edge.battery.soltaro.CellCharacteristic; import io.openems.edge.battery.soltaro.single.versionb.Config; -import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionB; +import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionBImpl; public class Context { - protected final SingleRackVersionB component; + protected final SingleRackVersionBImpl component; protected final Config config; + protected final CellCharacteristic cellCharacteristic; - public Context(SingleRackVersionB component, Config config) { + public Context(SingleRackVersionBImpl component, Config config, CellCharacteristic cellCharacteristic) { super(); this.component = component; this.config = config; + this.cellCharacteristic = cellCharacteristic; } } \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java index bc2e1514ef4..a0c96db3eeb 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java @@ -1,13 +1,34 @@ package io.openems.edge.battery.soltaro.single.versionb.statemachine; +import java.time.LocalDateTime; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionB; import io.openems.edge.battery.soltaro.single.versionb.statemachine.StateMachine.State; +import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; public class RunningHandler extends StateHandler { + public static int refreshIntervalSeconds = 900; + LocalDateTime refreshTime = null; + + + @Override + protected void onExit(Context context) throws OpenemsNamedException { + refreshTime = null; + super.onExit(context); + } + + @Override + protected void onEntry(Context context) throws OpenemsNamedException { + super.onEntry(context); + refreshTime = LocalDateTime.now(); + } + @Override - public State runAndGetNextState(Context context) { + public State runAndGetNextState(Context context) throws OpenemsNamedException { if (ControlAndLogic.hasError(context.component, context.config.numberOfSlaves())) { return State.UNDEFINED; } @@ -18,8 +39,53 @@ public State runAndGetNextState(Context context) { // Mark as started context.component._setStartStop(StartStop.START); + + refreshBatteryValues(context); return State.RUNNING; } + private void refreshBatteryValues(Context context) throws OpenemsNamedException { + if (refreshTime.plusSeconds(refreshIntervalSeconds).isBefore(LocalDateTime.now())) { + refreshTime = LocalDateTime.now(); + setBatteryValues(context); + } + + } + + private void setBatteryValues(Context context) throws OpenemsNamedException { + + // 0x2086 ==> 2800 + WriteChannel channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_VOLTAGE_ALARM); + channel.setNextWriteValue(context.cellCharacteristic.getFinalCellDischargeVoltage_mV()); + + // 0x2087 ==> 2850 + channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_VOLTAGE_RECOVER); + channel.setNextWriteValue(context.cellCharacteristic.getFinalCellDischargeVoltage_mV() + 50); + + // 0x2047 ==> 2750 + channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_VOLTAGE_RECOVER); + channel.setNextWriteValue(context.cellCharacteristic.getForceChargeCellVoltage_mV()); + + // 0x2046 ==> 2700 + channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_VOLTAGE_PROTECTION); + channel.setNextWriteValue(context.cellCharacteristic.getForceChargeCellVoltage_mV() - 50); + + // 0x2080 ==> 3650 + channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_VOLTAGE_ALARM); + channel.setNextWriteValue(context.cellCharacteristic.getFinalCellChargeVoltage_mV()); + + // 0x2081 ==> 3600 + channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_VOLTAGE_RECOVER); + channel.setNextWriteValue(context.cellCharacteristic.getFinalCellChargeVoltage_mV() - 50); + + // 0x2041 ==> 3680 + channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_VOLTAGE_RECOVER); + channel.setNextWriteValue(context.cellCharacteristic.getForceDischargeCellVoltage_mV()); + + // 0x2040 ==> 3730 + channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_VOLTAGE_PROTECTION); + channel.setNextWriteValue(context.cellCharacteristic.getForceDischargeCellVoltage_mV() + 50); + } + } diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/DummyBattery.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/DummyBattery.java similarity index 52% rename from io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/DummyBattery.java rename to io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/DummyBattery.java index ac5b26fa072..c7cc5232e3b 100644 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/DummyBattery.java +++ b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/DummyBattery.java @@ -1,4 +1,4 @@ -package io.openems.edge.battery.soltaro.controller.helper; +package io.openems.edge.battery.soltaro; import io.openems.common.exceptions.NotImplementedException; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; @@ -10,11 +10,15 @@ public class DummyBattery extends AbstractOpenemsComponent implements Battery, StartStoppable { - public static int DEFAULT_SOC = 50; - public static int DEFAULT_MIN_CELL_VOLTAGE = 3280; - public static int DEFAULT_MAX_CELL_VOLTAGE = 3380; - public static int DEFAULT_MIN_CELL_TEMPERATURE = 25; - public static int DEFAULT_MAX_CELL_TEMPERATURE = 33; + public static final int DEFAULT_SOC = 50; + public static final int DEFAULT_CAPACITY = 50_000; + public static final int DEFAULT_VOLTAGE = 750; + public static final int DEFAULT_MIN_CELL_VOLTAGE = 3280; + public static final int DEFAULT_MAX_CELL_VOLTAGE = 3380; + public static final int DEFAULT_MIN_CELL_TEMPERATURE = 25; + public static final int DEFAULT_MAX_CELL_TEMPERATURE = 33; + public static final int DEFAULT_MAX_CHARGE_CURRENT = 50; + public static final int DEFAULT_MAX_DISCHARGE_CURRENT = 50; protected DummyBattery(// ) { // @@ -24,24 +28,15 @@ protected DummyBattery(// StartStoppable.ChannelId.values() // ); -// getChargeIndication().onSetNextValue( v -> { -// -// if (v != null && v.get() != null) { -// ChargeIndication indication = v.get(); -// if (indication == ChargeIndication.CHARGING || indication == ChargeIndication.DISCHARGING) { -// LocalDateTime time = LocalDateTime.now(); -// long seconds = time.toEpochSecond(ZONE_OFFSET); -// getNotActiveSince().setNextValue(seconds); -//// ICH WEISS ES NICHT -// } -// } -// }); - setMinimalCellVoltage(DEFAULT_MIN_CELL_VOLTAGE); setMaximalCellVoltage(DEFAULT_MAX_CELL_VOLTAGE); setMinimalCellTemperature(DEFAULT_MIN_CELL_TEMPERATURE); setMaximalCellTemperature(DEFAULT_MAX_CELL_TEMPERATURE); setSoc(DEFAULT_SOC); + setCapacity(DEFAULT_CAPACITY); + setVoltage(DEFAULT_VOLTAGE); + setChargeMaxCurrent(DEFAULT_MAX_CHARGE_CURRENT); + setDischargeMaxCurrent(DEFAULT_MAX_DISCHARGE_CURRENT); } public void setMinimalCellVoltage(int minimalCellVoltage) { @@ -93,10 +88,70 @@ public void setSocToUndefined() { this._setSoc(null); this.getSocChannel().nextProcessImage(); } + + public void setVoltage(int voltage) { + this._setVoltage(voltage); + this.getVoltageChannel().nextProcessImage(); + } + + public void setVoltageToUndefined() { + this._setVoltage(null); + this.getVoltageChannel().nextProcessImage(); + } + + public void setCapacity(int capacity) { + this._setCapacity(capacity); + this.getCapacityChannel().nextProcessImage(); + } + + public void setCapacityToUndefined() { + this._setCapacity(null); + this.getCapacityChannel().nextProcessImage(); + } + + public void setForceDischargeActive(boolean active) { + this._setForceDischargeActive(active); + this.getForceDischargeActiveChannel().nextProcessImage(); + } + + public void setForceDischargeActiveToUndefined() { + this._setForceDischargeActive(null); + this.getForceDischargeActiveChannel().nextProcessImage(); + } + + public void setForceChargeActive(boolean active) { + this._setForceChargeActive(active); + this.getForceChargeActiveChannel().nextProcessImage(); + } + + public void setForceChargeActiveToUndefined() { + this._setForceChargeActive(null); + this.getForceChargeActiveChannel().nextProcessImage(); + } + + public void setChargeMaxCurrent(int value) { + this._setChargeMaxCurrent(value); + this.getChargeMaxCurrentChannel().nextProcessImage(); + } + public void setChargeMaxCurrentToUndefined() { + this._setChargeMaxCurrent(null); + this.getChargeMaxCurrentChannel().nextProcessImage(); + } + + public void setDischargeMaxCurrent(int value) { + this._setDischargeMaxCurrent(value); + this.getDischargeMaxCurrentChannel().nextProcessImage(); + } + + public void setDischargeMaxCurrentToUndefined() { + this._setDischargeMaxCurrent(null); + this.getDischargeMaxCurrentChannel().nextProcessImage(); + } + @Override public void setStartStop(StartStop value) throws OpenemsNamedException { // TODO start stop is not implemented - throw new NotImplementedException("Start Stop is not implemented for Soltaro SingleRack Version B"); + throw new NotImplementedException("Start Stop is not implemented"); } } diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/DummyCellCharacteristic.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/DummyCellCharacteristic.java new file mode 100644 index 00000000000..9682381869b --- /dev/null +++ b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/DummyCellCharacteristic.java @@ -0,0 +1,30 @@ +package io.openems.edge.battery.soltaro; + +public class DummyCellCharacteristic implements CellCharacteristic { + + public static final int FINAL_CELL_CHARGE_VOLTAGE_MV = 3_650; + public static final int FINAL_CELL_DISCHARGE_VOLTAGE_MV = 2_900; + public static final int FORCE_CHARGE_CELL_VOLTAGE_MV = 2_800; + public static final int FORCE_DISCHARGE_CELL_VOLTAGE_MV = 3_680; + + @Override + public int getFinalCellChargeVoltage_mV() { + return FINAL_CELL_CHARGE_VOLTAGE_MV; + } + + @Override + public int getFinalCellDischargeVoltage_mV() { + return FINAL_CELL_DISCHARGE_VOLTAGE_MV; + } + + @Override + public int getForceChargeCellVoltage_mV() { + return FORCE_CHARGE_CELL_VOLTAGE_MV; + } + + @Override + public int getForceDischargeCellVoltage_mV() { + return FORCE_DISCHARGE_CELL_VOLTAGE_MV; + } + +} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java new file mode 100644 index 00000000000..9c19501f68f --- /dev/null +++ b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java @@ -0,0 +1,362 @@ +package io.openems.edge.battery.soltaro; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; + +public class UtilTest { + + private DummyBattery battery; + private DummyCellCharacteristic cellCharacteristic; + + @Before + public void setUp() throws Exception { + battery = new DummyBattery(); + cellCharacteristic = new DummyCellCharacteristic(); + } + + @Test + public void testSetMaxAllowedCurrents() { + // Nothing is necessary + int maxDischargeCurrentFromBMS = DummyBattery.DEFAULT_MAX_DISCHARGE_CURRENT; + int maxChargeCurrentFromBMS = DummyBattery.DEFAULT_MAX_CHARGE_CURRENT; + Util.setMaxAllowedCurrents(cellCharacteristic, maxChargeCurrentFromBMS, maxDischargeCurrentFromBMS, battery); + + battery.getChargeMaxCurrentChannel().nextProcessImage(); + battery.getForceDischargeActiveChannel().nextProcessImage(); + battery.getDischargeMaxCurrentChannel().nextProcessImage(); + battery.getForceChargeActiveChannel().nextProcessImage(); + + int expectedMaxChargeCurrent = maxChargeCurrentFromBMS; + int actualMaxChargeCurrent = battery.getChargeMaxCurrent().get(); + assertEquals(expectedMaxChargeCurrent, actualMaxChargeCurrent); + int expectedMaxDischargeCurrent = maxDischargeCurrentFromBMS; + int actualMaxDischargeCurrent = battery.getDischargeMaxCurrent().get(); + assertEquals(expectedMaxDischargeCurrent, actualMaxDischargeCurrent); + boolean expectedChargeForce = false; + boolean actualChargeForce = battery.getForceChargeActive().get(); + assertEquals(expectedChargeForce, actualChargeForce); + boolean expectedDischargeForce = false; + boolean actualdischargeForce = battery.getForceDischargeActive().get(); + assertEquals(expectedDischargeForce, actualdischargeForce); + + // Battery has to be charged + maxDischargeCurrentFromBMS = 0; + battery.setMinimalCellVoltage(DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV); + + Util.setMaxAllowedCurrents(cellCharacteristic, maxChargeCurrentFromBMS, maxDischargeCurrentFromBMS, battery); + + battery.getChargeMaxCurrentChannel().nextProcessImage(); + battery.getForceDischargeActiveChannel().nextProcessImage(); + battery.getDischargeMaxCurrentChannel().nextProcessImage(); + battery.getForceChargeActiveChannel().nextProcessImage(); + + expectedMaxChargeCurrent = maxChargeCurrentFromBMS; + actualMaxChargeCurrent = battery.getChargeMaxCurrent().get(); + assertEquals(expectedMaxChargeCurrent, actualMaxChargeCurrent); + + expectedMaxDischargeCurrent = - (int) Math.max(1, battery.getCapacity().get() * 0.02 / battery.getVoltage().get()); + actualMaxDischargeCurrent = battery.getDischargeMaxCurrent().get(); + assertEquals(expectedMaxDischargeCurrent, actualMaxDischargeCurrent); + expectedChargeForce = true; + actualChargeForce = battery.getForceChargeActive().get(); + assertEquals(expectedChargeForce, actualChargeForce); + expectedDischargeForce = false; + actualdischargeForce = battery.getForceDischargeActive().get(); + assertEquals(expectedDischargeForce, actualdischargeForce); + } + + @Test + public void testSetChannelsForCharge() { + int expectedCurrent = DummyBattery.DEFAULT_MAX_CHARGE_CURRENT; + int actualCurrent = battery.getChargeMaxCurrent().get(); + assertEquals(expectedCurrent, actualCurrent); + + // Battery can be charged, no discharge necessary + int maxChargeCurrent = DummyBattery.DEFAULT_MAX_CHARGE_CURRENT + 1; + Util.setChannelsForCharge(maxChargeCurrent, battery); + battery.getChargeMaxCurrentChannel().nextProcessImage(); + battery.getForceDischargeActiveChannel().nextProcessImage(); + + expectedCurrent = maxChargeCurrent; + actualCurrent = battery.getChargeMaxCurrent().get(); + assertEquals(expectedCurrent, actualCurrent); + + boolean expectedForce = false; + boolean actualForce = battery.getForceDischargeActive().get(); + assertEquals(expectedForce, actualForce); + + // Battery cannot be charged, no discharge necessary + maxChargeCurrent = 0; + Util.setChannelsForCharge(maxChargeCurrent, battery); + battery.getChargeMaxCurrentChannel().nextProcessImage(); + battery.getForceDischargeActiveChannel().nextProcessImage(); + + expectedCurrent = maxChargeCurrent; + actualCurrent = battery.getChargeMaxCurrent().get(); + assertEquals(expectedCurrent, actualCurrent); + + expectedForce = false; + actualForce = battery.getForceDischargeActive().get(); + assertEquals(expectedForce, actualForce); + + // Battery cannot be charged, must be discharged + maxChargeCurrent = -8; + Util.setChannelsForCharge(maxChargeCurrent, battery); + battery.getChargeMaxCurrentChannel().nextProcessImage(); + battery.getForceDischargeActiveChannel().nextProcessImage(); + + expectedCurrent = maxChargeCurrent; + actualCurrent = battery.getChargeMaxCurrent().get(); + assertEquals(expectedCurrent, actualCurrent); + + expectedForce = true; + actualForce = battery.getForceDischargeActive().get(); + assertEquals(expectedForce, actualForce); + } + + @Test + public void testSetChannelsForDischarge() { + int expectedCurrent = DummyBattery.DEFAULT_MAX_DISCHARGE_CURRENT; + int actualCurrent = battery.getDischargeMaxCurrent().get(); + assertEquals(expectedCurrent, actualCurrent); + + // Battery can be discharged, no charge necessary + int maxDischargeCurrent = DummyBattery.DEFAULT_MAX_DISCHARGE_CURRENT + 1; + Util.setChannelsForDischarge(maxDischargeCurrent, battery); + battery.getDischargeMaxCurrentChannel().nextProcessImage(); + battery.getForceChargeActiveChannel().nextProcessImage(); + + expectedCurrent = maxDischargeCurrent; + actualCurrent = battery.getDischargeMaxCurrent().get(); + assertEquals(expectedCurrent, actualCurrent); + + boolean expectedForce = false; + boolean actualForce = battery.getForceChargeActive().get(); + assertEquals(expectedForce, actualForce); + + // Battery cannot be discharged, no charge necessary + maxDischargeCurrent = 0; + Util.setChannelsForDischarge(maxDischargeCurrent, battery); + battery.getDischargeMaxCurrentChannel().nextProcessImage(); + battery.getForceChargeActiveChannel().nextProcessImage(); + + expectedCurrent = maxDischargeCurrent; + actualCurrent = battery.getDischargeMaxCurrent().get(); + assertEquals(expectedCurrent, actualCurrent); + + expectedForce = false; + actualForce = battery.getForceChargeActive().get(); + assertEquals(expectedForce, actualForce); + + // Battery cannot be charged, must be charged + maxDischargeCurrent = -8; + Util.setChannelsForDischarge(maxDischargeCurrent, battery); + battery.getDischargeMaxCurrentChannel().nextProcessImage(); + battery.getForceChargeActiveChannel().nextProcessImage(); + + expectedCurrent = maxDischargeCurrent; + actualCurrent = battery.getDischargeMaxCurrent().get(); + assertEquals(expectedCurrent, actualCurrent); + + expectedForce = true; + actualForce = battery.getForceChargeActive().get(); + assertEquals(expectedForce, actualForce); + } + + + @Test + public void testIsVoltageLowerThanForceDischargeVoltage() { + + assertTrue(Util.isVoltageLowerThanForceDischargeVoltage(cellCharacteristic, battery)); + + battery.setMaximalCellVoltage((DummyCellCharacteristic.FORCE_DISCHARGE_CELL_VOLTAGE_MV - 1)); + assertTrue(Util.isVoltageLowerThanForceDischargeVoltage(cellCharacteristic, battery)); + + battery.setMaximalCellVoltage((DummyCellCharacteristic.FORCE_DISCHARGE_CELL_VOLTAGE_MV)); + assertFalse(Util.isVoltageLowerThanForceDischargeVoltage(cellCharacteristic, battery)); + + battery.setMaximalCellVoltage((DummyCellCharacteristic.FORCE_DISCHARGE_CELL_VOLTAGE_MV + 1)); + assertFalse(Util.isVoltageLowerThanForceDischargeVoltage(cellCharacteristic, battery)); + } + + @Test + public void testIsVoltageAboveFinalChargingVoltage() { + assertFalse(Util.isVoltageAboveFinalChargingVoltage(cellCharacteristic, battery)); + + battery.setMaximalCellVoltage((DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV - 1)); + assertFalse(Util.isVoltageAboveFinalChargingVoltage(cellCharacteristic, battery)); + + battery.setMaximalCellVoltage((DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV)); + assertFalse(Util.isVoltageAboveFinalChargingVoltage(cellCharacteristic, battery)); + + battery.setMaximalCellVoltage((DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV + 1)); + assertTrue(Util.isVoltageAboveFinalChargingVoltage(cellCharacteristic, battery)); + } + + @Test + public void testIsVoltageHigherThanForceChargeVoltage() { + assertTrue(Util.isVoltageHigherThanForceChargeVoltage(cellCharacteristic, battery)); + + battery.setMinimalCellVoltage((DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV - 1)); + assertFalse(Util.isVoltageHigherThanForceChargeVoltage(cellCharacteristic, battery)); + + battery.setMinimalCellVoltage((DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV)); + assertFalse(Util.isVoltageHigherThanForceChargeVoltage(cellCharacteristic, battery)); + + battery.setMinimalCellVoltage((DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV + 1)); + assertTrue(Util.isVoltageHigherThanForceChargeVoltage(cellCharacteristic, battery)); + } + + @Test + public void testIsVoltageBelowFinalDischargingVoltage() { + assertFalse(Util.isVoltageBelowFinalDischargingVoltage(cellCharacteristic, battery)); + + battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - 1); + assertTrue(Util.isVoltageBelowFinalDischargingVoltage(cellCharacteristic, battery)); + + battery.setMinimalCellVoltage((DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV)); + assertFalse(Util.isVoltageBelowFinalDischargingVoltage(cellCharacteristic, battery)); + + battery.setMinimalCellVoltage((DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV + 1)); + assertFalse(Util.isVoltageBelowFinalDischargingVoltage(cellCharacteristic, battery)); + } + + @Test + public void testIsFurtherDischargingNecessary() { + assertFalse(Util.isFurtherDischargingNecessary(cellCharacteristic, battery)); + + battery.setMaximalCellVoltage(DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV + 1); + assertFalse(Util.isFurtherDischargingNecessary(cellCharacteristic, battery)); + + battery.setMaximalCellVoltage(DummyCellCharacteristic.FORCE_DISCHARGE_CELL_VOLTAGE_MV + 1); + assertFalse(Util.isFurtherDischargingNecessary(cellCharacteristic, battery)); + + battery.setForceDischargeActive(false); + assertFalse(Util.isFurtherDischargingNecessary(cellCharacteristic, battery)); + + battery.setForceDischargeActive(true); + assertTrue(Util.isFurtherDischargingNecessary(cellCharacteristic, battery)); + + battery.setMaximalCellVoltage(DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV + 1); + assertTrue(Util.isFurtherDischargingNecessary(cellCharacteristic, battery)); + + battery.setMaximalCellVoltage(DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV); + assertFalse(Util.isFurtherDischargingNecessary(cellCharacteristic, battery)); + } + + @Test + public void testIsDischargingAlready() { + assertFalse(Util.isDischargingAlready(battery)); + + battery.setForceDischargeActive(true); + assertTrue(Util.isDischargingAlready(battery)); + + battery.setForceDischargeActive(false); + assertFalse(Util.isDischargingAlready(battery)); + } + + @Test + public void testCalculateForceCurrent() { + int expected = - (int) Math.max(1, DummyBattery.DEFAULT_CAPACITY * 0.02 / DummyBattery.DEFAULT_VOLTAGE); // 1.333 => 1 + assertEquals(expected, Util.calculateForceCurrent(battery)); + + int newCapacity = 200_000; + battery.setCapacity(newCapacity); + expected = - (int) Math.max(1, newCapacity * 0.02 / DummyBattery.DEFAULT_VOLTAGE); // 5.333 => 5 + assertEquals(expected, Util.calculateForceCurrent(battery)); + + int newVoltage = 850; + battery.setCapacity(newCapacity); + battery.setVoltage(newVoltage); + expected = - (int) Math.max(1, newCapacity * 0.02 / newVoltage); // 4.706 => 4 + assertEquals(expected, Util.calculateForceCurrent(battery)); + + newCapacity = 30_000; + newVoltage = 700; + battery.setCapacity(newCapacity); + battery.setVoltage(newVoltage); + expected = - (int) Math.max(1, newCapacity * 0.02 / newVoltage); // 0.857 => 1 + assertEquals(expected, Util.calculateForceCurrent(battery)); + + newCapacity = 10_000; + battery.setCapacity(newCapacity); + battery.setVoltage(newVoltage); + expected = - (int) Math.max(1, newCapacity * 0.02 / newVoltage); // 0.286 => 1 + assertEquals(expected, Util.calculateForceCurrent(battery)); + } + + + @Test + public void testCalculateForceDischargeCurrent() { + int expected = - (int) Math.max(1, DummyBattery.DEFAULT_CAPACITY * 0.02 / DummyBattery.DEFAULT_VOLTAGE); // 1.333 => 1 + assertEquals(expected, Util.calculateForceDischargeCurrent(battery)); + } + + @Test + public void testCalculateForceChargeCurrent() { + int expected = - (int) Math.max(1, DummyBattery.DEFAULT_CAPACITY * 0.02 / DummyBattery.DEFAULT_VOLTAGE); // 1.333 => 1 + assertEquals(expected, Util.calculateForceChargeCurrent(battery)); + } + + @Test + public void testIsFurtherChargingNecessary() { + assertFalse(Util.isFurtherChargingNecessary(cellCharacteristic, battery)); + + battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - 1); + assertFalse(Util.isFurtherChargingNecessary(cellCharacteristic, battery)); + + battery.setMinimalCellVoltage(DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV - 1); + assertFalse(Util.isFurtherChargingNecessary(cellCharacteristic, battery)); + + battery.setForceChargeActive(false); + assertFalse(Util.isFurtherChargingNecessary(cellCharacteristic, battery)); + + battery.setForceChargeActive(true); + assertTrue(Util.isFurtherChargingNecessary(cellCharacteristic, battery)); + + battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - 1); + assertTrue(Util.isFurtherChargingNecessary(cellCharacteristic, battery)); + + battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV); + assertFalse(Util.isFurtherChargingNecessary(cellCharacteristic, battery)); + } + + @Test + public void testIsChargingAlready() { + assertFalse(Util.isChargingAlready(battery)); + + battery.setForceChargeActive(true); + assertTrue(Util.isChargingAlready(battery)); + + battery.setForceChargeActive(false); + assertFalse(Util.isChargingAlready(battery)); + } + + @Test + public void testAreApiValuesPresent() { + assertTrue(Util.areApiValuesPresent(battery)); + + battery.setCapacityToUndefined(); + assertFalse(Util.areApiValuesPresent(battery)); + + battery.setCapacity(DummyBattery.DEFAULT_CAPACITY); + battery.setVoltageToUndefined(); + assertFalse(Util.areApiValuesPresent(battery)); + + battery.setVoltage(DummyBattery.DEFAULT_VOLTAGE); + battery.setMinimalCellVoltageToUndefined(); + assertFalse(Util.areApiValuesPresent(battery)); + + battery.setMinimalCellVoltage(DummyBattery.DEFAULT_MIN_CELL_VOLTAGE); + battery.setMaximalCellVoltageToUndefined(); + assertFalse(Util.areApiValuesPresent(battery)); + + battery.setMaximalCellVoltage(DummyBattery.DEFAULT_MAX_CELL_VOLTAGE); + assertTrue(Util.areApiValuesPresent(battery)); + } + +} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/TestController.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/TestController.java deleted file mode 100644 index a07e6e5f750..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/TestController.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.openems.edge.battery.soltaro.controller; - -import static org.junit.Assert.fail; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -//import io.openems.common.types.ChannelAddress; -import io.openems.edge.battery.soltaro.controller.helper.Creator; -import io.openems.edge.battery.soltaro.controller.helper.DummyComponentManager; -//import io.openems.edge.common.test.AbstractComponentTest.TestCase; -import io.openems.edge.controller.test.ControllerTest; -import io.openems.edge.ess.api.ManagedSymmetricEss; -import io.openems.edge.ess.test.DummyManagedSymmetricEss; - -public class TestController { - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - } - - @Before - public void setUp() throws Exception { - } - - @Test - public final void test() { - // TODO More tests and scenarios needed - // Initialize Controller - BatteryHandlingController controller = new BatteryHandlingController(); - // Add referenced services - DummyComponentManager componentManager = new DummyComponentManager(); - controller.componentManager = componentManager; - // Activate (twice, so that reference target is set) - Config config = Creator.createConfig(); - try { - controller.activate(null, config); - controller.activate(null, config); - // Prepare Channels -// ChannelAddress ctrl0MinCellVoltage = new ChannelAddress(Creator.ESS_ID, "MinCellVoltage"); -// ChannelAddress ctrl0State = new ChannelAddress(Creator.ID, "StateMachine"); - // Build and run test - ManagedSymmetricEss ess = new DummyManagedSymmetricEss(Creator.ESS_ID); - new ControllerTest(controller, componentManager, ess, controller) // -// .next(new TestCase() // -// .input(ctrl0MinCellVoltage, config.warningLowCellVoltage() - 1) // -// .output(ctrl0State, State.LIMIT.getValue())) // -// .next(new TestCase() // -// .input(ctrl0MinCellVoltage, config.criticalLowCellVoltage() - 1) // -// .output(ctrl0State, State.FORCE_CHARGE.getValue())) // - ; - } catch (Exception e) { - fail(e.getMessage()); - } - } -} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/TestStateController.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/TestStateController.java deleted file mode 100644 index 79c8bb8b09e..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/TestStateController.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.openems.edge.battery.soltaro.controller; - -import static org.junit.Assert.assertNotNull; - -import org.junit.Before; -import org.junit.Test; - -import io.openems.edge.battery.soltaro.controller.helper.Creator; -import io.openems.edge.battery.soltaro.controller.helper.DummyComponentManager; -import io.openems.edge.battery.soltaro.controller.state.StateController; -import io.openems.edge.common.component.ComponentManager; - -public class TestStateController { - - @Before - public void setUp() throws Exception { - Config c = Creator.createConfig(); - ComponentManager componentManager = new DummyComponentManager(); - StateController.init(componentManager, c); - } - - @Test - public final void test() { - - // after calling init for each state there should be a state object - - assertNotNull(StateController.getStateObject(State.CHECK)); - assertNotNull(StateController.getStateObject(State.FORCE_CHARGE)); - assertNotNull(StateController.getStateObject(State.FULL_CHARGE)); - assertNotNull(StateController.getStateObject(State.LIMIT)); - assertNotNull(StateController.getStateObject(State.NORMAL)); - assertNotNull(StateController.getStateObject(State.UNDEFINED)); - - } - -} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/Creator.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/Creator.java deleted file mode 100644 index 25db07583c2..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/Creator.java +++ /dev/null @@ -1,153 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.helper; - -import java.lang.annotation.Annotation; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.soltaro.controller.Config; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.battery.soltaro.controller.state.BaseState; - -public class Creator { - - public static final int CHARGE_POWER_PERCENT = 20; - public static final int CHARGING_TIME = 2; - public static final String ESS_ID = "ess0"; - public static final String BMS_ID = "bms0"; - public static final boolean ENABLED = true; - public static final int WARNING_LOW_CELL_VOLTAGE = 2900; - public static final int CRITICAL_LOW_CELL_VOLTAGE = 2800; - public static final int CRITICAL_HIGH_CELL_VOLTAGE = 3650; - - public static final int FORCE_CHARGE_REACHABLE_MIN_CELL_VOLTAGE = 3100; - - public static final int WARNING_SOC = 10; - public static final int CRITICAL_SOC = 5; - - public static final int DELTA_SOC = 5; - - public static final int LOW_TEMPERATURE = 0; - public static final int HIGH_TEMPERATURE = 60; - - public static final long UNUSED_TIME = 2; - - public static final String ID = "ctrl0"; - - public static BaseState createBaseState(DummyEss ess, DummyBattery bms) { - return new BaseState(ess, bms) { - @Override - public State getState() { - return null; - } - - @Override - public State getNextState() { - return null; - } - - @Override - public void act() throws OpenemsNamedException { - } - }; - } - - public static Config createConfig() { - - return new Config() { - - @Override - public Class annotationType() { - return null; - } - - @Override - public String webconsole_configurationFactory_nameHint() { - return null; - } - - @Override - public int warningLowCellVoltage() { - return WARNING_LOW_CELL_VOLTAGE; - } - - @Override - public String id() { - return ID; - } - - @Override - public String ess_id() { - return ESS_ID; - } - - @Override - public boolean enabled() { - return ENABLED; - } - - @Override - public int chargingTime() { - return CHARGING_TIME; - } - - @Override - public int chargePowerPercent() { - return CHARGE_POWER_PERCENT; - } - - @Override - public String alias() { - return null; - } - - @Override - public int criticalLowCellVoltage() { - return CRITICAL_LOW_CELL_VOLTAGE; - } - - @Override - public int criticalHighCellVoltage() { - return CRITICAL_HIGH_CELL_VOLTAGE; - } - - @Override - public int warningSoC() { - return WARNING_SOC; - } - - @Override - public int criticalSoC() { - return CRITICAL_SOC; - } - - @Override - public int deltaSoC() { - return DELTA_SOC; - } - - @Override - public int lowTemperature() { - return LOW_TEMPERATURE; - } - - @Override - public int highTemperature() { - return HIGH_TEMPERATURE; - } - - @Override - public long unusedTime() { - return UNUSED_TIME; - } - - @Override - public int forceChargeReachableMinCellVoltage() { - return FORCE_CHARGE_REACHABLE_MIN_CELL_VOLTAGE; - } - - @Override - public String bms_id() { - return BMS_ID; - } - }; - } -} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/DummyComponentManager.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/DummyComponentManager.java deleted file mode 100644 index f1a567a0bc1..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/DummyComponentManager.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.helper; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.api.Battery; -import io.openems.edge.common.component.ComponentManager; -import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.ess.api.ManagedSymmetricEss; -import io.openems.edge.ess.api.SymmetricEss; - -public class DummyComponentManager extends io.openems.edge.common.test.DummyComponentManager - implements ComponentManager { - - private ManagedSymmetricEss ess = createEss(); - private Battery bms = createBms(); - - @SuppressWarnings("unchecked") - @Override - public T getComponent(String componentId) throws OpenemsNamedException { - if (Creator.ESS_ID.equals(componentId)) { - return (T) ess; - } - if (Creator.BMS_ID.equals(componentId)) { - return (T) bms; - } - return null; - } - - private Battery createBms() { - return new DummyBattery(); - } - - private ManagedSymmetricEss createEss() { - - return new DummyEss(OpenemsComponent.ChannelId.values(), // - SymmetricEss.ChannelId.values(), // - ManagedSymmetricEss.ChannelId.values() // ; - ); - } - - public void destroyEss() { - this.ess = null; - } - - public void initEss() { - this.ess = createEss(); - } - - public void destroyBms() { - this.bms = null; - } - - public void initBms() { - this.bms = createBms(); - } - -} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/DummyEss.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/DummyEss.java deleted file mode 100644 index 84cdb1183a1..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/helper/DummyEss.java +++ /dev/null @@ -1,114 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.helper; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.edge.common.component.AbstractOpenemsComponent; -import io.openems.edge.common.filter.PidFilter; -import io.openems.edge.ess.api.ManagedSymmetricEss; -import io.openems.edge.ess.power.api.Coefficient; -import io.openems.edge.ess.power.api.Constraint; -import io.openems.edge.ess.power.api.LinearCoefficient; -import io.openems.edge.ess.power.api.Phase; -import io.openems.edge.ess.power.api.Power; -import io.openems.edge.ess.power.api.Pwr; -import io.openems.edge.ess.power.api.Relationship; - -public class DummyEss extends AbstractOpenemsComponent implements ManagedSymmetricEss { - - public static int MAXIMUM_POWER = 10000; - private int currentActivePower = 0; - - protected DummyEss(// - io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, // - io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds // - ) { // - super(firstInitialChannelIds, furtherInitialChannelIds); - - setCurrentActivePower(0); - } - - public int getCurrentActivePower() { - return currentActivePower; - } - - public void setCurrentActivePower(int power) { - currentActivePower = power; - this._setActivePower(power); - this.getActivePowerChannel().nextProcessImage(); - } - - @Override - public Power getPower() { - - return new Power() { - - @Override - public void removeConstraint(Constraint constraint) { - } - - @Override - public int getMinPower(ManagedSymmetricEss ess, Phase phase, Pwr pwr) { - return (-1) * MAXIMUM_POWER; - } - - @Override - public int getMaxPower(ManagedSymmetricEss ess, Phase phase, Pwr pwr) { - return MAXIMUM_POWER; - } - - @Override - public Coefficient getCoefficient(ManagedSymmetricEss ess, Phase phase, Pwr pwr) throws OpenemsException { - return null; - } - - @Override - public Constraint createSimpleConstraint(String description, ManagedSymmetricEss ess, Phase phase, Pwr pwr, - Relationship relationship, double value) throws OpenemsException { - Coefficient coefficient = new Coefficient(0, ess.id(), phase, pwr); - LinearCoefficient lc = new LinearCoefficient(coefficient, value); - LinearCoefficient[] coefficients = { lc }; - return new Constraint(description, coefficients, relationship, value); - } - - @Override - public Constraint addConstraintAndValidate(Constraint constraint) throws OpenemsException { - return addConstraint(constraint); - } - - @Override - public Constraint addConstraint(Constraint constraint) { - switch (constraint.getRelationship()) { - case EQUALS: - currentActivePower = constraint.getValue().get().intValue(); - break; - case GREATER_OR_EQUALS: - currentActivePower = Math.max(currentActivePower, constraint.getValue().get().intValue()); - break; - case LESS_OR_EQUALS: - currentActivePower = Math.min(currentActivePower, constraint.getValue().get().intValue()); - break; - default: - break; - - } - return constraint; - } - - @Override - public PidFilter getPidFilter() { - // TODO Auto-generated method stub - return null; - } - }; - } - - @Override - public void applyPower(int activePower, int reactivePower) throws OpenemsNamedException { - this.currentActivePower = activePower; - } - - @Override - public int getPowerPrecision() { - return 1; - } -} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestBaseState.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestBaseState.java deleted file mode 100644 index 6c2df8b54f6..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestBaseState.java +++ /dev/null @@ -1,129 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import io.openems.edge.battery.soltaro.controller.helper.Creator; -import io.openems.edge.battery.soltaro.controller.helper.DummyBattery; -import io.openems.edge.battery.soltaro.controller.helper.DummyComponentManager; -import io.openems.edge.battery.soltaro.controller.helper.DummyEss; - -public class TestBaseState { - - private BaseState sut; - private static DummyComponentManager componentManager; - private DummyEss ess; - private DummyBattery bms; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - componentManager = new DummyComponentManager(); - } - - @Before - public void setUp() throws Exception { - // Always create ess newly to have an ess in "normal" situation that does - // nothing - componentManager.initEss(); - ess = componentManager.getComponent(Creator.ESS_ID); - bms = componentManager.getComponent(Creator.BMS_ID); - sut = Creator.createBaseState(ess, bms); - } - - @Test - public final void testBaseState() { - assertNotNull(sut.getEss()); - } - - @Test - public final void testDenyCharge() { - ((DummyEss) sut.getEss()).setCurrentActivePower((-1 * DummyEss.MAXIMUM_POWER)); - sut.denyCharge(); - assertTrue(((DummyEss) sut.getEss()).getCurrentActivePower() >= 0); - } - - @Test - public final void testDenyDischarge() { - ((DummyEss) sut.getEss()).setCurrentActivePower(DummyEss.MAXIMUM_POWER); - sut.denyDischarge(); - assertTrue(((DummyEss) sut.getEss()).getCurrentActivePower() <= 0); - } - - @Test - public final void testChargeEssWithPercentOfMaxPower() { - int percent = 20; - sut.chargeEssWithPercentOfMaxPower(percent); - assertEquals(percent * DummyEss.MAXIMUM_POWER * (-1) / 100, ((DummyEss) sut.getEss()).getCurrentActivePower()); - } - - @Test - public final void testIsNextStateUndefined() { - assertFalse(sut.isNextStateUndefined()); - - bms.setMaximalCellTemperatureToUndefined(); - assertTrue(sut.isNextStateUndefined()); - - bms.setMaximalCellTemperature(DummyBattery.DEFAULT_MAX_CELL_TEMPERATURE); - assertFalse(sut.isNextStateUndefined()); - - bms.setMinimalCellTemperatureToUndefined(); - assertTrue(sut.isNextStateUndefined()); - - bms.setMinimalCellTemperature(DummyBattery.DEFAULT_MIN_CELL_TEMPERATURE); - assertFalse(sut.isNextStateUndefined()); - - bms.setMaximalCellVoltageToUndefined(); - assertTrue(sut.isNextStateUndefined()); - - bms.setMaximalCellVoltage(DummyBattery.DEFAULT_MAX_CELL_VOLTAGE); - assertFalse(sut.isNextStateUndefined()); - - bms.setMinimalCellVoltageToUndefined(); - assertTrue(sut.isNextStateUndefined()); - - bms.setMinimalCellVoltage(DummyBattery.DEFAULT_MIN_CELL_VOLTAGE); - assertFalse(sut.isNextStateUndefined()); - - bms.setSocToUndefined(); - assertTrue(sut.isNextStateUndefined()); - - bms.setSoc(DummyBattery.DEFAULT_SOC); - assertFalse(sut.isNextStateUndefined()); - - sut = Creator.createBaseState(null, null); - assertTrue(sut.isNextStateUndefined()); - - } - - @Test - public final void testGetBmsSoC() { - assertEquals(DummyBattery.DEFAULT_SOC, sut.getBmsSoC()); - } - - @Test - public final void testGetBmsMinCellTemperature() { - assertEquals(DummyBattery.DEFAULT_MIN_CELL_TEMPERATURE, sut.getBmsMinCellTemperature()); - } - - @Test - public final void testGetBmsMaxCellTemperature() { - assertEquals(DummyBattery.DEFAULT_MAX_CELL_TEMPERATURE, sut.getBmsMaxCellTemperature()); - } - - @Test - public final void testGetBmsMinCellVoltage() { - assertEquals(DummyBattery.DEFAULT_MIN_CELL_VOLTAGE, sut.getBmsMinCellVoltage()); - } - - @Test - public final void testGetBmsMaxCellVoltage() { - assertEquals(DummyBattery.DEFAULT_MAX_CELL_VOLTAGE, sut.getBmsMaxCellVoltage()); - } - -} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestCheck.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestCheck.java deleted file mode 100644 index 0cad077fc6c..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestCheck.java +++ /dev/null @@ -1,137 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.soltaro.controller.Config; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.battery.soltaro.controller.helper.Creator; -import io.openems.edge.battery.soltaro.controller.helper.DummyBattery; -import io.openems.edge.battery.soltaro.controller.helper.DummyComponentManager; -import io.openems.edge.battery.soltaro.controller.helper.DummyEss; - -public class TestCheck { - - private IState sut; - private static DummyComponentManager componentManager; - private static Config config; - private DummyEss ess; - private DummyBattery bms; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - config = Creator.createConfig(); - componentManager = new DummyComponentManager(); - } - - @Before - public void setUp() throws Exception { - // Always create ess newly to have an ess in "normal" situation that does - // nothing - componentManager.initEss(); - ess = componentManager.getComponent(Creator.ESS_ID); - componentManager.destroyBms(); - componentManager.initBms(); - bms = componentManager.getComponent(Creator.BMS_ID); - sut = new Check(ess, bms, config.deltaSoC(), config.unusedTime(), config.criticalLowCellVoltage()); - } - - @Test - public final void testGetState() { - assertEquals(sut.getState(), State.CHECK); - } - - @Test - public final void testGetNextStateNoChanges() { - State next = sut.getNextState(); - assertEquals(State.CHECK, next); - } - - @Test - public final void testGetNextStateUndefined() { - bms.setSocToUndefined(); - State next = sut.getNextState(); - assertEquals(State.UNDEFINED, next); - } - - @Test - public final void testGetNextStateNormal() { - State next = sut.getNextState(); - assertEquals(State.CHECK, next); - - bms.setSoc(bms.getSoc().get() + config.deltaSoC() + 1); // FIXME this will throw a NullPointerException! - next = sut.getNextState(); - assertEquals(State.NORMAL, next); - } - - @Test - public final void testGetNextStateForceCharge() { - bms.setMinimalCellVoltage(config.criticalLowCellVoltage() - 1); - State next = sut.getNextState(); - assertEquals(State.FORCE_CHARGE, next); - } - -// @Test -// public final void testGetNextStateFullCharge() { -// -// //TODO how do i tell the bms that there was action ?! -// // we find it out if there was no ChargeIndication for the last 2 weeks in the soltaro bms -// //Wie ich Zeitdaten reinbekomm esehe ich in sum.impl --> TimeData Service und ich sollte mir einen Channel schreiben für "NotActiveSince" -// -// -// // writing two times causes past values in the channel -// bms.setChargeIndication(1); -// bms.setChargeIndication(1); -// -// -// State next = sut.getNextState(); -// assertEquals(State.CHECK, next); -// -// try { -// Thread.sleep(1000 * config.unusedTime() + 500); -// } catch (InterruptedException e) { -// fail(); -// } -// -// bms.setChargeIndication(0); -// bms.setChargeIndication(0); -// -// //Waiting long enough means that the last charge or discharge action is too long away -// next = sut.getNextState(); -// assertEquals(State.FULL_CHARGE, next); -// } - - @Test - public final void testActAllowCharging() { - int power = -2000; - ess.setCurrentActivePower(power); - try { - sut.act(); - } catch (OpenemsNamedException e) { - fail(); - } - int expected = power; - int actual = ess.getCurrentActivePower(); - assertEquals(expected, actual); - } - - @Test - public final void testActDenyDischarging() { - int power = 2000; - ess.setCurrentActivePower(power); - try { - sut.act(); - } catch (OpenemsNamedException e) { - fail(); - } - int expected = 0; - int actual = ess.getCurrentActivePower(); - assertEquals(expected, actual); - } -} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestForceCharge.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestForceCharge.java deleted file mode 100644 index 2ff7509e8e1..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestForceCharge.java +++ /dev/null @@ -1,111 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.soltaro.controller.Config; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.battery.soltaro.controller.helper.Creator; -import io.openems.edge.battery.soltaro.controller.helper.DummyBattery; -import io.openems.edge.battery.soltaro.controller.helper.DummyComponentManager; -import io.openems.edge.battery.soltaro.controller.helper.DummyEss; - -public class TestForceCharge { - - private IState sut; - private static DummyComponentManager componentManager; - private static Config config; - private DummyEss ess; - private DummyBattery bms; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - config = Creator.createConfig(); - componentManager = new DummyComponentManager(); - } - - @Before - public void setUp() throws Exception { - // Always create ess newly to have an ess in "normal" situation - // This ess has a min cell voltage below the limit, and no active power - componentManager.initEss(); - ess = componentManager.getComponent(Creator.ESS_ID); - componentManager.initBms(); - bms = componentManager.getComponent(Creator.BMS_ID); - bms.setMinimalCellVoltage(config.criticalLowCellVoltage() - 1); - sut = new ForceCharge(ess, bms, config.chargePowerPercent(), config.chargingTime(), - config.forceChargeReachableMinCellVoltage()); - } - - @Test - public final void testGetState() { - assertEquals(sut.getState(), State.FORCE_CHARGE); - } - - @Test - public final void testGetNextStateNoChanges() { - State next = sut.getNextState(); - assertEquals(State.FORCE_CHARGE, next); - } - - @Test - public final void testGetNextStateCheckAfterWaitingPeriod() { - State next = sut.getNextState(); - assertEquals(State.FORCE_CHARGE, next); - - // Wait the defined time, then the next state should always be CHECK - try { - Thread.sleep(TestForceCharge.config.chargingTime() * 1000 + 500); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - next = sut.getNextState(); - assertEquals(State.CHECK, next); - } - - @Test - public final void testGetNextStateCheckAfterReachingMinCellLimit() { - State next = sut.getNextState(); - assertEquals(State.FORCE_CHARGE, next); - - bms.setMinimalCellVoltage(config.forceChargeReachableMinCellVoltage() + 1); - - next = sut.getNextState(); - assertEquals(State.CHECK, next); - } - - @Test - public final void testGetNextStateObjectUndefined() { - bms.setSocToUndefined(); - assertEquals(State.UNDEFINED, sut.getNextState()); - } - - @Test - public final void testAct() { - // After executing the act() function the channel SetActivePowerLessOrEquals - // should have a value in the nextWriteValue - try { - sut.act(); - } catch (OpenemsNamedException e) { - fail(e.getMessage()); - } - - int actual = ess.getSetActivePowerLessOrEqualsChannel().getNextWriteValue().get(); - - // According to the dummy config 20% of -10000 (neg. values for charge are - // expected) - int expected = -1 * DummyEss.MAXIMUM_POWER * config.chargePowerPercent() / 100; - assertEquals(expected, actual); - - actual = ess.getCurrentActivePower(); - - assertEquals(expected, actual); - } -} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestFullCharge.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestFullCharge.java deleted file mode 100644 index 3f0aca4945a..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestFullCharge.java +++ /dev/null @@ -1,114 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import io.openems.edge.battery.soltaro.controller.Config; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.battery.soltaro.controller.helper.Creator; -import io.openems.edge.battery.soltaro.controller.helper.DummyBattery; -import io.openems.edge.battery.soltaro.controller.helper.DummyComponentManager; -import io.openems.edge.battery.soltaro.controller.helper.DummyEss; - -public class TestFullCharge { - - private IState sut; - private static DummyComponentManager componentManager; - private static Config config; - private DummyEss ess; - private DummyBattery bms; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - config = Creator.createConfig(); - componentManager = new DummyComponentManager(); - } - - @Before - public void setUp() throws Exception { - // Always create ess newly to have an ess in "normal" situation that does - // nothing - componentManager.initEss(); - ess = componentManager.getComponent(Creator.ESS_ID); - componentManager.initBms(); - bms = componentManager.getComponent(Creator.BMS_ID); - sut = new FullCharge(ess, bms, config.criticalHighCellVoltage()); - } - - @Test - public final void testGetState() { - assertEquals(State.FULL_CHARGE, sut.getState()); - } - - @Test - public final void testGetNextStateUndefinedSoCUndefined() { - bms.setSocToUndefined(); - State nextState = sut.getNextState(); - assertEquals(State.UNDEFINED, nextState); - - bms.setSoc(0); - nextState = sut.getNextState(); - assertEquals(State.FULL_CHARGE, nextState); - } - - @Test - public final void testGetNextStateUndefinedMaxCellVoltageUndefined() { - bms.setMaximalCellVoltageToUndefined(); - State nextState = sut.getNextState(); - assertEquals(State.UNDEFINED, nextState); - - bms.setMaximalCellVoltage(0); - nextState = sut.getNextState(); - assertEquals(State.FULL_CHARGE, nextState); - } - - @Test - public final void testGetNextStateNormalCriticalVoltageReached() { - bms.setMaximalCellVoltage(config.criticalHighCellVoltage()); - State nextState = sut.getNextState(); - assertEquals(State.NORMAL, nextState); - } - - @Test - public final void testGetNextStateNormalCriticalVoltageExceeded() { - bms.setMaximalCellVoltage(config.criticalHighCellVoltage() + 1); - State nextState = sut.getNextState(); - assertEquals(State.NORMAL, nextState); - } - - @Test - public final void testGetNextStateFullChargeNothingChanged() { - // If values are defined and max cell voltage is not above critical value state - // should remain in full charge - State nextState = sut.getNextState(); - assertEquals(State.FULL_CHARGE, nextState); - } - - @Test - public final void testGetNextStateFullChargeMinVoltageChanged() { - // If values are defined and max cell voltage has not reached critical value - // state should remain in full charge - // Other values are not interesting - bms.setMinimalCellVoltage(DummyBattery.DEFAULT_MIN_CELL_VOLTAGE - 1); - State nextState = sut.getNextState(); - assertEquals(State.FULL_CHARGE, nextState); - } - - @Test - public final void testAct() { - try { - // ess should charge - sut.act(); - int activePower = ess.getCurrentActivePower(); - assertTrue(activePower < 0); - } catch (Exception e) { - fail(); - } - } -} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestLimit.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestLimit.java deleted file mode 100644 index 5ad1e3bfc17..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestLimit.java +++ /dev/null @@ -1,264 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.soltaro.controller.Config; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.battery.soltaro.controller.helper.Creator; -import io.openems.edge.battery.soltaro.controller.helper.DummyBattery; -import io.openems.edge.battery.soltaro.controller.helper.DummyComponentManager; -import io.openems.edge.battery.soltaro.controller.helper.DummyEss; - -public class TestLimit { - - private IState sut; - private static DummyComponentManager componentManager; - private static Config config; - private DummyEss ess; - private DummyBattery bms; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - config = Creator.createConfig(); - componentManager = new DummyComponentManager(); - } - - @Before - public void setUp() throws Exception { - // Always create ess newly to have an ess in "normal" situation that does - // nothing - componentManager.initEss(); - ess = componentManager.getComponent(Creator.ESS_ID); - componentManager.destroyBms(); - componentManager.initBms(); - bms = componentManager.getComponent(Creator.BMS_ID); - sut = new Limit(ess, bms, config.warningLowCellVoltage(), config.criticalLowCellVoltage(), - config.criticalHighCellVoltage(), config.warningSoC(), config.lowTemperature(), - config.highTemperature(), config.unusedTime()); - } - - @Test - public final void testGetState() { - assertEquals(State.LIMIT, sut.getState()); - } - - @Test - public final void testGetNextStateForceCharge() { - bms.setMinimalCellVoltage(config.criticalLowCellVoltage() - 1); - assertEquals(State.FORCE_CHARGE, sut.getNextState()); - } - -// @Test -// public final void testGetNextStateFullCharge() { -// // writing two times causes past values in the channel -// bms.setChargeIndication(0); -// bms.setChargeIndication(0); -// -// State next = sut.getNextState(); -// assertEquals(State.FULL_CHARGE, next); -// -// try { -// Thread.sleep(1000 * config.unusedTime() + 500); -// } catch (InterruptedException e) { -// fail(); -// } -// -// // Waiting long enough means that the last charge or discharge action is too -// // long away -// bms.setMinimalCellVoltage(config.warningLowCellVoltage() - 1); -// next = sut.getNextState(); -// assertEquals(State.LIMIT, next); -// } - - @Test - public final void testGetNextStateNormal() { - assertEquals(State.NORMAL, sut.getNextState()); - } - - @Test - public final void testGetNextStateUndefined() { - bms.setSocToUndefined(); - State next = sut.getNextState(); - assertEquals(State.UNDEFINED, next); - } - - @Test - public final void testGetNextStateLimitMinCellVoltage() { - bms.setMinimalCellVoltage(config.warningLowCellVoltage() - 1); - assertEquals(State.LIMIT, sut.getNextState()); - - bms.setMinimalCellVoltage(config.warningLowCellVoltage()); - assertEquals(State.LIMIT, sut.getNextState()); - - bms.setMinimalCellVoltage(config.warningLowCellVoltage() + 1); - assertEquals(State.NORMAL, sut.getNextState()); - } - - @Test - public final void testGetNextStateLimitMaxCellVoltage() { - bms.setMaximalCellVoltage(config.criticalHighCellVoltage() + 1); - assertEquals(State.LIMIT, sut.getNextState()); - - bms.setMaximalCellVoltage(config.criticalHighCellVoltage()); - assertEquals(State.LIMIT, sut.getNextState()); - - bms.setMaximalCellVoltage(config.criticalHighCellVoltage() - 1); - assertEquals(State.NORMAL, sut.getNextState()); - } - - @Test - public final void testGetNextStateLimitMinCellTemperature() { - bms.setMinimalCellTemperature(config.lowTemperature() - 1); - assertEquals(State.LIMIT, sut.getNextState()); - - bms.setMinimalCellTemperature(config.lowTemperature()); - assertEquals(State.LIMIT, sut.getNextState()); - - bms.setMinimalCellTemperature(config.lowTemperature() + 1); - assertEquals(State.NORMAL, sut.getNextState()); - } - - @Test - public final void testGetNextStateLimitMaxCellTemperature() { - bms.setMaximalCellTemperature(config.highTemperature() + 1); - assertEquals(State.LIMIT, sut.getNextState()); - - bms.setMaximalCellTemperature(config.highTemperature()); - assertEquals(State.LIMIT, sut.getNextState()); - - bms.setMaximalCellTemperature(config.highTemperature() - 1); - assertEquals(State.NORMAL, sut.getNextState()); - } - - @Test - public final void testGetNextStateLimitSoc() { - bms.setSoc(config.warningSoC() - 1); - assertEquals(State.LIMIT, sut.getNextState()); - - bms.setSoc(config.warningSoC()); - assertEquals(State.LIMIT, sut.getNextState()); - - bms.setSoc(config.warningSoC() + 1); - assertEquals(State.NORMAL, sut.getNextState()); - } - - @Test - public final void testDenyDischargingLowCellVoltage() { - int power = 1000; - ess.setCurrentActivePower(power); - bms.setMinimalCellVoltage(config.warningLowCellVoltage()); - - assertEquals(power, ess.getCurrentActivePower()); - try { - sut.act(); - } catch (OpenemsNamedException e) { - fail(e.getMessage()); - } - - assertTrue(ess.getCurrentActivePower() <= 0); - } - - @Test - public final void testDenyDischargingLowSoc() { - int power = 1000; - ess.setCurrentActivePower(power); - bms.setSoc(config.warningSoC()); - - assertEquals(power, ess.getCurrentActivePower()); - try { - sut.act(); - } catch (OpenemsNamedException e) { - fail(e.getMessage()); - } - - assertTrue(ess.getCurrentActivePower() <= 0); - } - - @Test - public final void testDenyChargingHighCellVoltage() { - int power = -1000; - ess.setCurrentActivePower(power); - bms.setMaximalCellVoltage(config.criticalHighCellVoltage()); - - assertEquals(power, ess.getCurrentActivePower()); - try { - sut.act(); - } catch (OpenemsNamedException e) { - fail(e.getMessage()); - } - - assertTrue(ess.getCurrentActivePower() >= 0); - } - - @Test - public final void testDenyChargingLowTemperature() { - int power = -1000; - ess.setCurrentActivePower(power); - bms.setMinimalCellTemperature(config.lowTemperature()); - - assertEquals(power, ess.getCurrentActivePower()); - try { - sut.act(); - } catch (OpenemsNamedException e) { - fail(e.getMessage()); - } - - assertTrue(ess.getCurrentActivePower() == 0); - } - - @Test - public final void testDenyDischargingLowTemperature() { - int power = 1000; - ess.setCurrentActivePower(power); - bms.setMinimalCellTemperature(config.lowTemperature()); - - assertEquals(power, ess.getCurrentActivePower()); - try { - sut.act(); - } catch (OpenemsNamedException e) { - fail(e.getMessage()); - } - - assertTrue(ess.getCurrentActivePower() == 0); - } - - @Test - public final void testDenyChargingHighTemperature() { - int power = -1000; - ess.setCurrentActivePower(power); - bms.setMaximalCellTemperature(config.highTemperature()); - - assertEquals(power, ess.getCurrentActivePower()); - try { - sut.act(); - } catch (OpenemsNamedException e) { - fail(e.getMessage()); - } - - assertTrue(ess.getCurrentActivePower() == 0); - } - - @Test - public final void testDenyDischargingHighTemperature() { - int power = 1000; - ess.setCurrentActivePower(power); - bms.setMaximalCellTemperature(config.highTemperature()); - - assertEquals(power, ess.getCurrentActivePower()); - try { - sut.act(); - } catch (OpenemsNamedException e) { - fail(e.getMessage()); - } - - assertTrue(ess.getCurrentActivePower() == 0); - } -} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestNormal.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestNormal.java deleted file mode 100644 index c2934279425..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestNormal.java +++ /dev/null @@ -1,197 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import io.openems.edge.battery.soltaro.controller.Config; -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.battery.soltaro.controller.helper.Creator; -import io.openems.edge.battery.soltaro.controller.helper.DummyBattery; -import io.openems.edge.battery.soltaro.controller.helper.DummyComponentManager; -import io.openems.edge.battery.soltaro.controller.helper.DummyEss; - -public class TestNormal { - - private IState sut; - private static DummyComponentManager componentManager; - private static Config config; - private DummyEss ess; - private DummyBattery bms; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - config = Creator.createConfig(); - componentManager = new DummyComponentManager(); - } - - @Before - public void setUp() throws Exception { - // Always create ess and bms newly to have them in "normal" situation that does - // nothing - componentManager.initEss(); - ess = componentManager.getComponent(Creator.ESS_ID); - componentManager.initBms(); - bms = componentManager.getComponent(Creator.BMS_ID); - sut = new Normal(ess, bms, config.warningLowCellVoltage(), config.criticalHighCellVoltage(), - config.warningSoC(), config.lowTemperature(), config.highTemperature(), config.unusedTime()); - } - - @Test - public final void testGetState() { - assertEquals(sut.getState(), State.NORMAL); - } - - @Test - public final void testGetNextStateWithNoChanges() { - State next = sut.getNextState(); - assertEquals(State.NORMAL, next); - } - - @Test - public final void testGetNextStateNormalNoChargingValuesPresent() { - // writing two times causes past values in the channel - - State next = sut.getNextState(); - assertEquals(State.NORMAL, next); - - try { - Thread.sleep(1000 * config.unusedTime() + 500); - } catch (InterruptedException e) { - fail(); - } - - // Waiting long enough means that the last charge or discharge action is too - // long away, but there are no values, so state should be normal - next = sut.getNextState(); - assertEquals(State.NORMAL, next); - } - - @Test - public final void testGetNextStateNormalNoChargingValuePresent() { - // writing two times causes past values in the channel - - State next = sut.getNextState(); - assertEquals(State.NORMAL, next); - - try { - Thread.sleep(1000 * config.unusedTime() + 500); - } catch (InterruptedException e) { - fail(); - } - - // Waiting long enough means that the last charge or discharge action is too - // long away, but there are no values, so state should be normal - next = sut.getNextState(); - assertEquals(State.NORMAL, next); - } - -// @Test -// public final void testGetNextStateFullCharge() { -// // writing two times causes past values in the channel -// bms.setChargeIndication(1); -// bms.setChargeIndication(1); -// -// State next = sut.getNextState(); -// assertEquals(State.NORMAL, next); -// -// try { -// Thread.sleep(1000 * config.unusedTime() + 500); -// } catch (InterruptedException e) { -// fail(); -// } -// -// bms.setChargeIndication(0); -// bms.setChargeIndication(0); -// -// // Waiting long enough means that the last charge or discharge action is too -// // long away, but there are no values, so state should be normal -// next = sut.getNextState(); -// assertEquals(State.FULL_CHARGE, next); -// } - - @Test - public final void testGetNextStateUndefinedNoVoltage() { - bms.setMinimalCellVoltageToUndefined(); - State next = sut.getNextState(); - assertEquals(State.UNDEFINED, next); - } - - @Test - public final void testGetNextStateLimitLowCellVoltage() { - bms.setMinimalCellVoltage(config.warningLowCellVoltage() - 1); - State next = sut.getNextState(); - assertEquals(State.LIMIT, next); - - bms.setMinimalCellVoltage(config.warningLowCellVoltage()); - next = sut.getNextState(); - assertEquals(State.NORMAL, next); - } - - @Test - public final void testGetNextStateLimitHighCellVoltage() { - bms.setMaximalCellVoltage(config.criticalHighCellVoltage() + 1); - State next = sut.getNextState(); - assertEquals(State.LIMIT, next); - - bms.setMaximalCellVoltage(config.criticalHighCellVoltage()); - next = sut.getNextState(); - assertEquals(State.NORMAL, next); - } - - @Test - public final void testGetNextStateLimitLowCellTemperature() { - bms.setMinimalCellTemperature(config.lowTemperature() - 1); - State next = sut.getNextState(); - assertEquals(State.LIMIT, next); - - bms.setMinimalCellTemperature(config.lowTemperature()); - next = sut.getNextState(); - assertEquals(State.NORMAL, next); - } - - @Test - public final void testGetNextStateLimitHighCellTemperature() { - bms.setMaximalCellTemperature(config.highTemperature() + 1); - State next = sut.getNextState(); - assertEquals(State.LIMIT, next); - - bms.setMaximalCellTemperature(config.highTemperature()); - next = sut.getNextState(); - assertEquals(State.NORMAL, next); - } - - @Test - public final void testGetNextStateLimitSoc() { - bms.setSoc(config.warningSoC() - 1); - State next = sut.getNextState(); - assertEquals(State.LIMIT, next); - - bms.setSoc(config.warningSoC()); - next = sut.getNextState(); - assertEquals(State.NORMAL, next); - } - - @Test - public final void testAct() { - // act should have no interference on ess - try { - int power = 1000; - ess.setCurrentActivePower(power); - sut.act(); - assertEquals(power, ess.getCurrentActivePower()); - - power = -1000; - ess.setCurrentActivePower(power); - sut.act(); - assertEquals(power, ess.getCurrentActivePower()); - } catch (Exception e) { - fail(); - } - } - -} diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestUndefinedState.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestUndefinedState.java deleted file mode 100644 index a9cbcd941a2..00000000000 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/controller/state/TestUndefinedState.java +++ /dev/null @@ -1,87 +0,0 @@ -package io.openems.edge.battery.soltaro.controller.state; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.fail; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import io.openems.edge.battery.soltaro.controller.IState; -import io.openems.edge.battery.soltaro.controller.State; -import io.openems.edge.battery.soltaro.controller.helper.Creator; -import io.openems.edge.battery.soltaro.controller.helper.DummyBattery; -import io.openems.edge.battery.soltaro.controller.helper.DummyComponentManager; -import io.openems.edge.battery.soltaro.controller.helper.DummyEss; - -public class TestUndefinedState { - - private IState sut; - private static DummyComponentManager componentManager; - private DummyEss ess; - private DummyBattery bms; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - componentManager = new DummyComponentManager(); - } - - @Before - public void setUp() throws Exception { - // Always create ess newly to have an ess in "normal" situation that does - // nothing - componentManager.initEss(); - ess = componentManager.getComponent(Creator.ESS_ID); - bms = componentManager.getComponent(Creator.BMS_ID); - sut = new Undefined(ess, bms); - } - - @Test - public final void testGetState() { - assertEquals(State.UNDEFINED, sut.getState()); - } - - @Test - public final void testGetNextStateUndefinedSoc() { - assertNotEquals(State.UNDEFINED, sut.getNextState()); - - bms.setSocToUndefined(); - State nextState = sut.getNextState(); - assertEquals(State.UNDEFINED, nextState); - - bms.setSoc(0); - nextState = sut.getNextState(); - assertNotEquals(State.UNDEFINED, nextState); - assertEquals(State.NORMAL, nextState); - } - - @Test - public final void testGetNextStateUndefinedMinCell() { - assertNotEquals(State.UNDEFINED, sut.getNextState()); - - bms.setMinimalCellVoltageToUndefined(); - State nextState = sut.getNextState(); - assertEquals(State.UNDEFINED, nextState); - - bms.setMinimalCellVoltage(0); - nextState = sut.getNextState(); - assertNotEquals(State.UNDEFINED, nextState); - assertEquals(State.NORMAL, nextState); - } - - @Test - public final void testGetNextStateNormal() { - State nextState = sut.getNextState(); - assertEquals(State.NORMAL, nextState); - } - - @Test - public final void testAct() { - try { - sut.act(); - } catch (Exception e) { - fail(); - } - } -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/test/ManagedSymmetricEssTest.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/test/ManagedSymmetricEssTest.java index d9167068f9a..229a3b0f4d8 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/test/ManagedSymmetricEssTest.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/test/ManagedSymmetricEssTest.java @@ -1,7 +1,5 @@ package io.openems.edge.ess.test; -import java.util.Optional; - import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.test.AbstractComponentTest; import io.openems.edge.ess.api.ManagedSymmetricEss; @@ -18,10 +16,20 @@ public ManagedSymmetricEssTest(ManagedSymmetricEss sut) { @Override protected void onBeforeWrite() throws OpenemsNamedException { ManagedSymmetricEss ess = this.getSut(); - Optional activePower = ess.getSetActivePowerEqualsChannel().getNextWriteValueAndReset(); - Optional reactivePower = ess.getSetReactivePowerEqualsChannel().getNextWriteValueAndReset(); + int activePower = ess.getSetActivePowerEqualsChannel().getNextWriteValueAndReset().orElse(0); + int reactivePower = ess.getSetReactivePowerEqualsChannel().getNextWriteValueAndReset().orElse(0); + + int allowedChargePower = ess.getAllowedChargePower().orElse(0); + if (activePower < allowedChargePower) { + activePower = allowedChargePower; + } + + int allowedDischargePower = ess.getAllowedDischargePower().orElse(0); + if (activePower > allowedDischargePower) { + activePower = allowedDischargePower; + } - this.getSut().applyPower(activePower.orElse(0), reactivePower.orElse(0)); + this.getSut().applyPower(activePower, reactivePower); } @Override diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java index 4a6dbecfa75..1056ef48b59 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java @@ -54,6 +54,33 @@ public void activate(Battery battery, ManagedSymmetricBatteryInverter batteryInv this.parent._setAllowedChargePower(0); this.parent._setAllowedDischargePower(0); } + +// Value forceChargeCurrent = battery.getForceChargeCurrentChannel().getNextValue(); +// Value forceDischargeCurrent = battery.getForceDischargeCurrentChannel().getNextValue(); +// +// final int allowedChargePower; +// final int allowedDischargePower; +// +// if(!voltage.isDefined()) { +// allowedChargePower = 0; +// allowedDischargePower = 0; +// } else { +// if(forceChargeCurrent.isDefined() && forceChargeCurrent.get) { +// allowedDischargePower = forceChargeCurrent +// } +// } +// +// if (voltage.isDefined() && dischargeMaxCurrent.isDefined() && chargeMaxCurrent.isDefined()) { +// // efficiency factor is not considered in chargeMaxCurrent (DC Power > AC Power) +// this.parent._setAllowedChargePower(// +// (int) (chargeMaxCurrent.get() * voltage.get() * -1)); +// this.parent._setAllowedDischargePower(// +// (int) (dischargeMaxCurrent.get() * voltage.get() * efficiencyFactor)); +// } else { +// } + +// this.parent._setAllowedChargePower(allowedChargePower); +// this.parent._setAllowedDischargePower(allowedDischargePower); }; this.addOnSetNextValueListener(battery, Battery.ChannelId.DISCHARGE_MIN_VOLTAGE, diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEss.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEss.java index eb51014832e..3835f47c977 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEss.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEss.java @@ -18,6 +18,12 @@ public interface GenericManagedSymmetricEss extends ManagedSymmetricEss, StartStoppable, ModbusSlave { + /** + * Efficiency factor to calculate AC Charge/Discharge limits from DC. Used at + * {@link ChannelManager}. + */ + public static double EFFICIENCY_FACTOR = 0.95; + /** * Retry set-command after x Seconds, e.g. for starting battery or * battery-inverter. diff --git a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEssTest.java b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEssTest.java index fb3e2045546..e78d3db20e0 100644 --- a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEssTest.java +++ b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEssTest.java @@ -11,6 +11,8 @@ import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; +import io.openems.edge.ess.test.DummyPower; +import io.openems.edge.ess.test.ManagedSymmetricEssTest; public class GenericManagedSymmetricEssTest { @@ -19,9 +21,14 @@ public class GenericManagedSymmetricEssTest { private static final String BATTERY_INVERTER_ID = "batteryInverter0"; private static final ChannelAddress ESS_STATE_MACHINE = new ChannelAddress(ESS_ID, "StateMachine"); + private static final ChannelAddress ESS_ALLOWED_DISCHARGE_POWER = new ChannelAddress(ESS_ID, + "AllowedDischargePower"); + private static final ChannelAddress BATTERY_START_STOP = new ChannelAddress(BATTERY_ID, "StartStop"); private static final ChannelAddress BATTERY_INVERTER_START_STOP = new ChannelAddress(BATTERY_INVERTER_ID, "StartStop"); + private static final ChannelAddress BATTERY_INVERTER_ACTIVE_POWER = new ChannelAddress(BATTERY_INVERTER_ID, + "ActivePower"); @Test public void testStart() throws Exception { @@ -50,4 +57,29 @@ public void testStart() throws Exception { ; } + @Test + public void testForceCharge() throws Exception { + new ManagedSymmetricEssTest(new GenericManagedSymmetricEssImpl()) // + .addReference("power", new DummyPower()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("batteryInverter", new DummyManagedSymmetricBatteryInverter(BATTERY_INVERTER_ID)) // + .addReference("battery", new DummyBattery(BATTERY_ID) // + .withVoltage(500) // + .withChargeMaxCurrent(50) // + .withDischargeMaxCurrent(-5) // + ) // + .activate(MyConfig.create() // + .setId(ESS_ID) // + .setStartStopConfig(StartStopConfig.START) // + .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setBatteryId(BATTERY_ID) // + .build()) // + .next(new TestCase() // + .output(ESS_ALLOWED_DISCHARGE_POWER, + (int) (-2500 * GenericManagedSymmetricEss.EFFICIENCY_FACTOR)) // + .output(BATTERY_INVERTER_ACTIVE_POWER, + (int) (-2500 * GenericManagedSymmetricEss.EFFICIENCY_FACTOR))) // + ; + } + } From 8d2c49d8aca3c8ec43839cbd6fa1af8b67e987f2 Mon Sep 17 00:00:00 2001 From: Wolfgang Gerbl Date: Tue, 8 Dec 2020 13:34:54 +0100 Subject: [PATCH 02/22] implemented for version b, test implmentation with different cell characteristic for version c --- .../soltaro/single/versionb/Config.java | 2 +- .../versionb/statemachine/RunningHandler.java | 66 +++++++++---------- .../versionc/SingleRackVersionCImpl.java | 62 +++++++++++++++-- .../versionb/SingleRackVersionBImplTest.java | 22 +++++++ .../kaco/blueplanet/gridsave50/Config.java | 2 +- 5 files changed, 113 insertions(+), 41 deletions(-) diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/Config.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/Config.java index 86db06be50d..25442019af6 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/Config.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/Config.java @@ -30,7 +30,7 @@ StartStopConfig startStop() default StartStopConfig.AUTO; @AttributeDefinition(name = "Number of slaves", description = "The number of slaves in this battery rack (max. 20)", min = "1", max = "20") - int numberOfSlaves() default 20; + int numberOfSlaves() default 20; // TODO can be removed because it can be read out from BMS @AttributeDefinition(name = "Module type", description = "The type of modules in the rack") ModuleType moduleType() default ModuleType.MODULE_3_5_KWH; diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java index a0c96db3eeb..00e55931b4f 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java @@ -3,9 +3,7 @@ import java.time.LocalDateTime; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionB; import io.openems.edge.battery.soltaro.single.versionb.statemachine.StateMachine.State; -import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; @@ -55,37 +53,39 @@ private void refreshBatteryValues(Context context) throws OpenemsNamedException private void setBatteryValues(Context context) throws OpenemsNamedException { - // 0x2086 ==> 2800 - WriteChannel channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_VOLTAGE_ALARM); - channel.setNextWriteValue(context.cellCharacteristic.getFinalCellDischargeVoltage_mV()); - - // 0x2087 ==> 2850 - channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_VOLTAGE_RECOVER); - channel.setNextWriteValue(context.cellCharacteristic.getFinalCellDischargeVoltage_mV() + 50); - - // 0x2047 ==> 2750 - channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_VOLTAGE_RECOVER); - channel.setNextWriteValue(context.cellCharacteristic.getForceChargeCellVoltage_mV()); - - // 0x2046 ==> 2700 - channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_VOLTAGE_PROTECTION); - channel.setNextWriteValue(context.cellCharacteristic.getForceChargeCellVoltage_mV() - 50); - - // 0x2080 ==> 3650 - channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_VOLTAGE_ALARM); - channel.setNextWriteValue(context.cellCharacteristic.getFinalCellChargeVoltage_mV()); - - // 0x2081 ==> 3600 - channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_VOLTAGE_RECOVER); - channel.setNextWriteValue(context.cellCharacteristic.getFinalCellChargeVoltage_mV() - 50); - - // 0x2041 ==> 3680 - channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_VOLTAGE_RECOVER); - channel.setNextWriteValue(context.cellCharacteristic.getForceDischargeCellVoltage_mV()); - - // 0x2040 ==> 3730 - channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_VOLTAGE_PROTECTION); - channel.setNextWriteValue(context.cellCharacteristic.getForceDischargeCellVoltage_mV() + 50); + //TODO first step is only to check the values and if there is a difference show a warning + +// // 0x2086 ==> 2800 +// WriteChannel channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_VOLTAGE_ALARM); +// channel.setNextWriteValue(context.cellCharacteristic.getFinalCellDischargeVoltage_mV()); +// +// // 0x2087 ==> 2850 +// channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_VOLTAGE_RECOVER); +// channel.setNextWriteValue(context.cellCharacteristic.getFinalCellDischargeVoltage_mV() + 50); +// +// // 0x2047 ==> 2750 +// channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_VOLTAGE_RECOVER); +// channel.setNextWriteValue(context.cellCharacteristic.getForceChargeCellVoltage_mV()); +// +// // 0x2046 ==> 2700 +// channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_VOLTAGE_PROTECTION); +// channel.setNextWriteValue(context.cellCharacteristic.getForceChargeCellVoltage_mV() - 50); +// +// // 0x2080 ==> 3650 +// channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_VOLTAGE_ALARM); +// channel.setNextWriteValue(context.cellCharacteristic.getFinalCellChargeVoltage_mV()); +// +// // 0x2081 ==> 3600 +// channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_VOLTAGE_RECOVER); +// channel.setNextWriteValue(context.cellCharacteristic.getFinalCellChargeVoltage_mV() - 50); +// +// // 0x2041 ==> 3680 +// channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_VOLTAGE_RECOVER); +// channel.setNextWriteValue(context.cellCharacteristic.getForceDischargeCellVoltage_mV()); +// +// // 0x2040 ==> 3730 +// channel = context.component.channel(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_VOLTAGE_PROTECTION); +// channel.setNextWriteValue(context.cellCharacteristic.getForceDischargeCellVoltage_mV() + 50); } } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionCImpl.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionCImpl.java index 6b49698f3e5..27f8305fa77 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionCImpl.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionCImpl.java @@ -24,6 +24,10 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.edge.battery.api.Battery; +import io.openems.edge.battery.soltaro.CellCharacteristic; +import io.openems.edge.battery.soltaro.SoltaroCellCharacteristic; +import io.openems.edge.battery.soltaro.Util; +import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionB; import io.openems.edge.battery.soltaro.single.versionc.statemachine.Context; import io.openems.edge.battery.soltaro.single.versionc.statemachine.StateMachine; import io.openems.edge.battery.soltaro.single.versionc.statemachine.StateMachine.State; @@ -40,6 +44,7 @@ import io.openems.edge.bridge.modbus.api.task.FC16WriteRegistersTask; import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; import io.openems.edge.bridge.modbus.api.task.FC6WriteRegisterTask; +import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.channel.IntegerWriteChannel; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; @@ -54,9 +59,10 @@ name = "Bms.Soltaro.SingleRack.VersionC", // immediate = true, // configurationPolicy = ConfigurationPolicy.REQUIRE, // - property = { // - EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE, // - }) + property = { + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // + }) public class SingleRackVersionCImpl extends AbstractOpenemsModbusComponent implements SingleRackVersionC, Battery, OpenemsComponent, EventHandler, ModbusSlave, StartStoppable { @@ -71,6 +77,33 @@ public class SingleRackVersionCImpl extends AbstractOpenemsModbusComponent private final StateMachine stateMachine = new StateMachine(State.UNDEFINED); private Config config; + + // TODO Test cell characteristic, remove after test and replace it by correct ones + private CellCharacteristic cellCharacteristic = new CellCharacteristic() { + + @Override + public int getForceDischargeCellVoltage_mV() { + // TODO Auto-generated method stub + return 3_680; + } + + @Override + public int getForceChargeCellVoltage_mV() { + return 3_250; + } + + @Override + public int getFinalCellDischargeVoltage_mV() { + // TODO Auto-generated method stub + return 3_300; + } + + @Override + public int getFinalCellChargeVoltage_mV() { + // TODO Auto-generated method stub + return 3_650; + } + }; public SingleRackVersionCImpl() { super(// @@ -121,6 +154,13 @@ public void handleEvent(Event event) { return; } switch (event.getTopic()) { + + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: + + this.setAllowedCurrents(); + + break; + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: this.handleStateMachine(); @@ -128,6 +168,16 @@ public void handleEvent(Event event) { } } + private void setAllowedCurrents() { + IntegerReadChannel maxChargeCurrentChannel = this.channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_CHARGE_CURRENT); + int maxChargeCurrentFromBMS = maxChargeCurrentChannel.value().orElse(0) / 1000; + + IntegerReadChannel maxDischargeChannel = this.channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_DISCHARGE_CURRENT); + int maxDischargeCurrentFromBMS = maxDischargeChannel.value().orElse(0) / 1000; + + Util.setMaxAllowedCurrents(cellCharacteristic, maxChargeCurrentFromBMS, maxDischargeCurrentFromBMS, this); + } + /** * Handles the State-Machine. */ @@ -273,13 +323,13 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { m(new UnsignedWordElement(0x210F)) // .m(SingleRackVersionC.ChannelId.SYSTEM_MAX_CHARGE_CURRENT, ElementToChannelConverter.SCALE_FACTOR_2) // - .m(Battery.ChannelId.CHARGE_MAX_CURRENT, ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // +// .m(Battery.ChannelId.CHARGE_MAX_CURRENT, ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // .build(), // m(new UnsignedWordElement(0x2110)) // .m(SingleRackVersionC.ChannelId.SYSTEM_MAX_DISCHARGE_CURRENT, ElementToChannelConverter.SCALE_FACTOR_2) // - .m(Battery.ChannelId.DISCHARGE_MAX_CURRENT, - ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // +// .m(Battery.ChannelId.DISCHARGE_MAX_CURRENT, +// ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // .build(), // m(SingleRackVersionC.ChannelId.POSITIVE_INSULATION, new UnsignedWordElement(0x2111)), // m(SingleRackVersionC.ChannelId.NEGATIVE_INSULATION, new UnsignedWordElement(0x2112)), // diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImplTest.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImplTest.java index a22ae45cda1..07c7557480e 100644 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImplTest.java +++ b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImplTest.java @@ -2,9 +2,11 @@ import org.junit.Test; +import io.openems.common.types.ChannelAddress; import io.openems.edge.battery.soltaro.ModuleType; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.startstop.StartStopConfig; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; @@ -12,6 +14,12 @@ public class SingleRackVersionBImplTest { private static final String BATTERY_ID = "battery0"; private static final String MODBUS_ID = "modbus0"; + private ChannelAddress minCellVoltageAdress = new ChannelAddress(BATTERY_ID, "MinCellVoltage"); + private ChannelAddress maxCellVoltageAdress = new ChannelAddress(BATTERY_ID, "MaxCellVoltage"); + private ChannelAddress capacityAdress = new ChannelAddress(BATTERY_ID, "Capacity"); + private ChannelAddress voltageAdress = new ChannelAddress(BATTERY_ID, "Voltage"); + private ChannelAddress maxDischargeCurrentAdress = new ChannelAddress(BATTERY_ID, "DischargeMaxCurrent"); + @Test public void test() throws Exception { @@ -35,6 +43,20 @@ public void test() throws Exception { .setSoCLowAlarm(0) // .setReduceTasks(false) // .build()) // + + + .next(new TestCase("Empty case")) + + /* set min cell voltage below limit, capacity and voltage are needed to calculate charge current */ + .next(new TestCase("test charge necessary") + .input(minCellVoltageAdress, 2750) + .input(maxCellVoltageAdress, 3050) + .input(capacityAdress, 70000) + .input(voltageAdress, 600) + ) + .next(new TestCase().output(maxDischargeCurrentAdress, -2)) + + ; } diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/Config.java b/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/Config.java index ef354943721..be61a406aa5 100644 --- a/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/Config.java +++ b/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/Config.java @@ -26,7 +26,7 @@ String Modbus_target() default ""; @AttributeDefinition(name = "Watchdog", description = "Sets the watchdog timer interval in seconds, 0=disable") - int watchdoginterval() default 0; + int watchdoginterval() default 60; @AttributeDefinition(name = "Battery-ID", description = "ID of Battery.") String battery_id() default "bms0"; From 351c3fe1eb4863632fce09fe1f959f6ffb816ff6 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 11 Dec 2020 14:55:45 +0100 Subject: [PATCH 03/22] Debug-Log-Controller: allow wildcards for ignore components + non-condensed output --- .../openems/common/types/ChannelAddress.java | 36 ++++++++++++++ .../io/openems/common/utils/StringUtils.java | 33 +++++++++++++ .../edge/controller/debuglog/Config.java | 3 ++ .../controller/debuglog/DebugLogImpl.java | 18 +++++-- .../controller/debuglog/DebugLogImplTest.java | 47 +++++++++++++++++++ .../edge/controller/debuglog/MyConfig.java | 15 +++++- 6 files changed, 146 insertions(+), 6 deletions(-) diff --git a/io.openems.common/src/io/openems/common/types/ChannelAddress.java b/io.openems.common/src/io/openems/common/types/ChannelAddress.java index 25fc64fdefa..e08967a079b 100644 --- a/io.openems.common/src/io/openems/common/types/ChannelAddress.java +++ b/io.openems.common/src/io/openems/common/types/ChannelAddress.java @@ -2,6 +2,7 @@ import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.utils.StringUtils; public class ChannelAddress implements Comparable { @@ -79,4 +80,39 @@ public boolean equals(Object obj) { ChannelAddress other = (ChannelAddress) obj; return this.toString().equals(other.toString()); } + + /** + * Match two ChannelAddresses, considering wildcards. + * + *
      + *
    • if {@link #equals(Object)} is true -> return 0 + *
    • if both {@link ChannelAddress}es match via wildcards -> return value > 1; + * bigger values represent a better match + *
    • if both {@link ChannelAddress}es do not match -> return -1 + *
    + * + *

    + * See {@link StringUtils#matchWildcard(String, String)} for implementation + * details. + * + * @param source the source {@link ChannelAddress} + * @param pattern the pattern {@link ChannelAddress} + * @return an integer value representing the degree of matching + */ + public static int match(ChannelAddress source, ChannelAddress pattern) { + int componentIdMatch = StringUtils.matchWildcard(source.componentId, pattern.componentId); + int channelIdMatch = StringUtils.matchWildcard(source.channelId, pattern.channelId); + if (componentIdMatch < 0 || channelIdMatch < 0) { + return -1; + } else if (componentIdMatch == 0 && channelIdMatch == 0) { + return 0; + } + if (componentIdMatch == 0) { + return Integer.MAX_VALUE / 2 + channelIdMatch; + } else if (channelIdMatch == 0) { + return Integer.MAX_VALUE / 2 + componentIdMatch; + } else { + return componentIdMatch + channelIdMatch; + } + } } diff --git a/io.openems.common/src/io/openems/common/utils/StringUtils.java b/io.openems.common/src/io/openems/common/utils/StringUtils.java index 200adfd8d9a..8315ea3d53a 100644 --- a/io.openems.common/src/io/openems/common/utils/StringUtils.java +++ b/io.openems.common/src/io/openems/common/utils/StringUtils.java @@ -23,4 +23,37 @@ public static String toShortString(JsonElement j, int length) { public static String capitalizeFirstLetter(String s) { return s.substring(0, 1).toUpperCase() + s.substring(1); } + + /** + * Match two Strings, considering wildcards. + * + *

      + *
    • if {@link #equals(Object)} is true -> return 0 + *
    • if 'pattern' matches 'source' -> return value > 1; bigger values + * represent a better match + *
    • if both Strings do not match -> return -1 + *
    + * + *

    + * Implementation note: only one wildcard is considered. Either the entire + * string is "*" or the wildcard is at the beginning or at the end of the + * pattern String. The the JUnit test for details. + * + * @param source the String to be evaluated + * @param pattern the pattern String, i.e. "meter*" + * @return an integer value representing the degree of matching + */ + public static int matchWildcard(String source, String pattern) { + if (source.equals(pattern)) { + return 0; + } else if (pattern.equals("*")) { + return 1; + } else if (pattern.startsWith("*") && source.endsWith(pattern.substring(1))) { + return pattern.length(); + } else if (pattern.endsWith("*") && source.startsWith(pattern.substring(0, pattern.length() - 1))) { + return pattern.length(); + } else { + return -1; + } + } } diff --git a/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/Config.java b/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/Config.java index 720ffc6d97f..2ced8486b7e 100644 --- a/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/Config.java +++ b/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/Config.java @@ -17,6 +17,9 @@ @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") boolean enabled() default true; + @AttributeDefinition(name = "Condensed output", description = "Print all logs in one joint line") + boolean condensedOutput() default true; + @AttributeDefinition(name = "Additional Channels", description = "Channel-Addresses of additional Channels that should be logged") String[] additionalChannels() default {}; diff --git a/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/DebugLogImpl.java b/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/DebugLogImpl.java index aaae09d449e..6ef73606838 100644 --- a/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/DebugLogImpl.java +++ b/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/DebugLogImpl.java @@ -24,6 +24,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.types.ChannelAddress; +import io.openems.common.utils.StringUtils; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; @@ -45,8 +46,9 @@ public class DebugLogImpl extends AbstractOpenemsComponent implements DebugLog, target = "(&(enabled=true)(!(service.factoryPid=Controller.Debug.Log)))") private volatile List components = new CopyOnWriteArrayList<>(); - private TreeMultimap additionalChannels = TreeMultimap.create(); - private Set ignoreComponents = new HashSet<>(); + private Config config; + private final TreeMultimap additionalChannels = TreeMultimap.create(); + private final Set ignoreComponents = new HashSet<>(); public DebugLogImpl() { super(// @@ -58,6 +60,7 @@ public DebugLogImpl() { @Activate void activate(ComponentContext context, Config config) throws OpenemsNamedException { + this.config = config; super.activate(context, config.id(), config.alias(), config.enabled()); // Parse Additional Channels @@ -100,7 +103,8 @@ protected String getLogMessage() { final List logs = new ArrayList<>(); // Should the default logs of this Component be ignored? - if (!this.ignoreComponents.contains(component.id())) { + if (this.ignoreComponents.stream() // + .noneMatch(pattern -> StringUtils.matchWildcard(component.id(), pattern) >= 0)) { // Component Debug-Log String debugLog = component.debugLog(); if (debugLog != null) { @@ -126,6 +130,12 @@ protected String getLogMessage() { result.add(component.id() + "[" + String.join("|", logs) + "]"); } }); - return String.join(" ", result); + if (this.config.condensedOutput()) { + // separate components by space; one line in total + return String.join(" ", result); + } else { + // separate components by newline + return String.join("\n", result); + } } } diff --git a/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/DebugLogImplTest.java b/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/DebugLogImplTest.java index b5110640006..fdb91ad272b 100644 --- a/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/DebugLogImplTest.java +++ b/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/DebugLogImplTest.java @@ -21,6 +21,8 @@ public class DebugLogImplTest { private static final String DUMMY0_ID = "dummy0"; private static final String DUMMY1_ID = "dummy1"; + private static final String ANY_DUMMY = "dummy*"; + private final static ChannelAddress SUM_ESS_SOC = new ChannelAddress("_sum", "EssSoc"); @Test @@ -52,6 +54,7 @@ public String debugLog() { .addComponent(components.get(1)) // .activate(MyConfig.create() // .setId(CTRL_ID) // + .setCondensedOutput(true) // .setAdditionalChannels(new String[] { // SUM_ESS_SOC.toString() // }) // @@ -66,4 +69,48 @@ public String debugLog() { } + @Test + public void testWildcard() throws Exception { + List components = new ArrayList<>(); + components.add(new DummySum() { + @Override + public String debugLog() { + return "foo:bar"; + } + }); + components.add(new DummyController(DUMMY0_ID) { + @Override + public String debugLog() { + return "abc:xyz"; + } + }); + components.add(new DummyController(DUMMY1_ID) { + @Override + public String debugLog() { + return "def:uvw"; + } + }); + + DebugLogImpl sut = new DebugLogImpl(); + new ControllerTest(sut) // + .addReference("components", components) // + .addComponent(components.get(0)) // + .addComponent(components.get(1)) // + .activate(MyConfig.create() // + .setId(CTRL_ID) // + .setCondensedOutput(true) // + .setAdditionalChannels(new String[] { // + SUM_ESS_SOC.toString() // + }) // + .setIgnoreComponents(new String[] { // + ANY_DUMMY // + }) // + .build()) // + .next(new TestCase() // + .input(SUM_ESS_SOC, 50)); + + assertEquals("_sum[foo:bar|EssSoc:50 %]", sut.getLogMessage()); + + } + } diff --git a/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/MyConfig.java b/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/MyConfig.java index bdbda2ae803..aba2864cf58 100644 --- a/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/MyConfig.java +++ b/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/MyConfig.java @@ -10,6 +10,7 @@ protected static class Builder { private String rule = null; public String[] additionalChannels; public String[] ignoreComponents; + public boolean condensedOutput; private Builder() { @@ -24,12 +25,17 @@ public Builder setAdditionalChannels(String[] additionalChannels) { this.additionalChannels = additionalChannels; return this; } - + public Builder setIgnoreComponents(String[] ignoreComponents) { this.ignoreComponents = ignoreComponents; return this; } - + + public Builder setCondensedOutput(boolean condensedOutput) { + this.condensedOutput = condensedOutput; + return this; + } + public MyConfig build() { return new MyConfig(this); } @@ -56,4 +62,9 @@ public String[] ignoreComponents() { return this.builder.ignoreComponents; } + @Override + public boolean condensedOutput() { + return this.builder.condensedOutput; + } + } \ No newline at end of file From 10dd8000bc26acc92f4c65091187737b69f1831e Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 11 Dec 2020 14:56:47 +0100 Subject: [PATCH 04/22] Improve ApiWorker logs --- .../component/AbstractOpenemsComponent.java | 9 ++-- .../common/component/OpenemsComponent.java | 47 +++++++++++++++++++ .../api/backend/BackendApiImpl.java | 2 +- .../edge/controller/api/common/ApiWorker.java | 26 ++++++---- .../api/modbus/AbstractModbusTcpApi.java | 2 +- .../controller/api/rest/AbstractRestApi.java | 2 +- .../api/websocket/WebsocketApi.java | 2 +- 7 files changed, 71 insertions(+), 19 deletions(-) diff --git a/io.openems.edge.common/src/io/openems/edge/common/component/AbstractOpenemsComponent.java b/io.openems.edge.common/src/io/openems/edge/common/component/AbstractOpenemsComponent.java index 91c8aaf76ec..1b3563fb069 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/component/AbstractOpenemsComponent.java +++ b/io.openems.edge.common/src/io/openems/edge/common/component/AbstractOpenemsComponent.java @@ -405,8 +405,7 @@ public Collection> channels() { * @param message the message */ protected void logDebug(Logger log, String message) { - // TODO use log.debug(String, Object...) to improve speed - log.debug("[" + this.id() + "] " + message); + OpenemsComponent.logDebug(this, log, message); } /** @@ -416,7 +415,7 @@ protected void logDebug(Logger log, String message) { * @param message the message */ protected void logInfo(Logger log, String message) { - log.info("[" + this.id() + "] " + message); + OpenemsComponent.logInfo(this, log, message); } /** @@ -426,7 +425,7 @@ protected void logInfo(Logger log, String message) { * @param message the message */ protected void logWarn(Logger log, String message) { - log.warn("[" + this.id() + "] " + message); + OpenemsComponent.logWarn(this, log, message); } /** @@ -436,7 +435,7 @@ protected void logWarn(Logger log, String message) { * @param message the message */ protected void logError(Logger log, String message) { - log.error("[" + this.id() + "] " + message); + OpenemsComponent.logError(this, log, message); } /** diff --git a/io.openems.edge.common/src/io/openems/edge/common/component/OpenemsComponent.java b/io.openems.edge.common/src/io/openems/edge/common/component/OpenemsComponent.java index 08fe068d65a..4fb3c93668a 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/component/OpenemsComponent.java +++ b/io.openems.edge.common/src/io/openems/edge/common/component/OpenemsComponent.java @@ -8,6 +8,7 @@ import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; import io.openems.common.channel.AccessMode; import io.openems.common.channel.Level; @@ -372,4 +373,50 @@ public static void updateConfigurationProperty(ConfigurationAdmin cm, String pid System.out.println("ERROR: " + e.getMessage()); } } + + /** + * Log a debug message including the Component ID. + * + * @param component the {@link OpenemsComponent} + * @param log the {@link Logger} instance + * @param message the message + */ + public static void logDebug(OpenemsComponent component, Logger log, String message) { + // TODO use log.debug(String, Object...) to improve speed + log.debug("[" + component.id() + "] " + message); + } + + /** + * Log a info message including the Component ID. + * + * @param component the {@link OpenemsComponent} + * @param log the {@link Logger} instance + * @param message the message + */ + public static void logInfo(OpenemsComponent component, Logger log, String message) { + log.info("[" + component.id() + "] " + message); + } + + /** + * Log a warn message including the Component ID. + * + * @param component the {@link OpenemsComponent} + * @param log the {@link Logger} instance + * @param message the message + */ + public static void logWarn(OpenemsComponent component, Logger log, String message) { + log.warn("[" + component.id() + "] " + message); + } + + /** + * Log a error message including the Component ID. + * + * @param component the {@link OpenemsComponent} + * @param log the {@link Logger} instance + * @param message the message + */ + public static void logError(OpenemsComponent component, Logger log, String message) { + log.error("[" + component.id() + "] " + message); + } + } diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApiImpl.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApiImpl.java index 1df8db9a834..1374d6ed00d 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApiImpl.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApiImpl.java @@ -56,7 +56,7 @@ public class BackendApiImpl extends AbstractOpenemsComponent protected final BackendWorker worker = new BackendWorker(this); - protected final ApiWorker apiWorker = new ApiWorker(); + protected final ApiWorker apiWorker = new ApiWorker(this); private final Logger log = LoggerFactory.getLogger(BackendApiImpl.class); diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java index ac8aca799fc..31a24728caf 100644 --- a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java @@ -26,6 +26,7 @@ import io.openems.edge.common.channel.StringReadChannel; import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.common.component.OpenemsComponent; /** * Takes care of continuously writing channels till a timeout. This class is @@ -37,7 +38,9 @@ public class ApiWorker { public static final int DEFAULT_TIMEOUT_SECONDS = 10; - private static final Logger log = LoggerFactory.getLogger(ApiWorker.class); + private final Logger log = LoggerFactory.getLogger(ApiWorker.class); + + private final OpenemsComponent parent; /** * Debug information about writes to channels is sent to this channel. @@ -55,7 +58,8 @@ public class ApiWorker { private int timeoutSeconds = DEFAULT_TIMEOUT_SECONDS; - public ApiWorker() { + public ApiWorker(OpenemsComponent parent) { + this.parent = parent; this.executor = Executors.newSingleThreadScheduledExecutor(); } @@ -81,12 +85,13 @@ public void addValue(WriteChannel channel, WriteObject writeObject) { synchronized (this.values) { if (writeObject.isNull()) { // set null -> remove write-value - log.info("Unset [" + channel.address() + "] via API."); + OpenemsComponent.logInfo(this.parent, this.log, + "Set [" + channel.address() + "] to [" + writeObject.valueToString() + "] via API"); this.values.remove(channel); } else { // set write-value - log.info("Set [" + channel.address() + "] to [" + writeObject.valueToString() - + "] via API. Timeout is [" + this.timeoutSeconds + "s]"); + OpenemsComponent.logInfo(this.parent, this.log, "Set [" + channel.address() + "] to [" + + writeObject.valueToString() + "] via API. Timeout is [" + this.timeoutSeconds + "s]"); this.values.put(channel, writeObject); } } @@ -141,8 +146,8 @@ private synchronized void resetTimeout() { */ synchronized (this.values) { for (Entry, WriteObject> entry : this.values.entrySet()) { - log.info("API timeout for channel [" + entry.getKey().address() + "] after [" - + this.timeoutSeconds + "s]"); + OpenemsComponent.logInfo(this.parent, this.log, "API timeout for channel [" + + entry.getKey().address() + "] after [" + this.timeoutSeconds + "s]"); entry.getValue().notifyTimeout(); } this.values.clear(); @@ -177,13 +182,14 @@ public void run() throws OpenemsNamedException { WriteChannel channel = entry.getKey(); WriteObject writeObject = entry.getValue(); try { - log.info("Set Channel [" + channel.address() + "] to Value [" + writeObject.valueToString() + "]"); + OpenemsComponent.logInfo(this.parent, this.log, + "Set Channel [" + channel.address() + "] to Value [" + writeObject.valueToString() + "]"); writeObject.setNextWriteValue(channel); writeObject.notifySuccess(); logs.add(channel.address() + ":" + writeObject.valueToString()); } catch (OpenemsException e) { - log.error("Unable to set Channel [" + channel.address() + "] to Value [" - + writeObject.valueToString() + "]: " + e.getMessage()); + OpenemsComponent.logError(this.parent, this.log, "Unable to set Channel [" + channel.address() + + "] to Value [" + writeObject.valueToString() + "]: " + e.getMessage()); logs.add(channel.address() + ":" + writeObject.valueToString() + "-ERROR:" + e.getMessage()); writeObject.notifyError(e); anExceptionHappened = e; diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java index 335e74d8df7..507132a0c1d 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java @@ -49,7 +49,7 @@ public abstract class AbstractModbusTcpApi extends AbstractOpenemsComponent public static final int DEFAULT_PORT = 502; public static final int DEFAULT_MAX_CONCURRENT_CONNECTIONS = 5; - protected final ApiWorker apiWorker = new ApiWorker(); + protected final ApiWorker apiWorker = new ApiWorker(this); private final Logger log = LoggerFactory.getLogger(AbstractModbusTcpApi.class); private final MyProcessImage processImage; diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/AbstractRestApi.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/AbstractRestApi.java index f62a0c64a62..05e4f523481 100644 --- a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/AbstractRestApi.java +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/AbstractRestApi.java @@ -27,7 +27,7 @@ public abstract class AbstractRestApi extends AbstractOpenemsComponent public static final boolean DEFAULT_DEBUG_MODE = true; - protected final ApiWorker apiWorker = new ApiWorker(); + protected final ApiWorker apiWorker = new ApiWorker(this); private final Logger log = LoggerFactory.getLogger(RestApiReadOnlyImpl.class); private final String implementationName; diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketApi.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketApi.java index cb3d205f4db..f102730482d 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketApi.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketApi.java @@ -60,7 +60,7 @@ public class WebsocketApi extends AbstractOpenemsComponent public static final int DEFAULT_PORT = 8075; - protected final ApiWorker apiWorker = new ApiWorker(); + protected final ApiWorker apiWorker = new ApiWorker(this); private final SystemLogHandler systemLogHandler; From 50eaf2ecd8113d057c556590e4367879b2909bb8 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 11 Dec 2020 20:21:12 +0100 Subject: [PATCH 05/22] Autoformat, remove unnecessary logs, add Javadoc --- .../io/openems/edge/battery/api/Battery.java | 26 +- .../statemachine/ErrorHandler.java | 2 - .../battery/soltaro/CellCharacteristic.java | 25 +- .../soltaro/SoltaroCellCharacteristic.java | 4 +- .../versionc/statemachine/ErrorHandler.java | 2 - .../versionb/SingleRackVersionBImpl.java | 345 +++++++++--------- .../versionb/statemachine/ErrorHandler.java | 2 - .../versionb/statemachine/RunningHandler.java | 19 +- .../versionc/SingleRackVersionCImpl.java | 43 +-- .../versionc/statemachine/ErrorHandler.java | 2 - .../symmetric/statemachine/ErrorHandler.java | 2 - 11 files changed, 253 insertions(+), 219 deletions(-) diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java index 0558322fcc3..36ba542292d 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java @@ -119,6 +119,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { * {@link ChannelId#FORCE_DISCHARGE_ACTIVE} * */ + // TODO every Battery-Inverter implementation needs to be adjusted accordingly! + // Usually this register might be UINT16 and not accept negative values! CHARGE_MAX_CURRENT(Doc.of(OpenemsType.INTEGER) // .unit(Unit.AMPERE)), @@ -749,8 +751,7 @@ public default StateChannel getForceChargeActiveChannel() { } /** - * Gets the State. See - * {@link ChannelId#FORCE_CHARGE_ACTIVE}. + * Gets the State. See {@link ChannelId#FORCE_CHARGE_ACTIVE}. * * @return the Channel {@link Value} */ @@ -759,8 +760,8 @@ public default Value getForceChargeActive() { } /** - * Internal method to set the 'nextValue' on {@link ChannelId#FORCE_CHARGE_ACTIVE} - * Channel. + * Internal method to set the 'nextValue' on + * {@link ChannelId#FORCE_CHARGE_ACTIVE} Channel. * * @param value the next value */ @@ -769,15 +770,15 @@ public default void _setForceChargeActive(Boolean value) { } /** - * Internal method to set the 'nextValue' on {@link ChannelId#FORCE_CHARGE_ACTIVE} - * Channel. + * Internal method to set the 'nextValue' on + * {@link ChannelId#FORCE_CHARGE_ACTIVE} Channel. * * @param value the next value */ public default void _setForceChargeActive(boolean value) { this.getForceChargeActiveChannel().setNextValue(value); } - + /** * Gets the Channel for {@link ChannelId#FORCE_DISCHARGE_ACTIVE}. * @@ -788,8 +789,7 @@ public default StateChannel getForceDischargeActiveChannel() { } /** - * Gets the State. See - * {@link ChannelId#FORCE_DISCHARGE_ACTIVE}. + * Gets the State. See {@link ChannelId#FORCE_DISCHARGE_ACTIVE}. * * @return the Channel {@link Value} */ @@ -798,8 +798,8 @@ public default Value getForceDischargeActive() { } /** - * Internal method to set the 'nextValue' on {@link ChannelId#FORCE_DISCHARGE_ACTIVE} - * Channel. + * Internal method to set the 'nextValue' on + * {@link ChannelId#FORCE_DISCHARGE_ACTIVE} Channel. * * @param value the next value */ @@ -808,8 +808,8 @@ public default void _setForceDischargeActive(Boolean value) { } /** - * Internal method to set the 'nextValue' on {@link ChannelId#FORCE_DISCHARGE_ACTIVE} - * Channel. + * Internal method to set the 'nextValue' on + * {@link ChannelId#FORCE_DISCHARGE_ACTIVE} Channel. * * @param value the next value */ diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java index 056818d1046..da51d913985 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java @@ -28,8 +28,6 @@ protected void onExit(Context context) throws OpenemsNamedException { @Override public State runAndGetNextState(Context context) { - System.out.println("Stuck in ERROR_HANDLING: " + context.component.getStateChannel().listStates()); - if (Duration.between(this.entryAt, Instant.now()).getSeconds() > 120) { // Try again return State.UNDEFINED; diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/CellCharacteristic.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/CellCharacteristic.java index e70e169d692..419d5a3f68c 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/CellCharacteristic.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/CellCharacteristic.java @@ -2,9 +2,32 @@ public interface CellCharacteristic { + /** + * German "Beladeschlussspannung". + * + * @return the final cell charge voltage in [mV] + */ int getFinalCellChargeVoltage_mV(); + + /** + * German "Entladeschlussspannung". + * + * @return the final cell discharge voltage in [mV] + */ int getFinalCellDischargeVoltage_mV(); + + /** + * German "Zwangsbeladespannung". + * + * @return the force charge cell voltage in [mV] + */ int getForceChargeCellVoltage_mV(); + + /** + * German "Zwangsentladespannung". + * + * @return the force discharge cell voltage in [mV] + */ int getForceDischargeCellVoltage_mV(); - + } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java index c539684c3c7..07bc6031d80 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java @@ -4,12 +4,12 @@ public class SoltaroCellCharacteristic implements CellCharacteristic { @Override public int getFinalCellDischargeVoltage_mV() { - return 2_800; // x2086 Cell under voltage Alarm + return 2_800; // 0x2086 Cell under voltage Alarm } @Override public int getForceChargeCellVoltage_mV() { - return 2_750; // x2047 Cell under voltage Protection recover + return 2_750; // 0x2047 Cell under voltage Protection recover } @Override diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/ErrorHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/ErrorHandler.java index a8d5c8abfc9..2cdbdee14e3 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/ErrorHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/ErrorHandler.java @@ -28,8 +28,6 @@ protected void onExit(Context context) throws OpenemsNamedException { @Override public State runAndGetNextState(Context context) { - System.out.println("Stuck in ERROR_HANDLING: " + context.component.getStateChannel().listStates()); - if (Duration.between(this.entryAt, Instant.now()).getSeconds() > 120) { // Try again return State.UNDEFINED; diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java index dc2b5e09dc2..32bee65a6e4 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java @@ -65,10 +65,10 @@ @Component(// name = "Bms.Soltaro.SingleRack.VersionB", // immediate = true, // - configurationPolicy = ConfigurationPolicy.REQUIRE, // - property = { - EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // - EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // + configurationPolicy = ConfigurationPolicy.REQUIRE, // + property = { // + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // }) public class SingleRackVersionBImpl extends AbstractOpenemsModbusComponent implements Battery, OpenemsComponent, EventHandler, ModbusSlave, StartStoppable, SingleRackVersionB { @@ -91,8 +91,8 @@ public class SingleRackVersionBImpl extends AbstractOpenemsModbusComponent private Config config; private Map> channelMap; - - private CellCharacteristic cellCharacteristic = new SoltaroCellCharacteristic(); + + private final CellCharacteristic cellCharacteristic = new SoltaroCellCharacteristic(); public SingleRackVersionBImpl() { super(// @@ -164,27 +164,46 @@ public void handleEvent(Event event) { } switch (event.getTopic()) { - case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: - + this.setAllowedCurrents(); - + break; - + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: this.handleStateMachine(); break; } } + private final static int MAX_INCREASE_MILLIAMPERE = 300; + + private int lastMaxChargeCurrentFromBMS = 0; + private int lastMaxDischargeCurrentFromBMS = 0; + private void setAllowedCurrents() { - IntegerReadChannel maxChargeCurrentChannel = this.channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_CHARGE_CURRENT); - int maxChargeCurrentFromBMS = maxChargeCurrentChannel.value().orElse(0) / 1000; - - IntegerReadChannel maxDischargeChannel = this.channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_DISCHARGE_CURRENT); - int maxDischargeCurrentFromBMS = maxDischargeChannel.value().orElse(0) / 1000; - - Util.setMaxAllowedCurrents(cellCharacteristic, maxChargeCurrentFromBMS, maxDischargeCurrentFromBMS, this); + IntegerReadChannel maxChargeCurrentChannel = this + .channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_CHARGE_CURRENT); + int maxChargeCurrentFromBMS = maxChargeCurrentChannel.value().orElse(0); + + // Allow max increase of 1 A + if (maxChargeCurrentFromBMS > lastMaxChargeCurrentFromBMS + MAX_INCREASE_MILLIAMPERE) { + maxChargeCurrentFromBMS = lastMaxChargeCurrentFromBMS + MAX_INCREASE_MILLIAMPERE; + } + this.lastMaxChargeCurrentFromBMS = maxChargeCurrentFromBMS; + + IntegerReadChannel maxDischargeChannel = this + .channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_DISCHARGE_CURRENT); + int maxDischargeCurrentFromBMS = maxDischargeChannel.value().orElse(0); + + // Allow max increase of 1 A + if (maxDischargeCurrentFromBMS > lastMaxDischargeCurrentFromBMS + MAX_INCREASE_MILLIAMPERE) { + maxDischargeCurrentFromBMS = lastMaxDischargeCurrentFromBMS + MAX_INCREASE_MILLIAMPERE; + } + this.lastMaxDischargeCurrentFromBMS = maxDischargeCurrentFromBMS; + + Util.setMaxAllowedCurrents(this.cellCharacteristic, maxChargeCurrentFromBMS / 1000, + maxDischargeCurrentFromBMS / 1000, this); } @Override @@ -520,7 +539,7 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { m(new UnsignedWordElement(0x2160)) // .m(SingleRackVersionB.ChannelId.SYSTEM_MAX_CHARGE_CURRENT, - ElementToChannelConverter.SCALE_FACTOR_2) // + ElementToChannelConverter.SCALE_FACTOR_2) // .build(), // m(new UnsignedWordElement(0x2161)) // .m(SingleRackVersionB.ChannelId.SYSTEM_MAX_DISCHARGE_CURRENT, @@ -632,152 +651,152 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { new UnsignedWordElement(0x21B4)), // m(SingleRackVersionB.ChannelId.SLAVE_TEMPERATURE_COMMUNICATION_ERROR_LOW, new UnsignedWordElement(0x21B5)) // - ) // - ); // - - if (!this.config.ReduceTasks()) { - - // Add tasks to read/write work and warn parameters - // Stop parameter - Task writeStopParameters = new FC16WriteRegistersTask(0x2040, // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_VOLTAGE_PROTECTION, - new UnsignedWordElement(0x2040)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_VOLTAGE_RECOVER, - new UnsignedWordElement(0x2041)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_OVER_VOLTAGE_PROTECTION, - new UnsignedWordElement(0x2042), ElementToChannelConverter.SCALE_FACTOR_2), - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_OVER_VOLTAGE_RECOVER, - new UnsignedWordElement(0x2043), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_CHARGE_OVER_CURRENT_PROTECTION, - new UnsignedWordElement(0x2044), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_CHARGE_OVER_CURRENT_RECOVER, - new UnsignedWordElement(0x2045), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_VOLTAGE_PROTECTION, - new UnsignedWordElement(0x2046)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_VOLTAGE_RECOVER, - new UnsignedWordElement(0x2047)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_UNDER_VOLTAGE_PROTECTION, - new UnsignedWordElement(0x2048), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_UNDER_VOLTAGE_RECOVER, - new UnsignedWordElement(0x2049), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_DISCHARGE_OVER_CURRENT_PROTECTION, - new UnsignedWordElement(0x204A), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_DISCHARGE_OVER_CURRENT_RECOVER, - new UnsignedWordElement(0x204B), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_TEMPERATURE_PROTECTION, - new UnsignedWordElement(0x204C)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_TEMPERATURE_RECOVER, - new UnsignedWordElement(0x204D)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_TEMPERATURE_PROTECTION, - new UnsignedWordElement(0x204E)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_TEMPERATURE_RECOVER, - new UnsignedWordElement(0x204F)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SOC_LOW_PROTECTION, new UnsignedWordElement(0x2050)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SOC_LOW_PROTECTION_RECOVER, - new UnsignedWordElement(0x2051)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SOC_HIGH_PROTECTION, new UnsignedWordElement(0x2052)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SOC_HIGH_PROTECTION_RECOVER, - new UnsignedWordElement(0x2053)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CONNECTOR_TEMPERATURE_HIGH_PROTECTION, - new UnsignedWordElement(0x2054)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CONNECTOR_TEMPERATURE_HIGH_PROTECTION_RECOVER, - new UnsignedWordElement(0x2055)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_INSULATION_PROTECTION, - new UnsignedWordElement(0x2056)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_INSULATION_PROTECTION_RECOVER, - new UnsignedWordElement(0x2057)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_VOLTAGE_DIFFERENCE_PROTECTION, - new UnsignedWordElement(0x2058)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_VOLTAGE_DIFFERENCE_PROTECTION_RECOVER, - new UnsignedWordElement(0x2059)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_TOTAL_VOLTAGE_DIFFERENCE_PROTECTION, - new UnsignedWordElement(0x205A), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_TOTAL_VOLTAGE_DIFFERENCE_PROTECTION_RECOVER, - new UnsignedWordElement(0x205B), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_DISCHARGE_TEMPERATURE_HIGH_PROTECTION, - new UnsignedWordElement(0x205C)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_DISCHARGE_TEMPERATURE_HIGH_PROTECTION_RECOVER, - new UnsignedWordElement(0x205D)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_DISCHARGE_TEMPERATURE_LOW_PROTECTION, - new UnsignedWordElement(0x205E)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_DISCHARGE_TEMPERATURE_LOW_PROTECTION_RECOVER, - new UnsignedWordElement(0x205F)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_TEMPERATURE_DIFFERENCE_PROTECTION, - new UnsignedWordElement(0x2060)), // - m(SingleRackVersionB.ChannelId.STOP_PARAMETER_TEMPERATURE_DIFFERENCE_PROTECTION_RECOVER, - new UnsignedWordElement(0x2061)) // - ); + ), // + // Add tasks to read/write work and warn parameters + // Stop parameter + new FC16WriteRegistersTask(0x2040, // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_VOLTAGE_PROTECTION, + new UnsignedWordElement(0x2040)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_VOLTAGE_RECOVER, + new UnsignedWordElement(0x2041)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_OVER_VOLTAGE_PROTECTION, + new UnsignedWordElement(0x2042), ElementToChannelConverter.SCALE_FACTOR_2), + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_OVER_VOLTAGE_RECOVER, + new UnsignedWordElement(0x2043), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_CHARGE_OVER_CURRENT_PROTECTION, + new UnsignedWordElement(0x2044), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_CHARGE_OVER_CURRENT_RECOVER, + new UnsignedWordElement(0x2045), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_VOLTAGE_PROTECTION, + new UnsignedWordElement(0x2046)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_VOLTAGE_RECOVER, + new UnsignedWordElement(0x2047)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_UNDER_VOLTAGE_PROTECTION, + new UnsignedWordElement(0x2048), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_UNDER_VOLTAGE_RECOVER, + new UnsignedWordElement(0x2049), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_DISCHARGE_OVER_CURRENT_PROTECTION, + new UnsignedWordElement(0x204A), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SYSTEM_DISCHARGE_OVER_CURRENT_RECOVER, + new UnsignedWordElement(0x204B), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_TEMPERATURE_PROTECTION, + new UnsignedWordElement(0x204C)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_TEMPERATURE_RECOVER, + new UnsignedWordElement(0x204D)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_TEMPERATURE_PROTECTION, + new UnsignedWordElement(0x204E)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_UNDER_TEMPERATURE_RECOVER, + new UnsignedWordElement(0x204F)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SOC_LOW_PROTECTION, + new UnsignedWordElement(0x2050)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SOC_LOW_PROTECTION_RECOVER, + new UnsignedWordElement(0x2051)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SOC_HIGH_PROTECTION, + new UnsignedWordElement(0x2052)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_SOC_HIGH_PROTECTION_RECOVER, + new UnsignedWordElement(0x2053)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CONNECTOR_TEMPERATURE_HIGH_PROTECTION, + new UnsignedWordElement(0x2054)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CONNECTOR_TEMPERATURE_HIGH_PROTECTION_RECOVER, + new UnsignedWordElement(0x2055)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_INSULATION_PROTECTION, + new UnsignedWordElement(0x2056)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_INSULATION_PROTECTION_RECOVER, + new UnsignedWordElement(0x2057)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_VOLTAGE_DIFFERENCE_PROTECTION, + new UnsignedWordElement(0x2058)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_VOLTAGE_DIFFERENCE_PROTECTION_RECOVER, + new UnsignedWordElement(0x2059)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_TOTAL_VOLTAGE_DIFFERENCE_PROTECTION, + new UnsignedWordElement(0x205A), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_TOTAL_VOLTAGE_DIFFERENCE_PROTECTION_RECOVER, + new UnsignedWordElement(0x205B), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_DISCHARGE_TEMPERATURE_HIGH_PROTECTION, + new UnsignedWordElement(0x205C)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_DISCHARGE_TEMPERATURE_HIGH_PROTECTION_RECOVER, + new UnsignedWordElement(0x205D)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_DISCHARGE_TEMPERATURE_LOW_PROTECTION, + new UnsignedWordElement(0x205E)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_DISCHARGE_TEMPERATURE_LOW_PROTECTION_RECOVER, + new UnsignedWordElement(0x205F)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_TEMPERATURE_DIFFERENCE_PROTECTION, + new UnsignedWordElement(0x2060)), // + m(SingleRackVersionB.ChannelId.STOP_PARAMETER_TEMPERATURE_DIFFERENCE_PROTECTION_RECOVER, + new UnsignedWordElement(0x2061)) // + ), - // Warn parameter - Task writeWarnParameters = new FC16WriteRegistersTask(0x2080, // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_VOLTAGE_ALARM, - new UnsignedWordElement(0x2080)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_VOLTAGE_RECOVER, - new UnsignedWordElement(0x2081)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_OVER_VOLTAGE_ALARM, - new UnsignedWordElement(0x2082), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_OVER_VOLTAGE_RECOVER, - new UnsignedWordElement(0x2083), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_CHARGE_OVER_CURRENT_ALARM, - new UnsignedWordElement(0x2084), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_CHARGE_OVER_CURRENT_RECOVER, - new UnsignedWordElement(0x2085), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_VOLTAGE_ALARM, - new UnsignedWordElement(0x2086)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_VOLTAGE_RECOVER, - new UnsignedWordElement(0x2087)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_UNDER_VOLTAGE_ALARM, - new UnsignedWordElement(0x2088), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_UNDER_VOLTAGE_RECOVER, - new UnsignedWordElement(0x2089), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_DISCHARGE_OVER_CURRENT_ALARM, - new UnsignedWordElement(0x208A), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_DISCHARGE_OVER_CURRENT_RECOVER, - new UnsignedWordElement(0x208B), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_TEMPERATURE_ALARM, - new UnsignedWordElement(0x208C)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_TEMPERATURE_RECOVER, - new UnsignedWordElement(0x208D)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_TEMPERATURE_ALARM, - new UnsignedWordElement(0x208E)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_TEMPERATURE_RECOVER, - new UnsignedWordElement(0x208F)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SOC_LOW_ALARM, new UnsignedWordElement(0x2090)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SOC_LOW_ALARM_RECOVER, - new UnsignedWordElement(0x2091)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SOC_HIGH_ALARM, new UnsignedWordElement(0x2092)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SOC_HIGH_ALARM_RECOVER, - new UnsignedWordElement(0x2093)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CONNECTOR_TEMPERATURE_HIGH_ALARM, - new UnsignedWordElement(0x2094)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CONNECTOR_TEMPERATURE_HIGH_ALARM_RECOVER, - new UnsignedWordElement(0x2095)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_INSULATION_ALARM, new UnsignedWordElement(0x2096)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_INSULATION_ALARM_RECOVER, - new UnsignedWordElement(0x2097)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_VOLTAGE_DIFFERENCE_ALARM, - new UnsignedWordElement(0x2098)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_VOLTAGE_DIFFERENCE_ALARM_RECOVER, - new UnsignedWordElement(0x2099)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_TOTAL_VOLTAGE_DIFFERENCE_ALARM, - new UnsignedWordElement(0x209A), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_TOTAL_VOLTAGE_DIFFERENCE_ALARM_RECOVER, - new UnsignedWordElement(0x209B), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_DISCHARGE_TEMPERATURE_HIGH_ALARM, - new UnsignedWordElement(0x209C)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_DISCHARGE_TEMPERATURE_HIGH_ALARM_RECOVER, - new UnsignedWordElement(0x209D)), // - new DummyRegisterElement(0x209E), - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_DISCHARGE_TEMPERATURE_LOW_ALARM, - new UnsignedWordElement(0x209F)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_DISCHARGE_TEMPERATURE_LOW_ALARM_RECOVER, - new UnsignedWordElement(0x20A0)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_TEMPERATURE_DIFFERENCE_ALARM, - new UnsignedWordElement(0x20A1)), // - m(SingleRackVersionB.ChannelId.WARN_PARAMETER_TEMPERATURE_DIFFERENCE_ALARM_RECOVER, - new UnsignedWordElement(0x20A2)) // - ); + // Warn parameter + new FC16WriteRegistersTask(0x2080, // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_VOLTAGE_ALARM, + new UnsignedWordElement(0x2080)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_VOLTAGE_RECOVER, + new UnsignedWordElement(0x2081)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_OVER_VOLTAGE_ALARM, + new UnsignedWordElement(0x2082), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_OVER_VOLTAGE_RECOVER, + new UnsignedWordElement(0x2083), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_CHARGE_OVER_CURRENT_ALARM, + new UnsignedWordElement(0x2084), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_CHARGE_OVER_CURRENT_RECOVER, + new UnsignedWordElement(0x2085), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_VOLTAGE_ALARM, + new UnsignedWordElement(0x2086)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_VOLTAGE_RECOVER, + new UnsignedWordElement(0x2087)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_UNDER_VOLTAGE_ALARM, + new UnsignedWordElement(0x2088), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_UNDER_VOLTAGE_RECOVER, + new UnsignedWordElement(0x2089), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_DISCHARGE_OVER_CURRENT_ALARM, + new UnsignedWordElement(0x208A), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SYSTEM_DISCHARGE_OVER_CURRENT_RECOVER, + new UnsignedWordElement(0x208B), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_TEMPERATURE_ALARM, + new UnsignedWordElement(0x208C)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_OVER_TEMPERATURE_RECOVER, + new UnsignedWordElement(0x208D)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_TEMPERATURE_ALARM, + new UnsignedWordElement(0x208E)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_TEMPERATURE_RECOVER, + new UnsignedWordElement(0x208F)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SOC_LOW_ALARM, new UnsignedWordElement(0x2090)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SOC_LOW_ALARM_RECOVER, + new UnsignedWordElement(0x2091)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SOC_HIGH_ALARM, new UnsignedWordElement(0x2092)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_SOC_HIGH_ALARM_RECOVER, + new UnsignedWordElement(0x2093)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CONNECTOR_TEMPERATURE_HIGH_ALARM, + new UnsignedWordElement(0x2094)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CONNECTOR_TEMPERATURE_HIGH_ALARM_RECOVER, + new UnsignedWordElement(0x2095)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_INSULATION_ALARM, + new UnsignedWordElement(0x2096)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_INSULATION_ALARM_RECOVER, + new UnsignedWordElement(0x2097)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_VOLTAGE_DIFFERENCE_ALARM, + new UnsignedWordElement(0x2098)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_VOLTAGE_DIFFERENCE_ALARM_RECOVER, + new UnsignedWordElement(0x2099)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_TOTAL_VOLTAGE_DIFFERENCE_ALARM, + new UnsignedWordElement(0x209A), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_TOTAL_VOLTAGE_DIFFERENCE_ALARM_RECOVER, + new UnsignedWordElement(0x209B), ElementToChannelConverter.SCALE_FACTOR_2), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_DISCHARGE_TEMPERATURE_HIGH_ALARM, + new UnsignedWordElement(0x209C)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_DISCHARGE_TEMPERATURE_HIGH_ALARM_RECOVER, + new UnsignedWordElement(0x209D)), // + new DummyRegisterElement(0x209E), + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_DISCHARGE_TEMPERATURE_LOW_ALARM, + new UnsignedWordElement(0x209F)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_DISCHARGE_TEMPERATURE_LOW_ALARM_RECOVER, + new UnsignedWordElement(0x20A0)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_TEMPERATURE_DIFFERENCE_ALARM, + new UnsignedWordElement(0x20A1)), // + m(SingleRackVersionB.ChannelId.WARN_PARAMETER_TEMPERATURE_DIFFERENCE_ALARM_RECOVER, + new UnsignedWordElement(0x20A2)) // + )); + if (!this.config.ReduceTasks()) { // Stop parameter Task readStopParameters = new FC3ReadRegistersTask(0x2040, Priority.LOW, // m(SingleRackVersionB.ChannelId.STOP_PARAMETER_CELL_OVER_VOLTAGE_PROTECTION, @@ -918,8 +937,6 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { protocol.addTask(readStopParameters); protocol.addTask(readWarnParameters); - protocol.addTask(writeStopParameters); - protocol.addTask(writeWarnParameters); // Add tasks for cell voltages and temperatures according to the number of // slaves, one task per module is created diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ErrorHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ErrorHandler.java index fa6f641985b..16beb7d73bb 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ErrorHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ErrorHandler.java @@ -26,8 +26,6 @@ protected void onExit(Context context) throws OpenemsNamedException { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - System.out.println("Stuck in ERROR_HANDLING: " + context.component.getStateChannel().listStates()); - if (Duration.between(this.entryAt, Instant.now()).getSeconds() > context.config.errorLevel2Delay()) { ControlAndLogic.resetSystem(context.component); ControlAndLogic.sleepSystem(context.component); diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java index 00e55931b4f..4597ffdd48a 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java @@ -11,8 +11,7 @@ public class RunningHandler extends StateHandler { public static int refreshIntervalSeconds = 900; LocalDateTime refreshTime = null; - - + @Override protected void onExit(Context context) throws OpenemsNamedException { refreshTime = null; @@ -37,7 +36,7 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { // Mark as started context.component._setStartStop(StartStop.START); - + refreshBatteryValues(context); return State.RUNNING; @@ -45,16 +44,20 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { private void refreshBatteryValues(Context context) throws OpenemsNamedException { if (refreshTime.plusSeconds(refreshIntervalSeconds).isBefore(LocalDateTime.now())) { - refreshTime = LocalDateTime.now(); + refreshTime = LocalDateTime.now(); setBatteryValues(context); } - + } private void setBatteryValues(Context context) throws OpenemsNamedException { - - //TODO first step is only to check the values and if there is a difference show a warning - + + // TODO first step is only to check the values and if there is a difference show + // a warning + // TODO this should not be done only in Running, but tested on every cycle. It + // might be that, because of wrong values the battery does not start properly, + // which would look us out. + // // 0x2086 ==> 2800 // WriteChannel channel = context.component.channel(SingleRackVersionB.ChannelId.WARN_PARAMETER_CELL_UNDER_VOLTAGE_ALARM); // channel.setNextWriteValue(context.cellCharacteristic.getFinalCellDischargeVoltage_mV()); diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionCImpl.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionCImpl.java index 27f8305fa77..678e3479edd 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionCImpl.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionCImpl.java @@ -25,7 +25,6 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.edge.battery.api.Battery; import io.openems.edge.battery.soltaro.CellCharacteristic; -import io.openems.edge.battery.soltaro.SoltaroCellCharacteristic; import io.openems.edge.battery.soltaro.Util; import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionB; import io.openems.edge.battery.soltaro.single.versionc.statemachine.Context; @@ -59,10 +58,10 @@ name = "Bms.Soltaro.SingleRack.VersionC", // immediate = true, // configurationPolicy = ConfigurationPolicy.REQUIRE, // - property = { - EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // - EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // - }) + property = { // + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // + }) public class SingleRackVersionCImpl extends AbstractOpenemsModbusComponent implements SingleRackVersionC, Battery, OpenemsComponent, EventHandler, ModbusSlave, StartStoppable { @@ -77,27 +76,28 @@ public class SingleRackVersionCImpl extends AbstractOpenemsModbusComponent private final StateMachine stateMachine = new StateMachine(State.UNDEFINED); private Config config; - - // TODO Test cell characteristic, remove after test and replace it by correct ones + + // TODO Test cell characteristic, remove after test and replace it by correct + // ones private CellCharacteristic cellCharacteristic = new CellCharacteristic() { - + @Override public int getForceDischargeCellVoltage_mV() { // TODO Auto-generated method stub return 3_680; } - + @Override - public int getForceChargeCellVoltage_mV() { + public int getForceChargeCellVoltage_mV() { return 3_250; } - + @Override public int getFinalCellDischargeVoltage_mV() { // TODO Auto-generated method stub return 3_300; } - + @Override public int getFinalCellChargeVoltage_mV() { // TODO Auto-generated method stub @@ -154,13 +154,12 @@ public void handleEvent(Event event) { return; } switch (event.getTopic()) { - + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: - + this.setAllowedCurrents(); - + break; - case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: this.handleStateMachine(); @@ -169,15 +168,17 @@ public void handleEvent(Event event) { } private void setAllowedCurrents() { - IntegerReadChannel maxChargeCurrentChannel = this.channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_CHARGE_CURRENT); + IntegerReadChannel maxChargeCurrentChannel = this + .channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_CHARGE_CURRENT); int maxChargeCurrentFromBMS = maxChargeCurrentChannel.value().orElse(0) / 1000; - - IntegerReadChannel maxDischargeChannel = this.channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_DISCHARGE_CURRENT); + + IntegerReadChannel maxDischargeChannel = this + .channel(SingleRackVersionB.ChannelId.SYSTEM_MAX_DISCHARGE_CURRENT); int maxDischargeCurrentFromBMS = maxDischargeChannel.value().orElse(0) / 1000; - + Util.setMaxAllowedCurrents(cellCharacteristic, maxChargeCurrentFromBMS, maxDischargeCurrentFromBMS, this); } - + /** * Handles the State-Machine. */ diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/ErrorHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/ErrorHandler.java index b1b741705b5..f8017443c0e 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/ErrorHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/ErrorHandler.java @@ -72,8 +72,6 @@ protected void onExit(Context context) throws OpenemsNamedException { @Override public State runAndGetNextState(Context context) { - System.out.println("Stuck in ERROR_HANDLING: " + context.component.getStateChannel().listStates()); - if (Duration.between(this.entryAt, Instant.now()).getSeconds() > 120) { // Try again return State.UNDEFINED; diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java index 17e7e5fb06a..f762e7280d9 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java @@ -29,8 +29,6 @@ protected void onExit(Context context) throws OpenemsNamedException { @Override public State runAndGetNextState(Context context) { - System.out.println("Stuck in ERROR_HANDLING: " + context.component.getStateChannel().listStates()); - if (Duration.between(this.entryAt, Instant.now()).getSeconds() > 120) { // Try again return State.UNDEFINED; From 8897dea1716d5dce71ed514f9c5f03c1342c1fa7 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 11 Dec 2020 20:22:35 +0100 Subject: [PATCH 06/22] Generic-Ess: apply ramp for allowed charge/discharge power --- .../ess/generic/symmetric/ChannelManager.java | 71 ++++++++++--------- .../GenericManagedSymmetricEssImpl.java | 10 --- 2 files changed, 37 insertions(+), 44 deletions(-) diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java index 1056ef48b59..4a9e72c8582 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java @@ -21,6 +21,9 @@ public class ChannelManager extends AbstractChannelListenerManager { private final GenericManagedSymmetricEss parent; + private float lastAllowedChargePower = 0; + private float lastAllowedDischargePower = 0; + public ChannelManager(GenericManagedSymmetricEss parent) { this.parent = parent; } @@ -38,49 +41,48 @@ public void activate(Battery battery, ManagedSymmetricBatteryInverter batteryInv final Consumer> allowedChargeDischargeCallback = (value) -> { // TODO: find proper efficiency factor to calculate AC Charge/Discharge limits // from DC - final double efficiencyFactor = 0.95; + final float efficiencyFactor = 0.95F; Value chargeMaxCurrent = battery.getChargeMaxCurrentChannel().getNextValue(); Value dischargeMaxCurrent = battery.getDischargeMaxCurrentChannel().getNextValue(); Value voltage = battery.getVoltageChannel().getNextValue(); - if (voltage.isDefined() && dischargeMaxCurrent.isDefined() && chargeMaxCurrent.isDefined()) { + float allowedChargePower; + float allowedDischargePower; + + // If the GenericEss is not in State "STARTED" block ACTIVE and REACTIVE Power! + if (this.parent.isStarted() && voltage.isDefined() && dischargeMaxCurrent.isDefined() + && chargeMaxCurrent.isDefined()) { // efficiency factor is not considered in chargeMaxCurrent (DC Power > AC Power) - this.parent._setAllowedChargePower(// - (int) (chargeMaxCurrent.get() * voltage.get() * -1)); - this.parent._setAllowedDischargePower(// - (int) (dischargeMaxCurrent.get() * voltage.get() * efficiencyFactor)); + allowedChargePower = chargeMaxCurrent.get() * voltage.get() * -1; + allowedDischargePower = dischargeMaxCurrent.get() * voltage.get() * efficiencyFactor; + } else { - this.parent._setAllowedChargePower(0); - this.parent._setAllowedDischargePower(0); + allowedChargePower = 0; + allowedDischargePower = 0; + } + + // Make sure solution is feasible + if (allowedChargePower > allowedDischargePower) { // Force Discharge + allowedDischargePower = allowedChargePower; + } + if (allowedDischargePower < allowedChargePower) { // Force Charge + allowedChargePower = allowedDischargePower; } -// Value forceChargeCurrent = battery.getForceChargeCurrentChannel().getNextValue(); -// Value forceDischargeCurrent = battery.getForceDischargeCurrentChannel().getNextValue(); -// -// final int allowedChargePower; -// final int allowedDischargePower; -// -// if(!voltage.isDefined()) { -// allowedChargePower = 0; -// allowedDischargePower = 0; -// } else { -// if(forceChargeCurrent.isDefined() && forceChargeCurrent.get) { -// allowedDischargePower = forceChargeCurrent -// } -// } -// -// if (voltage.isDefined() && dischargeMaxCurrent.isDefined() && chargeMaxCurrent.isDefined()) { -// // efficiency factor is not considered in chargeMaxCurrent (DC Power > AC Power) -// this.parent._setAllowedChargePower(// -// (int) (chargeMaxCurrent.get() * voltage.get() * -1)); -// this.parent._setAllowedDischargePower(// -// (int) (dischargeMaxCurrent.get() * voltage.get() * efficiencyFactor)); -// } else { -// } - -// this.parent._setAllowedChargePower(allowedChargePower); -// this.parent._setAllowedDischargePower(allowedDischargePower); + // Allow max increase of 1 % + if (allowedDischargePower > lastAllowedDischargePower + allowedDischargePower * 0.01F) { + allowedDischargePower = lastAllowedDischargePower + allowedDischargePower * 0.01F; + } + ChannelManager.this.lastAllowedDischargePower = allowedDischargePower; + + if (allowedChargePower < lastAllowedChargePower + allowedChargePower * 0.01F) { + allowedChargePower = lastAllowedChargePower + allowedChargePower * 0.01F; + } + ChannelManager.this.lastAllowedChargePower = allowedChargePower; + + this.parent._setAllowedChargePower(Math.round(allowedChargePower)); + this.parent._setAllowedDischargePower(Math.round(allowedDischargePower)); }; this.addOnSetNextValueListener(battery, Battery.ChannelId.DISCHARGE_MIN_VOLTAGE, @@ -117,6 +119,7 @@ public void activate(Battery battery, ManagedSymmetricBatteryInverter batteryInv this.addCopyListener(batteryInverter, // SymmetricBatteryInverter.ChannelId.REACTIVE_POWER, // SymmetricEss.ChannelId.REACTIVE_POWER); + } /** diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEssImpl.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEssImpl.java index b1260a27e2e..caf658986c5 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEssImpl.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEssImpl.java @@ -37,10 +37,7 @@ import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; import io.openems.edge.ess.power.api.Constraint; -import io.openems.edge.ess.power.api.Phase; import io.openems.edge.ess.power.api.Power; -import io.openems.edge.ess.power.api.Pwr; -import io.openems.edge.ess.power.api.Relationship; @Designate(ocd = Config.class, factory = true) @Component(// @@ -207,13 +204,6 @@ public Constraint[] getStaticConstraints() throws OpenemsNamedException { result.add(this.power.createSimpleConstraint(c.description, this, c.phase, c.pwr, c.relationship, c.value)); } - // If the GenericEss is not in State "STARTED" block ACTIVE and REACTIVE Power! - if (!this.isStarted()) { - result.add(this.createPowerConstraint("ActivePower Constraint ESS not Started", Phase.ALL, Pwr.ACTIVE, - Relationship.EQUALS, 0)); - result.add(this.createPowerConstraint("ReactivePower Constraint ESS not Started", Phase.ALL, Pwr.REACTIVE, - Relationship.EQUALS, 0)); - } return result.toArray(new Constraint[result.size()]); } From b84188a918bb8a94fd7a8fcfb04a3bd4b0ed8981 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 11 Dec 2020 20:23:26 +0100 Subject: [PATCH 07/22] Battery-Protection: set "0" limit when no data is available --- .../io/openems/edge/battery/soltaro/Util.java | 98 ++++++++++--------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java index 858e9206330..58363a37f30 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java @@ -6,60 +6,62 @@ public class Util { public static final double CHARGE_DISCHARGE_FACTOR = 0.02; public static final int MINIMUM_CURRENT = 1; - + public static void setMaxAllowedCurrents(CellCharacteristic cellCharacteristic, int maxChargeCurrentFromBMS, int maxDischargeCurrentFromBMS, Battery battery) { - - - if (!areApiValuesPresent(battery)) { - return; - } - + int maxChargeCurrent = maxChargeCurrentFromBMS; int maxDischargeCurrent = maxDischargeCurrentFromBMS; - - if (isChargingAlready(battery)) { - if(isFurtherChargingNecessary(cellCharacteristic, battery)) { - maxDischargeCurrent = calculateForceDischargeCurrent(battery); - } - } - - if (isDischargingAlready(battery)) { - if(isFurtherDischargingNecessary(cellCharacteristic, battery)) { - maxChargeCurrent = calculateForceChargeCurrent(battery); - } - } - - if (isVoltageBelowFinalDischargingVoltage(cellCharacteristic, battery)) { - if (isVoltageHigherThanForceChargeVoltage(cellCharacteristic, battery)) { - maxDischargeCurrent = 0; - } else { - maxDischargeCurrent = calculateForceDischargeCurrent(battery); + + if (!areApiValuesPresent(battery)) { + maxChargeCurrent = 0; + maxDischargeCurrent = 0; + + } else { + + if (isChargingAlready(battery)) { + if (isFurtherChargingNecessary(cellCharacteristic, battery)) { + maxDischargeCurrent = calculateForceDischargeCurrent(battery); + } } - } - - if (isVoltageAboveFinalChargingVoltage(cellCharacteristic, battery)) { - if (isVoltageLowerThanForceDischargeVoltage(cellCharacteristic, battery)) { - maxChargeCurrent = 0; - } else { - maxChargeCurrent = calculateForceChargeCurrent(battery); + + if (isDischargingAlready(battery)) { + if (isFurtherDischargingNecessary(cellCharacteristic, battery)) { + maxChargeCurrent = calculateForceChargeCurrent(battery); + } + } + + if (isVoltageBelowFinalDischargingVoltage(cellCharacteristic, battery)) { + if (isVoltageHigherThanForceChargeVoltage(cellCharacteristic, battery)) { + maxDischargeCurrent = 0; + } else { + maxDischargeCurrent = calculateForceDischargeCurrent(battery); + } + } + + if (isVoltageAboveFinalChargingVoltage(cellCharacteristic, battery)) { + if (isVoltageLowerThanForceDischargeVoltage(cellCharacteristic, battery)) { + maxChargeCurrent = 0; + } else { + maxChargeCurrent = calculateForceChargeCurrent(battery); + } } } - + setChannelsForCharge(maxChargeCurrent, battery); setChannelsForDischarge(maxDischargeCurrent, battery); } - + protected static void setChannelsForDischarge(int maxDischargeCurrent, Battery battery) { battery._setDischargeMaxCurrent(maxDischargeCurrent); - + boolean forceChargeNecessary = maxDischargeCurrent < 0; battery._setForceChargeActive(forceChargeNecessary); } protected static void setChannelsForCharge(int maxChargeCurrent, Battery battery) { battery._setChargeMaxCurrent(maxChargeCurrent); - + boolean forceDischargeNecessary = maxChargeCurrent < 0; battery._setForceDischargeActive(forceDischargeNecessary); } @@ -69,7 +71,8 @@ protected static boolean isVoltageLowerThanForceDischargeVoltage(CellCharacteris return battery.getMaxCellVoltage().get() < cellCharacteristic.getForceDischargeCellVoltage_mV(); } - protected static boolean isVoltageAboveFinalChargingVoltage(CellCharacteristic cellCharacteristic, Battery battery) { + protected static boolean isVoltageAboveFinalChargingVoltage(CellCharacteristic cellCharacteristic, + Battery battery) { return battery.getMaxCellVoltage().get() > cellCharacteristic.getFinalCellChargeVoltage_mV(); } @@ -87,7 +90,8 @@ protected static boolean isFurtherDischargingNecessary(CellCharacteristic cellCh if (!battery.getForceDischargeActive().isDefined()) { return false; } - return (battery.getForceDischargeActive().get() && battery.getMaxCellVoltage().get() > cellCharacteristic.getFinalCellChargeVoltage_mV()); + return (battery.getForceDischargeActive().get() + && battery.getMaxCellVoltage().get() > cellCharacteristic.getFinalCellChargeVoltage_mV()); } protected static boolean isDischargingAlready(Battery battery) { @@ -97,25 +101,26 @@ protected static boolean isDischargingAlready(Battery battery) { protected static int calculateForceDischargeCurrent(Battery battery) { return calculateForceCurrent(battery); } - + protected static int calculateForceChargeCurrent(Battery battery) { return calculateForceCurrent(battery); } protected static int calculateForceCurrent(Battery battery) { - double capacity = battery.getCapacity().get(); + double capacity = battery.getCapacity().get(); double voltage = battery.getVoltage().get(); double power = capacity * CHARGE_DISCHARGE_FACTOR; double current = power / voltage; - int value = - (int) Math.max(MINIMUM_CURRENT, current); + int value = -(int) Math.max(MINIMUM_CURRENT, current); return value; } - + protected static boolean isFurtherChargingNecessary(CellCharacteristic cellCharacteristic, Battery battery) { if (!battery.getForceChargeActive().isDefined()) { return false; } - return battery.getForceChargeActive().get() && battery.getMinCellVoltage().get() < cellCharacteristic.getFinalCellDischargeVoltage_mV(); + return battery.getForceChargeActive().get() + && battery.getMinCellVoltage().get() < cellCharacteristic.getFinalCellDischargeVoltage_mV(); } protected static boolean isChargingAlready(Battery battery) { @@ -123,11 +128,8 @@ protected static boolean isChargingAlready(Battery battery) { } protected static boolean areApiValuesPresent(Battery battery) { - return - battery.getCapacity().isDefined() && - battery.getVoltage().isDefined() && - battery.getMinCellVoltage().isDefined() && - battery.getMaxCellVoltage().isDefined(); + return battery.getCapacity().isDefined() && battery.getVoltage().isDefined() + && battery.getMinCellVoltage().isDefined() && battery.getMaxCellVoltage().isDefined(); } } From 20c8fe0e83ad4e74d9dff7ea10ae3e2981cdff84 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 11 Dec 2020 20:25:17 +0100 Subject: [PATCH 08/22] Soltaro Single B: reduce retry attempts to avoid race condition with Generic-ESS --- .../statemachine/ControlAndLogic.java | 132 +++++++++++------- 1 file changed, 84 insertions(+), 48 deletions(-) diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ControlAndLogic.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ControlAndLogic.java index 233c451cb17..0a501258f6d 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ControlAndLogic.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ControlAndLogic.java @@ -14,9 +14,8 @@ public class ControlAndLogic { private static final Integer SYSTEM_RESET = 0x1; private static final Integer SLEEP = 0x1; protected static final int RETRY_COMMAND_SECONDS = 30; - protected static final int RETRY_COMMAND_MAX_ATTEMPTS = 30; + protected static final int RETRY_COMMAND_MAX_ATTEMPTS = 10; - protected static void stopSystem(SingleRackVersionB singleRackVersionB) throws OpenemsNamedException { // To avoid hardware damages do not send stop command if system has already // stopped @@ -24,15 +23,16 @@ protected static void stopSystem(SingleRackVersionB singleRackVersionB) throws O singleRackVersionB.setContactorControl(ContactorControl.CUT_OFF); } } - + protected static void startSystem(SingleRackVersionB singleRackVersionB) throws OpenemsNamedException { // To avoid hardware damages do not send start command if system has already // started - if (singleRackVersionB.getContactorControl() != ContactorControl.ON_GRID && singleRackVersionB.getContactorControl() != ContactorControl.CONNECTION_INITIATING) { + if (singleRackVersionB.getContactorControl() != ContactorControl.ON_GRID + && singleRackVersionB.getContactorControl() != ContactorControl.CONNECTION_INITIATING) { singleRackVersionB.setContactorControl(ContactorControl.CONNECTION_INITIATING); } } - + protected static void resetSystem(SingleRackVersionB singleRackVersionB) throws OpenemsNamedException { singleRackVersionB.setSystemReset(SYSTEM_RESET); } @@ -40,97 +40,133 @@ protected static void resetSystem(SingleRackVersionB singleRackVersionB) throws protected static void sleepSystem(SingleRackVersionB singleRackVersionB) throws OpenemsNamedException { singleRackVersionB.setSleep(SLEEP); } - - protected static boolean isSystemRunning(SingleRackVersionB singleRackVersionB) { + + protected static boolean isSystemRunning(SingleRackVersionB singleRackVersionB) { return singleRackVersionB.getContactorControl() == ContactorControl.ON_GRID; } protected static boolean isSystemStopped(SingleRackVersionB singleRackVersionB) { return singleRackVersionB.getContactorControl() == ContactorControl.CUT_OFF; } - + protected static boolean hasError(SingleRackVersionB singleRackVersionB, int numberOfSlaves) { return isAlarmLevel2Error(singleRackVersionB) || isSlaveCommunicationError(singleRackVersionB, numberOfSlaves); } - + private static boolean isAlarmLevel2Error(SingleRackVersionB singleRackVersionB) { - return (readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_VOLTAGE_HIGH) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_TOTAL_VOLTAGE_HIGH) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CHA_CURRENT_HIGH) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_VOLTAGE_LOW) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_TOTAL_VOLTAGE_LOW) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_DISCHA_CURRENT_HIGH) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_CHA_TEMP_LOW) + return (readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_VOLTAGE_HIGH) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_TOTAL_VOLTAGE_HIGH) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CHA_CURRENT_HIGH) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_VOLTAGE_LOW) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_TOTAL_VOLTAGE_LOW) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_DISCHA_CURRENT_HIGH) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_CHA_TEMP_LOW) || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_SOC_LOW) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_TEMPERATURE_DIFFERENCE_HIGH) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_POLES_TEMPERATURE_DIFFERENCE_HIGH) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_VOLTAGE_DIFFERENCE_HIGH) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_INSULATION_LOW) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_TOTAL_VOLTAGE_DIFFERENCE_HIGH) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH) - || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW)); + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_TEMPERATURE_DIFFERENCE_HIGH) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_POLES_TEMPERATURE_DIFFERENCE_HIGH) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_VOLTAGE_DIFFERENCE_HIGH) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_INSULATION_LOW) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_TOTAL_VOLTAGE_DIFFERENCE_HIGH) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH) + || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW)); } private static boolean isSlaveCommunicationError(SingleRackVersionB singleRackVersionB, int numberOfSlaves) { boolean b = false; switch (numberOfSlaves) { case 20: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_20_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_20_COMMUNICATION_ERROR); case 19: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_19_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_19_COMMUNICATION_ERROR); case 18: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_18_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_18_COMMUNICATION_ERROR); case 17: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_17_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_17_COMMUNICATION_ERROR); case 16: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_16_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_16_COMMUNICATION_ERROR); case 15: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_15_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_15_COMMUNICATION_ERROR); case 14: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_14_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_14_COMMUNICATION_ERROR); case 13: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_13_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_13_COMMUNICATION_ERROR); case 12: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_12_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_12_COMMUNICATION_ERROR); case 11: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_11_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_11_COMMUNICATION_ERROR); case 10: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_10_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_10_COMMUNICATION_ERROR); case 9: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_9_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_9_COMMUNICATION_ERROR); case 8: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_8_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_8_COMMUNICATION_ERROR); case 7: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_7_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_7_COMMUNICATION_ERROR); case 6: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_6_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_6_COMMUNICATION_ERROR); case 5: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_5_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_5_COMMUNICATION_ERROR); case 4: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_4_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_4_COMMUNICATION_ERROR); case 3: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_3_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_3_COMMUNICATION_ERROR); case 2: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_2_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_2_COMMUNICATION_ERROR); case 1: - b = b || readValueFromBooleanChannel(singleRackVersionB, SingleRackVersionB.ChannelId.SLAVE_1_COMMUNICATION_ERROR); + b = b || readValueFromBooleanChannel(singleRackVersionB, + SingleRackVersionB.ChannelId.SLAVE_1_COMMUNICATION_ERROR); } return b; } - - private static boolean readValueFromBooleanChannel(OpenemsComponent component, SingleRackVersionB.ChannelId singleRackChannelId) { + + private static boolean readValueFromBooleanChannel(OpenemsComponent component, + SingleRackVersionB.ChannelId singleRackChannelId) { StateChannel r = component.channel(singleRackChannelId); Optional bOpt = r.value().asOptional(); return bOpt.isPresent() && bOpt.get(); } - + public static void setCapacity(SingleRackVersionB singleRackVersionB, Config config) { int capacity = config.numberOfSlaves() * config.moduleType().getCapacity_Wh(); singleRackVersionB._setCapacity(capacity); } - + public static void setWatchdog(SingleRackVersionB singleRackVersionB, int time_seconds) { try { singleRackVersionB.setWatchdog(time_seconds); From c819a5e41a2706d2d8b24df3f0fbc5f294d2b830 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 11 Dec 2020 20:26:02 +0100 Subject: [PATCH 09/22] KACO battery inverter: do not set possibly negative charge/discharge current --- .../blueplanetgridsave/KacoBlueplanetGridsaveImpl.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoBlueplanetGridsaveImpl.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoBlueplanetGridsaveImpl.java index 2803ca5cad5..fb1719558a0 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoBlueplanetGridsaveImpl.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoBlueplanetGridsaveImpl.java @@ -188,7 +188,7 @@ public void run(Battery battery, int setActivePower, int setReactivePower) throw if (this.config.activateWatchdog()) { // Trigger the Watchdog this.triggerWatchdog(); - } + } // Set State-Channels this.setStateChannels(); @@ -248,12 +248,14 @@ private void setBatteryLimits(Battery battery) throws OpenemsNamedException { chaMaxVChannel.setNextWriteValue(chargeMaxVoltage); // Discharge Max Current + // negative value is corrected as zero IntegerWriteChannel disMaxAChannel = this.getSunSpecChannelOrError(KacoSunSpecModel.S64202.DIS_MAX_A_0); - disMaxAChannel.setNextWriteValue(battery.getDischargeMaxCurrent().get()); + disMaxAChannel.setNextWriteValue(Math.max(0, battery.getDischargeMaxCurrent().orElse(0))); // Charge Max Current + // negative value is corrected as zero IntegerWriteChannel chaMaxAChannel = this.getSunSpecChannelOrError(KacoSunSpecModel.S64202.CHA_MAX_A_0); - chaMaxAChannel.setNextWriteValue(battery.getChargeMaxCurrent().get()); + chaMaxAChannel.setNextWriteValue(Math.max(0, battery.getChargeMaxCurrent().orElse(0))); // Activate Battery values EnumWriteChannel enLimitChannel = this.getSunSpecChannelOrError(KacoSunSpecModel.S64202.EN_LIMIT_0); @@ -469,7 +471,6 @@ private void calculateEnergy() { public Timedata getTimedata() { return this.timedata; } - protected void addBlock(int startAddress, SunSpecModel model, Priority priority) throws OpenemsException { super.addBlock(startAddress, model, priority); From 5ba1a2c6f46727dbb8aae6291d196248744f54e7 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 11 Dec 2020 20:26:49 +0100 Subject: [PATCH 10/22] ManagedSymmetricEss: avoid "Given LowLimit is higher than HighLimit" exception on rounding error --- .../src/io/openems/edge/ess/api/ManagedSymmetricEss.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java index 145e13c1f61..535e54ccabf 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java @@ -93,6 +93,9 @@ public void accept(Channel channel) { // configure PID filter int minPower = power.getMinPower(ess, Phase.ALL, Pwr.ACTIVE); int maxPower = power.getMaxPower(ess, Phase.ALL, Pwr.ACTIVE); + if (maxPower < minPower) { + maxPower = minPower; // avoid rounding error + } pidFilter.setLimits(minPower, maxPower); int currentActivePower = ess.getActivePower().orElse(0); From dc97bc34b9e0968bb2383f410f0925e07f16c2df Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 14 Dec 2020 13:50:28 +0100 Subject: [PATCH 11/22] Improve Logging in StateMachines - Add AbstractContext that takes a parent Component and handles logging - Update all State-Machines accordingly --- .../bydcommercial/statemachine/Context.java | 10 +- .../statemachine/ErrorHandler.java | 9 +- .../statemachine/GoConfigurationHandler.java | 15 -- .../statemachine/GoRunningHandler.java | 11 +- .../statemachine/GoStoppedHandler.java | 8 +- .../statemachine/RunningHandler.java | 9 +- .../statemachine/StateMachine.java | 6 +- .../statemachine/StoppedHandler.java | 5 +- .../statemachine/UndefinedHandler.java | 7 +- .../fenecon/home/statemachine/Context.java | 10 +- .../home/statemachine/GoRunningHandler.java | 4 +- .../home/statemachine/GoStoppedHandler.java | 2 +- .../home/statemachine/RunningHandler.java | 9 +- .../home/statemachine/UndefinedHandler.java | 7 +- .../versionc/statemachine/Context.java | 10 +- .../versionc/statemachine/ErrorHandler.java | 9 +- .../statemachine/GoRunningHandler.java | 15 +- .../statemachine/GoStoppedHandler.java | 10 +- .../versionc/statemachine/RunningHandler.java | 9 +- .../versionc/statemachine/StoppedHandler.java | 5 +- .../statemachine/UndefinedHandler.java | 7 +- .../single/versionb/statemachine/Context.java | 11 +- .../versionb/statemachine/ErrorHandler.java | 12 +- .../statemachine/GoRunningHandler.java | 18 +- .../statemachine/GoStoppedHandler.java | 8 +- .../versionb/statemachine/RunningHandler.java | 13 +- .../versionb/statemachine/StoppedHandler.java | 9 +- .../statemachine/UndefinedHandler.java | 7 +- .../single/versionc/statemachine/Context.java | 10 +- .../versionc/statemachine/ErrorHandler.java | 9 +- .../statemachine/GoConfigurationHandler.java | 232 ------------------ .../statemachine/GoRunningHandler.java | 11 +- .../statemachine/GoStoppedHandler.java | 8 +- .../versionc/statemachine/RunningHandler.java | 9 +- .../versionc/statemachine/StateMachine.java | 4 - .../versionc/statemachine/StoppedHandler.java | 4 +- .../statemachine/UndefinedHandler.java | 6 +- .../statemachine/Context.java | 9 +- .../statemachine/ErrorHandler.java | 6 +- .../statemachine/GoRunningHandler.java | 13 +- .../statemachine/GoStoppedHandler.java | 8 +- .../statemachine/RunningHandler.java | 16 +- .../statemachine/StoppedHandler.java | 4 +- .../statemachine/UndefinedHandler.java | 7 +- .../refu88k/statemachine/Context.java | 11 +- .../refu88k/statemachine/ErrorHandler.java | 6 +- .../statemachine/GoRunningHandler.java | 19 +- .../statemachine/GoStoppedHandler.java | 6 +- .../refu88k/statemachine/RunningHandler.java | 26 +- .../refu88k/statemachine/StoppedHandler.java | 9 +- .../statemachine/UndefinedHandler.java | 7 +- .../common/statemachine/AbstractContext.java | 69 ++++++ .../statemachine/AbstractStateMachine.java | 2 +- .../symmetric/statemachine/Context.java | 12 +- .../symmetric/statemachine/ErrorHandler.java | 7 +- .../statemachine/StartBatteryHandler.java | 7 +- .../StartBatteryInverterHandler.java | 7 +- .../statemachine/StartedHandler.java | 7 +- .../statemachine/StopBatteryHandler.java | 7 +- .../StopBatteryInverterHandler.java | 7 +- .../statemachine/StoppedHandler.java | 7 +- .../statemachine/UndefinedHandler.java | 6 +- .../ActivateDebugMode1Handler.java | 9 +- .../ActivateDebugMode2Handler.java | 11 +- .../ActivateDebugMode3Handler.java | 11 +- .../ActivateDebugMode4Handler.java | 9 +- .../ActivateEconomicMode1Handler.java | 9 +- .../ActivateEconomicMode2Handler.java | 13 +- .../ActivateEconomicMode3Handler.java | 11 +- .../ActivateEconomicMode4Handler.java | 9 +- .../mini/ess/statemachine/Context.java | 9 +- .../statemachine/GoReadonlyModeHandler.java | 5 +- .../ess/statemachine/GoWriteModeHandler.java | 13 +- .../ess/statemachine/UndefinedHandler.java | 15 +- .../ess/statemachine/WriteModeHandler.java | 25 +- .../edge/goodwe/ess/applypower/Context.java | 9 +- 76 files changed, 484 insertions(+), 507 deletions(-) delete mode 100644 io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoConfigurationHandler.java delete mode 100644 io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoConfigurationHandler.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractContext.java diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/Context.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/Context.java index cacdaf3f0fe..6cd4ca0d946 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/Context.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/Context.java @@ -2,14 +2,14 @@ import io.openems.edge.battery.bydcommercial.BatteryBoxC130; import io.openems.edge.battery.bydcommercial.Config; +import io.openems.edge.common.statemachine.AbstractContext; + +public class Context extends AbstractContext { -public class Context { - protected final BatteryBoxC130 component; protected final Config config; - public Context(BatteryBoxC130 component, Config config) { - super(); - this.component = component; + public Context(BatteryBoxC130 parent, Config config) { + super(parent); this.config = config; } } \ No newline at end of file diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java index da51d913985..128aff5e044 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.bydcommercial.BatteryBoxC130; import io.openems.edge.battery.bydcommercial.PowerCircuitControl; import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -17,13 +18,15 @@ protected void onEntry(Context context) throws OpenemsNamedException { this.entryAt = Instant.now(); // Try to stop system - context.component._setPowerCircuitControl(PowerCircuitControl.SWITCH_OFF); + BatteryBoxC130 battery = context.getParent(); + battery._setPowerCircuitControl(PowerCircuitControl.SWITCH_OFF); } @Override protected void onExit(Context context) throws OpenemsNamedException { - context.component._setMaxStartAttempts(false); - context.component._setMaxStopAttempts(false); + BatteryBoxC130 battery = context.getParent(); + battery._setMaxStartAttempts(false); + battery._setMaxStopAttempts(false); } @Override diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoConfigurationHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoConfigurationHandler.java deleted file mode 100644 index 7c4af03d87e..00000000000 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoConfigurationHandler.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.openems.edge.battery.bydcommercial.statemachine; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State; -import io.openems.edge.common.statemachine.StateHandler; - -public class GoConfigurationHandler extends StateHandler { - - @Override - public State runAndGetNextState(Context context) throws OpenemsNamedException { - System.out.println("Stuck in GO_CONFIGURATION"); - return State.GO_CONFIGURATION; - } - -} diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoRunningHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoRunningHandler.java index be39012e9ff..2749c7a139f 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoRunningHandler.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoRunningHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.bydcommercial.BatteryBoxC130; import io.openems.edge.battery.bydcommercial.PowerCircuitControl; import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State; import io.openems.edge.battery.bydcommercial.utils.Constants; @@ -18,12 +19,14 @@ public class GoRunningHandler extends StateHandler { protected void onEntry(Context context) throws OpenemsNamedException { this.lastAttempt = Instant.MIN; this.attemptCounter = 0; - context.component._setMaxStartAttempts(false); + BatteryBoxC130 battery = context.getParent(); + battery._setMaxStartAttempts(false); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - PowerCircuitControl preChargeControl = context.component.getPowerCircuitControl(); + BatteryBoxC130 battery = context.getParent(); + PowerCircuitControl preChargeControl = battery.getPowerCircuitControl(); if (preChargeControl == PowerCircuitControl.SWITCH_ON) { return State.RUNNING; @@ -36,12 +39,12 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > Constants.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxStartAttempts(true); + battery._setMaxStartAttempts(true); return State.UNDEFINED; } else { // Trying to switch on - context.component.setPowerCircuitControl(PowerCircuitControl.PRE_CHARGING_1); + battery.setPowerCircuitControl(PowerCircuitControl.PRE_CHARGING_1); this.lastAttempt = Instant.now(); this.attemptCounter++; return State.GO_RUNNING; diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoStoppedHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoStoppedHandler.java index 0511284621c..d098476130e 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoStoppedHandler.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoStoppedHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.bydcommercial.BatteryBoxC130; import io.openems.edge.battery.bydcommercial.PowerCircuitControl; import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State; import io.openems.edge.battery.bydcommercial.utils.Constants; @@ -22,7 +23,8 @@ protected void onEntry(Context context) { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - PowerCircuitControl powerCircuitControl = context.component.getPowerCircuitControl(); + BatteryBoxC130 battery = context.getParent(); + PowerCircuitControl powerCircuitControl = battery.getPowerCircuitControl(); if (powerCircuitControl == PowerCircuitControl.SWITCH_OFF) { return State.STOPPED; @@ -35,12 +37,12 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > Constants.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxStopAttempts(true); + battery._setMaxStopAttempts(true); return State.UNDEFINED; } else { // Trying to switch off - context.component.setPowerCircuitControl(PowerCircuitControl.SWITCH_OFF); + battery.setPowerCircuitControl(PowerCircuitControl.SWITCH_OFF); this.lastAttempt = Instant.now(); this.attemptCounter++; return State.GO_STOPPED; diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/RunningHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/RunningHandler.java index 4d2441640ea..c972ce01189 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/RunningHandler.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/RunningHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.bydcommercial.statemachine; +import io.openems.edge.battery.bydcommercial.BatteryBoxC130; import io.openems.edge.battery.bydcommercial.PowerCircuitControl; import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State; import io.openems.edge.common.startstop.StartStop; @@ -9,16 +10,18 @@ public class RunningHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - if (context.component.hasFaults()) { + BatteryBoxC130 battery = context.getParent(); + + if (battery.hasFaults()) { return State.UNDEFINED; } - if (context.component.getPowerCircuitControl() != PowerCircuitControl.SWITCH_ON) { + if (battery.getPowerCircuitControl() != PowerCircuitControl.SWITCH_ON) { return State.UNDEFINED; } // Mark as started - context.component._setStartStop(StartStop.START); + battery._setStartStop(StartStop.START); return State.RUNNING; } diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/StateMachine.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/StateMachine.java index a522a85a16c..a226ff7389b 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/StateMachine.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/StateMachine.java @@ -15,9 +15,7 @@ public enum State implements io.openems.edge.common.statemachine.State, O GO_STOPPED(20), // STOPPED(21), // - ERROR(30), // - - GO_CONFIGURATION(40), // + ERROR(30) // ; private final int value; @@ -66,8 +64,6 @@ public StateHandler getStateHandler(State state) { return new StoppedHandler(); case ERROR: return new ErrorHandler(); - case GO_CONFIGURATION: - return new GoConfigurationHandler(); } throw new IllegalArgumentException("Unknown State [" + state + "]"); } diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/StoppedHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/StoppedHandler.java index d1260fac094..ff0a0f7dfa7 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/StoppedHandler.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/StoppedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.bydcommercial.statemachine; +import io.openems.edge.battery.bydcommercial.BatteryBoxC130; import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; @@ -7,8 +8,10 @@ public class StoppedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { + BatteryBoxC130 battery = context.getParent(); + // Mark as stopped - context.component._setStartStop(StartStop.STOP); + battery._setStartStop(StartStop.STOP); return State.STOPPED; } diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/UndefinedHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/UndefinedHandler.java index 5919af76b98..3e4901afe8c 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/UndefinedHandler.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/UndefinedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.bydcommercial.statemachine; +import io.openems.edge.battery.bydcommercial.BatteryBoxC130; import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -7,14 +8,16 @@ public class UndefinedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - switch (context.component.getStartStopTarget()) { + BatteryBoxC130 battery = context.getParent(); + + switch (battery.getStartStopTarget()) { case UNDEFINED: // Stuck in UNDEFINED State return State.UNDEFINED; case START: // force START - if (context.component.hasFaults()) { + if (battery.hasFaults()) { // Has Faults -> error handling return State.ERROR; } else { diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/Context.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/Context.java index 77ec9b6d5ac..9d4461f7a8f 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/Context.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/Context.java @@ -1,12 +1,12 @@ package io.openems.edge.battery.fenecon.home.statemachine; import io.openems.edge.battery.fenecon.home.FeneconHomeBattery; +import io.openems.edge.common.statemachine.AbstractContext; -public class Context { - protected final FeneconHomeBattery component; +public class Context extends AbstractContext { - public Context(FeneconHomeBattery component) { - super(); - this.component = component; + public Context(FeneconHomeBattery parent) { + super(parent); } + } \ No newline at end of file diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoRunningHandler.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoRunningHandler.java index dbf956bdf8c..e9ddd1ffdf1 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoRunningHandler.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoRunningHandler.java @@ -1,6 +1,7 @@ package io.openems.edge.battery.fenecon.home.statemachine; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.fenecon.home.FeneconHomeBattery; import io.openems.edge.battery.fenecon.home.enums.BmsControl; import io.openems.edge.battery.fenecon.home.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -9,7 +10,8 @@ public class GoRunningHandler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - BmsControl bmsControl = context.component.getBmsControl(); + FeneconHomeBattery battery = context.getParent(); + BmsControl bmsControl = battery.getBmsControl(); // We can no nothing but wait... if (bmsControl == BmsControl.SWITCHED_ON) { diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java index c0a0bf7cbea..983fc889aa2 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java @@ -12,7 +12,7 @@ public class GoStoppedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - this.log.warn("Stopping a FENECON Home Battery is not supported"); + context.logWarn(this.log, "Stopping a FENECON Home Battery is not supported"); return State.GO_STOPPED; } diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/RunningHandler.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/RunningHandler.java index fc79a9cfe35..628b7d7808f 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/RunningHandler.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/RunningHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.fenecon.home.statemachine; +import io.openems.edge.battery.fenecon.home.FeneconHomeBattery; import io.openems.edge.battery.fenecon.home.enums.BmsControl; import io.openems.edge.battery.fenecon.home.statemachine.StateMachine.State; import io.openems.edge.common.startstop.StartStop; @@ -9,16 +10,18 @@ public class RunningHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - if (context.component.hasFaults()) { + FeneconHomeBattery battery = context.getParent(); + + if (battery.hasFaults()) { return State.UNDEFINED; } - if (context.component.getBmsControl() != BmsControl.SWITCHED_ON) { + if (battery.getBmsControl() != BmsControl.SWITCHED_ON) { return State.UNDEFINED; } // Mark as started - context.component._setStartStop(StartStop.START); + battery._setStartStop(StartStop.START); return State.RUNNING; } diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/UndefinedHandler.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/UndefinedHandler.java index 0317945be67..3f60e03e29a 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/UndefinedHandler.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/UndefinedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.fenecon.home.statemachine; +import io.openems.edge.battery.fenecon.home.FeneconHomeBattery; import io.openems.edge.battery.fenecon.home.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -7,14 +8,16 @@ public class UndefinedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - switch (context.component.getStartStopTarget()) { + FeneconHomeBattery battery = context.getParent(); + + switch (battery.getStartStopTarget()) { case UNDEFINED: // Stuck in UNDEFINED State return State.UNDEFINED; case START: // force START - if (context.component.hasFaults()) { + if (battery.hasFaults()) { // Has Faults -> error handling return State.ERROR; } else { diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/Context.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/Context.java index 39f97be4250..f3e2da5abfc 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/Context.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/Context.java @@ -2,14 +2,14 @@ import io.openems.edge.battery.soltaro.cluster.versionc.ClusterVersionC; import io.openems.edge.battery.soltaro.cluster.versionc.Config; +import io.openems.edge.common.statemachine.AbstractContext; + +public class Context extends AbstractContext { -public class Context { - protected final ClusterVersionC component; protected final Config config; - public Context(ClusterVersionC component, Config config) { - super(); - this.component = component; + public Context(ClusterVersionC parent, Config config) { + super(parent); this.config = config; } } \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/ErrorHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/ErrorHandler.java index 2cdbdee14e3..a895ac88a8f 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/ErrorHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/ErrorHandler.java @@ -5,6 +5,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.battery.soltaro.cluster.enums.ClusterStartStop; +import io.openems.edge.battery.soltaro.cluster.versionc.ClusterVersionC; import io.openems.edge.battery.soltaro.cluster.versionc.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -17,13 +18,15 @@ protected void onEntry(Context context) throws OpenemsNamedException { this.entryAt = Instant.now(); // Try to stop system - context.component.setClusterStartStop(ClusterStartStop.STOP); + ClusterVersionC battery = context.getParent(); + battery.setClusterStartStop(ClusterStartStop.STOP); } @Override protected void onExit(Context context) throws OpenemsNamedException { - context.component._setMaxStartAttempts(false); - context.component._setMaxStopAttempts(false); + ClusterVersionC battery = context.getParent(); + battery._setMaxStartAttempts(false); + battery._setMaxStopAttempts(false); } @Override diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/GoRunningHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/GoRunningHandler.java index f9be9edf04a..03803a57cf8 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/GoRunningHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/GoRunningHandler.java @@ -8,6 +8,7 @@ import io.openems.edge.battery.soltaro.cluster.enums.ClusterStartStop; import io.openems.edge.battery.soltaro.cluster.enums.Rack; import io.openems.edge.battery.soltaro.cluster.enums.RackUsage; +import io.openems.edge.battery.soltaro.cluster.versionc.ClusterVersionC; import io.openems.edge.battery.soltaro.cluster.versionc.statemachine.StateMachine.State; import io.openems.edge.battery.soltaro.single.versionc.enums.PreChargeControl; import io.openems.edge.battery.soltaro.versionc.utils.Constants; @@ -23,12 +24,14 @@ public class GoRunningHandler extends StateHandler { protected void onEntry(Context context) throws OpenemsNamedException { this.lastAttempt = Instant.MIN; this.attemptCounter = 0; - context.component._setMaxStartAttempts(false); + ClusterVersionC battery = context.getParent(); + battery._setMaxStartAttempts(false); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - PreChargeControl commonPreChargeControl = context.component.getCommonPreChargeControl() + ClusterVersionC battery = context.getParent(); + PreChargeControl commonPreChargeControl = battery.getCommonPreChargeControl() .orElse(PreChargeControl.UNDEFINED); if (commonPreChargeControl == PreChargeControl.RUNNING) { return State.RUNNING; @@ -41,17 +44,17 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > Constants.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxStartAttempts(true); + battery._setMaxStartAttempts(true); return State.UNDEFINED; } else { // Trying to switch on - context.component.setClusterStartStop(ClusterStartStop.START); + battery.setClusterStartStop(ClusterStartStop.START); // Set the active racks as 'USED', set the others as 'UNUSED' - Set activeRacks = context.component.getRacks(); + Set activeRacks = battery.getRacks(); for (Rack rack : Rack.values()) { - EnumWriteChannel rackUsageChannel = context.component.channel(rack.usageChannelId); + EnumWriteChannel rackUsageChannel = battery.channel(rack.usageChannelId); if (activeRacks.contains(rack)) { rackUsageChannel.setNextWriteValue(RackUsage.USED); } else { diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/GoStoppedHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/GoStoppedHandler.java index ff7089a7ef8..95a45604521 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/GoStoppedHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/GoStoppedHandler.java @@ -7,6 +7,7 @@ import io.openems.edge.battery.soltaro.cluster.enums.ClusterStartStop; import io.openems.edge.battery.soltaro.cluster.enums.Rack; import io.openems.edge.battery.soltaro.cluster.enums.RackUsage; +import io.openems.edge.battery.soltaro.cluster.versionc.ClusterVersionC; import io.openems.edge.battery.soltaro.cluster.versionc.statemachine.StateMachine.State; import io.openems.edge.battery.soltaro.single.versionc.enums.PreChargeControl; import io.openems.edge.battery.soltaro.versionc.utils.Constants; @@ -26,7 +27,8 @@ protected void onEntry(Context context) { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - PreChargeControl commonPreChargeControl = context.component.getCommonPreChargeControl() + ClusterVersionC battery = context.getParent(); + PreChargeControl commonPreChargeControl = battery.getCommonPreChargeControl() .orElse(PreChargeControl.UNDEFINED); if (commonPreChargeControl == PreChargeControl.SWITCH_OFF) { return State.STOPPED; @@ -39,14 +41,14 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > Constants.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxStopAttempts(true); + battery._setMaxStopAttempts(true); return State.UNDEFINED; } else { // Trying to switch off - context.component.setClusterStartStop(ClusterStartStop.STOP); + battery.setClusterStartStop(ClusterStartStop.STOP); for (Rack rack : Rack.values()) { - EnumWriteChannel rackUsageChannel = context.component.channel(rack.usageChannelId); + EnumWriteChannel rackUsageChannel = battery.channel(rack.usageChannelId); rackUsageChannel.setNextWriteValue(RackUsage.UNUSED); } this.lastAttempt = Instant.now(); diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/RunningHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/RunningHandler.java index 483fd7deaf1..cfe76946d99 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/RunningHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/RunningHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.soltaro.cluster.versionc.statemachine; +import io.openems.edge.battery.soltaro.cluster.versionc.ClusterVersionC; import io.openems.edge.battery.soltaro.cluster.versionc.statemachine.StateMachine.State; import io.openems.edge.battery.soltaro.single.versionc.enums.PreChargeControl; import io.openems.edge.common.startstop.StartStop; @@ -9,17 +10,19 @@ public class RunningHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - if (context.component.hasFaults()) { + ClusterVersionC battery = context.getParent(); + + if (battery.hasFaults()) { return State.UNDEFINED; } - PreChargeControl commonPreChargeControl = context.component.getCommonPreChargeControl() + PreChargeControl commonPreChargeControl = battery.getCommonPreChargeControl() .orElse(PreChargeControl.UNDEFINED); if (commonPreChargeControl != PreChargeControl.RUNNING) { return State.UNDEFINED; } - context.component._setStartStop(StartStop.START); + battery._setStartStop(StartStop.START); return State.RUNNING; } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/StoppedHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/StoppedHandler.java index 2d8959baaae..f2733fec72a 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/StoppedHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/StoppedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.soltaro.cluster.versionc.statemachine; +import io.openems.edge.battery.soltaro.cluster.versionc.ClusterVersionC; import io.openems.edge.battery.soltaro.cluster.versionc.statemachine.StateMachine.State; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; @@ -8,8 +9,10 @@ public class StoppedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { + ClusterVersionC battery = context.getParent(); + // Mark as stopped - context.component._setStartStop(StartStop.STOP); + battery._setStartStop(StartStop.STOP); return State.STOPPED; } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/UndefinedHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/UndefinedHandler.java index 4c5c4aa9dd8..6fe6a610cd5 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/UndefinedHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/statemachine/UndefinedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.soltaro.cluster.versionc.statemachine; +import io.openems.edge.battery.soltaro.cluster.versionc.ClusterVersionC; import io.openems.edge.battery.soltaro.cluster.versionc.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -7,14 +8,16 @@ public class UndefinedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - switch (context.component.getStartStopTarget()) { + ClusterVersionC battery = context.getParent(); + + switch (battery.getStartStopTarget()) { case UNDEFINED: // Stuck in UNDEFINED State return State.UNDEFINED; case START: // force START - if (context.component.hasFaults()) { + if (battery.hasFaults()) { // Has Faults -> error handling return State.ERROR; } else { diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/Context.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/Context.java index ad732ee9b5d..8734c9077df 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/Context.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/Context.java @@ -3,16 +3,17 @@ import io.openems.edge.battery.soltaro.CellCharacteristic; import io.openems.edge.battery.soltaro.single.versionb.Config; import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionBImpl; +import io.openems.edge.common.statemachine.AbstractContext; + +public class Context extends AbstractContext { -public class Context { - protected final SingleRackVersionBImpl component; protected final Config config; protected final CellCharacteristic cellCharacteristic; - public Context(SingleRackVersionBImpl component, Config config, CellCharacteristic cellCharacteristic) { - super(); - this.component = component; + public Context(SingleRackVersionBImpl parent, Config config, CellCharacteristic cellCharacteristic) { + super(parent); this.config = config; this.cellCharacteristic = cellCharacteristic; } + } \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ErrorHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ErrorHandler.java index 16beb7d73bb..13f5e2d3849 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ErrorHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/ErrorHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionBImpl; import io.openems.edge.battery.soltaro.single.versionb.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -15,20 +16,21 @@ public class ErrorHandler extends StateHandler { protected void onEntry(Context context) throws OpenemsNamedException { this.entryAt = Instant.now(); - ControlAndLogic.stopSystem(context.component); + ControlAndLogic.stopSystem(context.getParent()); } @Override protected void onExit(Context context) throws OpenemsNamedException { - context.component._setMaxStartAttempts(false); - context.component._setMaxStopAttempts(false); + SingleRackVersionBImpl battery = context.getParent(); + battery._setMaxStartAttempts(false); + battery._setMaxStopAttempts(false); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { if (Duration.between(this.entryAt, Instant.now()).getSeconds() > context.config.errorLevel2Delay()) { - ControlAndLogic.resetSystem(context.component); - ControlAndLogic.sleepSystem(context.component); + ControlAndLogic.resetSystem(context.getParent()); + ControlAndLogic.sleepSystem(context.getParent()); // Try again return State.UNDEFINED; } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/GoRunningHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/GoRunningHandler.java index eb7ded46df8..11d89382406 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/GoRunningHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/GoRunningHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionBImpl; import io.openems.edge.battery.soltaro.single.versionb.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -16,13 +17,15 @@ public class GoRunningHandler extends StateHandler { protected void onEntry(Context context) throws OpenemsNamedException { this.lastAttempt = Instant.MIN; this.attemptCounter = 0; - context.component._setMaxStartAttempts(false); + SingleRackVersionBImpl battery = context.getParent(); + battery._setMaxStartAttempts(false); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - - if (ControlAndLogic.isSystemRunning(context.component)) { + SingleRackVersionBImpl battery = context.getParent(); + + if (ControlAndLogic.isSystemRunning(battery)) { return State.RUNNING; } @@ -33,12 +36,12 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > ControlAndLogic.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxStartAttempts(true); + battery._setMaxStartAttempts(true); return State.UNDEFINED; } else { // Trying to switch on - ControlAndLogic.startSystem(context.component); + ControlAndLogic.startSystem(battery); this.lastAttempt = Instant.now(); this.attemptCounter++; return State.GO_RUNNING; @@ -51,9 +54,4 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { } } - - - - - } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/GoStoppedHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/GoStoppedHandler.java index ef9613a9f19..99bb5cad234 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/GoStoppedHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/GoStoppedHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionBImpl; import io.openems.edge.battery.soltaro.single.versionb.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -20,8 +21,9 @@ protected void onEntry(Context context) { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { + SingleRackVersionBImpl battery = context.getParent(); - if (ControlAndLogic.isSystemStopped(context.component)) { + if (ControlAndLogic.isSystemStopped(battery)) { return State.STOPPED; } @@ -32,12 +34,12 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > ControlAndLogic.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxStopAttempts(true); + battery._setMaxStopAttempts(true); return State.UNDEFINED; } else { // Trying to switch off - ControlAndLogic.stopSystem(context.component); + ControlAndLogic.stopSystem(battery); this.lastAttempt = Instant.now(); this.attemptCounter++; return State.GO_STOPPED; diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java index 4597ffdd48a..c1ccea067b4 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/RunningHandler.java @@ -3,6 +3,7 @@ import java.time.LocalDateTime; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionBImpl; import io.openems.edge.battery.soltaro.single.versionb.statemachine.StateMachine.State; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; @@ -14,28 +15,30 @@ public class RunningHandler extends StateHandler { @Override protected void onExit(Context context) throws OpenemsNamedException { - refreshTime = null; + this.refreshTime = null; super.onExit(context); } @Override protected void onEntry(Context context) throws OpenemsNamedException { super.onEntry(context); - refreshTime = LocalDateTime.now(); + this.refreshTime = LocalDateTime.now(); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (ControlAndLogic.hasError(context.component, context.config.numberOfSlaves())) { + SingleRackVersionBImpl battery = context.getParent(); + + if (ControlAndLogic.hasError(battery, context.config.numberOfSlaves())) { return State.UNDEFINED; } - if (!ControlAndLogic.isSystemRunning(context.component)) { + if (!ControlAndLogic.isSystemRunning(battery)) { return State.UNDEFINED; } // Mark as started - context.component._setStartStop(StartStop.START); + battery._setStartStop(StartStop.START); refreshBatteryValues(context); diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/StoppedHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/StoppedHandler.java index 89479f2a1da..e5b967248a2 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/StoppedHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/StoppedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.soltaro.single.versionb.statemachine; +import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionBImpl; import io.openems.edge.battery.soltaro.single.versionb.statemachine.StateMachine.State; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; @@ -8,16 +9,18 @@ public class StoppedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - if (context.component.hasFaults()) { + SingleRackVersionBImpl battery = context.getParent(); + + if (battery.hasFaults()) { return State.UNDEFINED; } - if (!ControlAndLogic.isSystemStopped(context.component)) { + if (!ControlAndLogic.isSystemStopped(context.getParent())) { return State.UNDEFINED; } // Mark as stopped - context.component._setStartStop(StartStop.STOP); + battery._setStartStop(StartStop.STOP); return State.STOPPED; } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/UndefinedHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/UndefinedHandler.java index 45c480852ca..0d1749f4f6a 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/UndefinedHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/statemachine/UndefinedHandler.java @@ -1,6 +1,7 @@ package io.openems.edge.battery.soltaro.single.versionb.statemachine; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.soltaro.single.versionb.SingleRackVersionBImpl; import io.openems.edge.battery.soltaro.single.versionb.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -8,14 +9,16 @@ public class UndefinedHandler extends StateHandler { @Override protected State runAndGetNextState(Context context) throws OpenemsNamedException { - switch (context.component.getStartStopTarget()) { + SingleRackVersionBImpl battery = context.getParent(); + + switch (battery.getStartStopTarget()) { case UNDEFINED: // Stuck in UNDEFINED State return State.UNDEFINED; case START: // force START - if (context.component.hasFaults()) { + if (battery.hasFaults()) { // Has Faults -> error handling return State.ERROR; } else { diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/Context.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/Context.java index 1a7944c306b..cf826302afc 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/Context.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/Context.java @@ -2,14 +2,14 @@ import io.openems.edge.battery.soltaro.single.versionc.Config; import io.openems.edge.battery.soltaro.single.versionc.SingleRackVersionC; +import io.openems.edge.common.statemachine.AbstractContext; + +public class Context extends AbstractContext { -public class Context { - protected final SingleRackVersionC component; protected final Config config; - public Context(SingleRackVersionC component, Config config) { - super(); - this.component = component; + public Context(SingleRackVersionC parent, Config config) { + super(parent); this.config = config; } } \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/ErrorHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/ErrorHandler.java index f8017443c0e..c2daa5160ab 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/ErrorHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/ErrorHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.soltaro.single.versionc.SingleRackVersionC; import io.openems.edge.battery.soltaro.single.versionc.enums.PreChargeControl; import io.openems.edge.battery.soltaro.single.versionc.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -61,13 +62,15 @@ protected void onEntry(Context context) throws OpenemsNamedException { this.entryAt = Instant.now(); // Try to stop system - context.component.setPreChargeControl(PreChargeControl.SWITCH_OFF); + SingleRackVersionC battery = context.getParent(); + battery.setPreChargeControl(PreChargeControl.SWITCH_OFF); } @Override protected void onExit(Context context) throws OpenemsNamedException { - context.component._setMaxStartAttempts(false); - context.component._setMaxStopAttempts(false); + SingleRackVersionC battery = context.getParent(); + battery._setMaxStartAttempts(false); + battery._setMaxStopAttempts(false); } @Override diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoConfigurationHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoConfigurationHandler.java deleted file mode 100644 index 279b3cc054a..00000000000 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoConfigurationHandler.java +++ /dev/null @@ -1,232 +0,0 @@ -package io.openems.edge.battery.soltaro.single.versionc.statemachine; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.battery.soltaro.single.versionc.statemachine.StateMachine.State; -import io.openems.edge.common.statemachine.StateHandler; - -public class GoConfigurationHandler extends StateHandler { - -// private void configureSlaves() { -// if (nextConfiguringProcess == ConfiguringProcess.NONE) { -// nextConfiguringProcess = ConfiguringProcess.CONFIGURING_STARTED; -// } -// -// switch (nextConfiguringProcess) { -// case CONFIGURING_STARTED: -// System.out.println(" ===> CONFIGURING STARTED: setNumberOfModules() <==="); -// setNumberOfModules(); -// break; -// case SET_ID_AUTO_CONFIGURING: -// System.out.println(" ===> SET_ID_AUTO_CONFIGURING: setIdAutoConfiguring() <==="); -// setIdAutoConfiguring(); -// break; -// case CHECK_ID_AUTO_CONFIGURING: -// if (timeAfterAutoId != null) { -// if (timeAfterAutoId.plusSeconds(delayAutoIdSeconds).isAfter(LocalDateTime.now())) { -// break; -// } else { -// timeAfterAutoId = null; -// } -// } -// System.out.println(" ===> CHECK_ID_AUTO_CONFIGURING: checkIdAutoConfiguring() <==="); -// checkIdAutoConfiguring(); -// break; -// case SET_TEMPERATURE_ID_AUTO_CONFIGURING: -// System.out.println(" ===> SET_TEMPERATURE_ID_AUTO_CONFIGURING: setTemperatureIdAutoConfiguring() <==="); -// setTemperatureIdAutoConfiguring(); -// break; -// case CHECK_TEMPERATURE_ID_AUTO_CONFIGURING: -// if (timeAfterAutoId != null) { -// if (timeAfterAutoId.plusSeconds(delayAutoIdSeconds).isAfter(LocalDateTime.now())) { -// break; -// } else { -// timeAfterAutoId = null; -// } -// } -// System.out.println(" ===> CHECK_TEMPERATURE_ID_AUTO_CONFIGURING: checkTemperatureIdAutoConfiguring() <==="); -// checkTemperatureIdAutoConfiguring(); -// break; -// case SET_VOLTAGE_RANGES: -// System.out.println(" ===> SET_VOLTAGE_RANGES: setVoltageRanges() <==="); -// setVoltageRanges(); -// -// break; -// case CONFIGURING_FINISHED: -// System.out.println("====>>> Configuring successful! <<<===="); -// -// if (configuringFinished == null) { -// nextConfiguringProcess = ConfiguringProcess.RESTART_AFTER_SETTING; -// } else { -// if (configuringFinished.plusSeconds(delayAfterConfiguringFinished).isAfter(LocalDateTime.now())) { -// System.out.println(">>> Delay time after configuring!"); -// } else { -// System.out.println("Delay time after configuring is over, reset system"); -// this.logInfo(this.log, -// "Soltaro Rack Version C [CONFIGURING_FINISHED SYSTEM_RESET] is not implemented!"); -// this.resetSystem(); -// } -// } -// break; -// case RESTART_AFTER_SETTING: -// // A manual restart is needed -// System.out.println("====>>> Please restart system manually!"); -// break; -// case NONE: -// break; -// } -//} -// -//private void setVoltageRanges() { -// try { -// IntegerWriteChannel level1OverVoltageChannel = this -// .channel(SingleRackVersionC.ChannelId.LEVEL1_SYSTEM_OVER_VOLTAGE_PROTECTION); -// level1OverVoltageChannel.setNextWriteValue( -// this.config.numberOfSlaves() * ModuleParameters.LEVEL_1_TOTAL_OVER_VOLTAGE_MILLIVOLT.getValue()); -// -// IntegerWriteChannel level1OverVoltageChannelRecover = this -// .channel(SingleRackVersionC.ChannelId.LEVEL1_SYSTEM_OVER_VOLTAGE_RECOVER); -// level1OverVoltageChannelRecover.setNextWriteValue(this.config.numberOfSlaves() -// * ModuleParameters.LEVEL_1_TOTAL_OVER_VOLTAGE_RECOVER_MILLIVOLT.getValue()); -// -// IntegerWriteChannel level1LowVoltageChannel = this -// .channel(SingleRackVersionC.ChannelId.LEVEL1_SYSTEM_UNDER_VOLTAGE_PROTECTION); -// level1LowVoltageChannel.setNextWriteValue( -// this.config.numberOfSlaves() * ModuleParameters.LEVEL_1_TOTAL_LOW_VOLTAGE_MILLIVOLT.getValue()); -// -// IntegerWriteChannel level1LowVoltageChannelRecover = this -// .channel(SingleRackVersionC.ChannelId.LEVEL1_SYSTEM_UNDER_VOLTAGE_RECOVER); -// level1LowVoltageChannelRecover.setNextWriteValue(this.config.numberOfSlaves() -// * ModuleParameters.LEVEL_1_TOTAL_LOW_VOLTAGE_RECOVER_MILLIVOLT.getValue()); -// -// IntegerWriteChannel level2OverVoltageChannel = this -// .channel(SingleRackVersionC.ChannelId.LEVEL2_SYSTEM_OVER_VOLTAGE_PROTECTION); -// level2OverVoltageChannel.setNextWriteValue( -// this.config.numberOfSlaves() * ModuleParameters.LEVEL_2_TOTAL_OVER_VOLTAGE_MILLIVOLT.getValue()); -// -// IntegerWriteChannel level2OverVoltageChannelRecover = this -// .channel(SingleRackVersionC.ChannelId.LEVEL2_SYSTEM_OVER_VOLTAGE_RECOVER); -// level2OverVoltageChannelRecover.setNextWriteValue(this.config.numberOfSlaves() -// * ModuleParameters.LEVEL_2_TOTAL_OVER_VOLTAGE_RECOVER_MILLIVOLT.getValue()); -// -// IntegerWriteChannel level2LowVoltageChannel = this -// .channel(SingleRackVersionC.ChannelId.LEVEL2_SYSTEM_UNDER_VOLTAGE_PROTECTION); -// level2LowVoltageChannel.setNextWriteValue( -// this.config.numberOfSlaves() * ModuleParameters.LEVEL_2_TOTAL_LOW_VOLTAGE_MILLIVOLT.getValue()); -// -// IntegerWriteChannel level2LowVoltageChannelRecover = this -// .channel(SingleRackVersionC.ChannelId.LEVEL2_SYSTEM_UNDER_VOLTAGE_RECOVER); -// level2LowVoltageChannelRecover.setNextWriteValue(this.config.numberOfSlaves() -// * ModuleParameters.LEVEL_2_TOTAL_LOW_VOLTAGE_RECOVER_MILLIVOLT.getValue()); -// -// nextConfiguringProcess = ConfiguringProcess.CONFIGURING_FINISHED; -// configuringFinished = LocalDateTime.now(); -// -// } catch (OpenemsNamedException e) { -// log.error("Setting voltage ranges not successful!"); -// // TODO Should throw Exception/write Warning-State-Channel -// } -//} - -//private void checkTemperatureIdAutoConfiguring() { -// EnumWriteChannel channel = this.channel(SingleRackVersionC.ChannelId.AUTO_SET_SLAVES_TEMPERATURE_ID); -// AutoSetFunction value = channel.value().asEnum(); -// switch (value) { -// case FAILURE: -// this.logError(this.log, "Auto set temperature slaves id failed! Start configuring process again!"); -// // Auto set failed, try again -// this.nextConfiguringProcess = ConfiguringProcess.CONFIGURING_STARTED; -// return; -// case SUCCESS: -// this.logInfo(this.log, "Auto set temperature slaves id succeeded!"); -// nextConfiguringProcess = ConfiguringProcess.SET_VOLTAGE_RANGES; -// return; -// case START_AUTO_SETTING: -// case INIT_MODE: -// case UNDEFINED: -// // Waiting... -// return; -// } -//} - -//private void setTemperatureIdAutoConfiguring() { -// EnumWriteChannel channel = this.channel(SingleRackVersionC.ChannelId.AUTO_SET_SLAVES_TEMPERATURE_ID); -// try { -// channel.setNextWriteValue(AutoSetFunction.START_AUTO_SETTING); -// this.timeAfterAutoId = LocalDateTime.now(); -// this.nextConfiguringProcess = ConfiguringProcess.CHECK_TEMPERATURE_ID_AUTO_CONFIGURING; -// } catch (OpenemsNamedException e) { -// // Set was not successful, it will be tried until it succeeded -// this.logError(this.log, "Setting temperature id auto set not successful"); -// } -//} - -//private void checkIdAutoConfiguring() { -// EnumWriteChannel channel = this.channel(SingleRackVersionC.ChannelId.AUTO_SET_SLAVES_ID); -// AutoSetFunction value = channel.value().asEnum(); -// switch (value) { -// case FAILURE: -// this.logError(this.log, "Auto set slaves id failed! Start configuring process again!"); -// // Auto set failed, try again -// this.nextConfiguringProcess = ConfiguringProcess.CONFIGURING_STARTED; -// return; -// case SUCCESS: -// this.logInfo(this.log, "Auto set slaves id succeeded!"); -// nextConfiguringProcess = ConfiguringProcess.SET_TEMPERATURE_ID_AUTO_CONFIGURING; -// return; -// case START_AUTO_SETTING: -// case INIT_MODE: -// case UNDEFINED: -// // Waiting... -// return; -// } -//} - -//private void setIdAutoConfiguring() { -// EnumWriteChannel channel = this.channel(SingleRackVersionC.ChannelId.AUTO_SET_SLAVES_ID); -// try { -// channel.setNextWriteValue(AutoSetFunction.START_AUTO_SETTING); -// this.timeAfterAutoId = LocalDateTime.now(); -// this.nextConfiguringProcess = ConfiguringProcess.CHECK_ID_AUTO_CONFIGURING; -// } catch (OpenemsNamedException e) { -// // Set was not successful, it will be tried until it succeeded -// this.logError(this.log, "Setting slave numbers not successful"); -// } -//} - -//private void setNumberOfModules() { -// // Set number of modules -// IntegerWriteChannel numberOfSlavesChannel = this -// .channel(SingleRackVersionC.ChannelId.WORK_PARAMETER_PCS_COMMUNICATION_RATE); -// try { -// numberOfSlavesChannel.setNextWriteValue(this.config.numberOfSlaves()); -// nextConfiguringProcess = ConfiguringProcess.SET_ID_AUTO_CONFIGURING; -// } catch (OpenemsNamedException e) { -// // Set was not successful, it will be tried until it succeeded -// this.logError(this.log, "Setting slave numbers not successful. Will try again till it succeeds"); -// } -//} - -//private enum ConfiguringProcess { -// NONE, CONFIGURING_STARTED, SET_ID_AUTO_CONFIGURING, CHECK_ID_AUTO_CONFIGURING, -// SET_TEMPERATURE_ID_AUTO_CONFIGURING, CHECK_TEMPERATURE_ID_AUTO_CONFIGURING, SET_VOLTAGE_RANGES, -// CONFIGURING_FINISHED, RESTART_AFTER_SETTING -//} - - /** - * Checks whether system has an undefined state, e.g. rack 1 & 2 are configured, - * but only rack 1 is running. This state can only be reached at startup coming - * from state undefined - * - * @return boolean - */ -//private boolean isSystemStatePending() { -// return !isSystemRunning() && !isSystemStopped(); -//} - - @Override - public State runAndGetNextState(Context context) throws OpenemsNamedException { - System.out.println("Stuck in GO_CONFIGURATION"); - return State.GO_CONFIGURATION; - } - -} diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoRunningHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoRunningHandler.java index 1b9c18c9d12..9bf892c1e2e 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoRunningHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoRunningHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.soltaro.single.versionc.SingleRackVersionC; import io.openems.edge.battery.soltaro.single.versionc.enums.PreChargeControl; import io.openems.edge.battery.soltaro.single.versionc.statemachine.StateMachine.State; import io.openems.edge.battery.soltaro.versionc.utils.Constants; @@ -18,12 +19,14 @@ public class GoRunningHandler extends StateHandler { protected void onEntry(Context context) throws OpenemsNamedException { this.lastAttempt = Instant.MIN; this.attemptCounter = 0; - context.component._setMaxStartAttempts(false); + SingleRackVersionC battery = context.getParent(); + battery._setMaxStartAttempts(false); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - PreChargeControl preChargeControl = context.component.getPreChargeControl(); + SingleRackVersionC battery = context.getParent(); + PreChargeControl preChargeControl = battery.getPreChargeControl(); if (preChargeControl == PreChargeControl.RUNNING) { return State.RUNNING; @@ -36,12 +39,12 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > Constants.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxStartAttempts(true); + battery._setMaxStartAttempts(true); return State.UNDEFINED; } else { // Trying to switch on - context.component.setPreChargeControl(PreChargeControl.SWITCH_ON); + battery.setPreChargeControl(PreChargeControl.SWITCH_ON); this.lastAttempt = Instant.now(); this.attemptCounter++; return State.GO_RUNNING; diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoStoppedHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoStoppedHandler.java index 345b844fa3e..cac7bc4efc9 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoStoppedHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/GoStoppedHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.soltaro.single.versionc.SingleRackVersionC; import io.openems.edge.battery.soltaro.single.versionc.enums.PreChargeControl; import io.openems.edge.battery.soltaro.single.versionc.statemachine.StateMachine.State; import io.openems.edge.battery.soltaro.versionc.utils.Constants; @@ -22,7 +23,8 @@ protected void onEntry(Context context) { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - PreChargeControl preChargeControl = context.component.getPreChargeControl(); + SingleRackVersionC battery = context.getParent(); + PreChargeControl preChargeControl = battery.getPreChargeControl(); if (preChargeControl == PreChargeControl.SWITCH_OFF) { return State.STOPPED; @@ -35,12 +37,12 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > Constants.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxStopAttempts(true); + battery._setMaxStopAttempts(true); return State.UNDEFINED; } else { // Trying to switch off - context.component.setPreChargeControl(PreChargeControl.SWITCH_OFF); + battery.setPreChargeControl(PreChargeControl.SWITCH_OFF); this.lastAttempt = Instant.now(); this.attemptCounter++; return State.GO_STOPPED; diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/RunningHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/RunningHandler.java index f09705a85af..dbe181572b1 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/RunningHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/RunningHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.soltaro.single.versionc.statemachine; +import io.openems.edge.battery.soltaro.single.versionc.SingleRackVersionC; import io.openems.edge.battery.soltaro.single.versionc.enums.PreChargeControl; import io.openems.edge.battery.soltaro.single.versionc.statemachine.StateMachine.State; import io.openems.edge.common.startstop.StartStop; @@ -9,16 +10,18 @@ public class RunningHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - if (context.component.hasFaults()) { + SingleRackVersionC battery = context.getParent(); + + if (battery.hasFaults()) { return State.UNDEFINED; } - if (context.component.getPreChargeControl() != PreChargeControl.RUNNING) { + if (battery.getPreChargeControl() != PreChargeControl.RUNNING) { return State.UNDEFINED; } // Mark as started - context.component._setStartStop(StartStop.START); + battery._setStartStop(StartStop.START); return State.RUNNING; } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/StateMachine.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/StateMachine.java index d92e4efdfa5..914c58eda06 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/StateMachine.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/StateMachine.java @@ -16,8 +16,6 @@ public enum State implements io.openems.edge.common.statemachine.State, O STOPPED(21), // ERROR(30), // - - GO_CONFIGURATION(40), // ; private final int value; @@ -66,8 +64,6 @@ public StateHandler getStateHandler(State state) { return new StoppedHandler(); case ERROR: return new ErrorHandler(); - case GO_CONFIGURATION: - return new GoConfigurationHandler(); } throw new IllegalArgumentException("Unknown State [" + state + "]"); } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/StoppedHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/StoppedHandler.java index 9f59816af5f..ea7c7d9a24c 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/StoppedHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/StoppedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.soltaro.single.versionc.statemachine; +import io.openems.edge.battery.soltaro.single.versionc.SingleRackVersionC; import io.openems.edge.battery.soltaro.single.versionc.statemachine.StateMachine.State; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; @@ -9,7 +10,8 @@ public class StoppedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { // Mark as stopped - context.component._setStartStop(StartStop.STOP); + SingleRackVersionC battery = context.getParent(); + battery._setStartStop(StartStop.STOP); return State.STOPPED; } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/UndefinedHandler.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/UndefinedHandler.java index 3709c74e581..cd13723f02a 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/UndefinedHandler.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/statemachine/UndefinedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.soltaro.single.versionc.statemachine; +import io.openems.edge.battery.soltaro.single.versionc.SingleRackVersionC; import io.openems.edge.battery.soltaro.single.versionc.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -7,14 +8,15 @@ public class UndefinedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - switch (context.component.getStartStopTarget()) { + SingleRackVersionC battery = context.getParent(); + switch (battery.getStartStopTarget()) { case UNDEFINED: // Stuck in UNDEFINED State return State.UNDEFINED; case START: // force START - if (context.component.hasFaults()) { + if (battery.hasFaults()) { // Has Faults -> error handling return State.ERROR; } else { diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java index 9abd966b938..c653d882044 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java @@ -3,17 +3,18 @@ import io.openems.edge.battery.api.Battery; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.Config; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoBlueplanetGridsave; +import io.openems.edge.common.statemachine.AbstractContext; + +public class Context extends AbstractContext { -public class Context { - protected final KacoBlueplanetGridsave component; protected final Battery battery; protected final Config config; protected final int setActivePower; protected final int setReactivePower; - public Context(KacoBlueplanetGridsave component, Battery battery, Config config, int setActivePower, + public Context(KacoBlueplanetGridsave parent, Battery battery, Config config, int setActivePower, int setReactivePower) { - this.component = component; + super(parent); this.battery = battery; this.config = config; this.setActivePower = setActivePower; diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java index 10acbb02ad8..79c162789c2 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoBlueplanetGridsave; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201RequestedState; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -21,7 +22,8 @@ protected void onEntry(Context context) throws OpenemsNamedException { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - switch (context.component.getCurrentState()) { + KacoBlueplanetGridsave inverter = context.getParent(); + switch (inverter.getCurrentState()) { case STANDBY: case GRID_CONNECTED: case GRID_PRE_CONNECTED: @@ -43,7 +45,7 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { * According to Manual: to more errors to be acknowledged - try to turn OFF */ // TODO this should not be set all the time - context.component.setRequestedState(S64201RequestedState.OFF); + inverter.setRequestedState(S64201RequestedState.OFF); break; } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoRunningHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoRunningHandler.java index c3e520bcca5..4504b35bc45 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoRunningHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoRunningHandler.java @@ -18,17 +18,20 @@ public class GoRunningHandler extends StateHandler { protected void onEntry(Context context) throws OpenemsNamedException { this.lastAttempt = Instant.MIN; this.attemptCounter = 0; - context.component._setMaxStartAttempts(false); + KacoBlueplanetGridsave inverter = context.getParent(); + inverter._setMaxStartAttempts(false); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { + KacoBlueplanetGridsave inverter = context.getParent(); + // Has Faults -> abort - if (context.component.hasFaults()) { + if (inverter.hasFaults()) { return State.UNDEFINED; } - switch (context.component.getCurrentState()) { + switch (inverter.getCurrentState()) { case GRID_CONNECTED: // All Good @@ -58,12 +61,12 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > KacoBlueplanetGridsave.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxStartAttempts(true); + inverter._setMaxStartAttempts(true); return State.UNDEFINED; } else { // Trying to switch on - context.component.setRequestedState(S64201RequestedState.GRID_CONNECTED); + inverter.setRequestedState(S64201RequestedState.GRID_CONNECTED); this.lastAttempt = Instant.now(); this.attemptCounter++; return State.GO_RUNNING; diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoStoppedHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoStoppedHandler.java index eca03c8ba20..d605cc93b66 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoStoppedHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoStoppedHandler.java @@ -22,7 +22,9 @@ protected void onEntry(Context context) { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - switch (context.component.getCurrentState()) { + KacoBlueplanetGridsave inverter = context.getParent(); + + switch (inverter.getCurrentState()) { case OFF: // All Good return State.STOPPED; @@ -49,12 +51,12 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > KacoBlueplanetGridsave.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxStopAttempts(true); + inverter._setMaxStopAttempts(true); return State.UNDEFINED; } else { // Trying to switch off - context.component.setRequestedState(S64201RequestedState.OFF); + inverter.setRequestedState(S64201RequestedState.OFF); this.lastAttempt = Instant.now(); this.attemptCounter++; return State.GO_STOPPED; diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java index 9f4fc11572c..d2c8fea6d1d 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java @@ -2,6 +2,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.batteryinverter.api.SymmetricBatteryInverter; +import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoBlueplanetGridsave; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine.StateMachine.State; import io.openems.edge.common.channel.IntegerReadChannel; @@ -13,11 +14,13 @@ public class RunningHandler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.hasFaults()) { + KacoBlueplanetGridsave inverter = context.getParent(); + + if (inverter.hasFaults()) { return State.UNDEFINED; } - switch (context.component.getCurrentState()) { + switch (inverter.getCurrentState()) { case FAULT: case GRID_PRE_CONNECTED: case MPPT: @@ -40,7 +43,7 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { } // Mark as started - context.component._setStartStop(StartStop.START); + inverter._setStartStop(StartStop.START); // Apply Active and Reactive Power Set-Points this.applyPower(context); @@ -55,10 +58,11 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { * @throws OpenemsNamedException on error */ private void applyPower(Context context) throws OpenemsNamedException { + KacoBlueplanetGridsave inverter = context.getParent(); + // TODO apply reactive power - IntegerWriteChannel wSetPctChannel = context.component - .getSunSpecChannelOrError(KacoSunSpecModel.S64201.W_SET_PCT); - IntegerReadChannel maxApparentPowerChannel = context.component + IntegerWriteChannel wSetPctChannel = inverter.getSunSpecChannelOrError(KacoSunSpecModel.S64201.W_SET_PCT); + IntegerReadChannel maxApparentPowerChannel = inverter .channel(SymmetricBatteryInverter.ChannelId.MAX_APPARENT_POWER); int maxApparentPower = maxApparentPowerChannel.value().getOrError(); diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java index 89a31358ef7..fcb3c55a001 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine; +import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoBlueplanetGridsave; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine.StateMachine.State; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; @@ -9,7 +10,8 @@ public class StoppedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { // Mark as stopped - context.component._setStartStop(StartStop.STOP); + KacoBlueplanetGridsave inverter = context.getParent(); + inverter._setStartStop(StartStop.STOP); return State.STOPPED; } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java index 1fab1bcfe88..a7f36a63128 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine; +import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoBlueplanetGridsave; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -7,14 +8,16 @@ public class UndefinedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - switch (context.component.getStartStopTarget()) { + KacoBlueplanetGridsave inverter = context.getParent(); + + switch (inverter.getStartStopTarget()) { case UNDEFINED: // Stuck in UNDEFINED State return State.UNDEFINED; case START: // force START - if (context.component.hasFaults()) { + if (inverter.hasFaults()) { // Has Faults -> error handling return State.ERROR; } else { diff --git a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/Context.java b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/Context.java index 6e99dbc9447..a88e883c065 100644 --- a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/Context.java +++ b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/Context.java @@ -1,20 +1,19 @@ package io.openems.edge.batteryinverter.refu88k.statemachine; import io.openems.edge.battery.api.Battery; -import io.openems.edge.batteryinverter.refu88k.RefuStore88k; import io.openems.edge.batteryinverter.refu88k.Config; +import io.openems.edge.batteryinverter.refu88k.RefuStore88k; +import io.openems.edge.common.statemachine.AbstractContext; +public class Context extends AbstractContext { -public class Context { - protected final RefuStore88k component; protected final Battery battery; protected final Config config; protected final int setActivePower; protected final int setReactivePower; - public Context(RefuStore88k component, Battery battery, Config config, int setActivePower, - int setReactivePower) { - this.component = component; + public Context(RefuStore88k parent, Battery battery, Config config, int setActivePower, int setReactivePower) { + super(parent); this.battery = battery; this.config = config; this.setActivePower = setActivePower; diff --git a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/ErrorHandler.java b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/ErrorHandler.java index 66cf70826f9..3190b3fb643 100644 --- a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/ErrorHandler.java +++ b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/ErrorHandler.java @@ -1,6 +1,7 @@ package io.openems.edge.batteryinverter.refu88k.statemachine; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.batteryinverter.refu88k.RefuStore88k; import io.openems.edge.batteryinverter.refu88k.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -8,9 +9,10 @@ public class ErrorHandler extends StateHandler { @Override public StateMachine.State runAndGetNextState(Context context) throws OpenemsNamedException { + RefuStore88k inverter = context.getParent(); - context.component._setActivePower(0); - context.component._setReactivePower(0); + inverter._setActivePower(0); + inverter._setReactivePower(0); // Try again return State.UNDEFINED; diff --git a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/GoRunningHandler.java b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/GoRunningHandler.java index f3935b0549c..5fbc1f44c43 100644 --- a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/GoRunningHandler.java +++ b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/GoRunningHandler.java @@ -1,6 +1,7 @@ package io.openems.edge.batteryinverter.refu88k.statemachine; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.batteryinverter.refu88k.RefuStore88k; import io.openems.edge.batteryinverter.refu88k.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -8,17 +9,21 @@ public class GoRunningHandler extends StateHandler { @Override protected void onEntry(Context context) throws OpenemsNamedException { - context.component._setMaxStartAttempts(false); + RefuStore88k inverter = context.getParent(); + + inverter._setMaxStartAttempts(false); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { + RefuStore88k inverter = context.getParent(); + // Has Faults -> abort - if (context.component.hasFaults()) { + if (inverter.hasFaults()) { return State.UNDEFINED; } - switch (context.component.getOperatingState()) { + switch (inverter.getOperatingState()) { case STARTING: return State.GO_RUNNING; @@ -29,16 +34,16 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { // is still working return State.RUNNING; case STANDBY: - context.component.exitStandbyMode(); + inverter.exitStandbyMode(); return State.GO_RUNNING; - // if inverter is throttled, full power is not available, but the device - // is still working + // if inverter is throttled, full power is not available, but the device + // is still working case FAULT: return State.ERROR; case OFF: case SLEEPING: case SHUTTING_DOWN: - + case UNDEFINED: return State.UNDEFINED; } diff --git a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/GoStoppedHandler.java b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/GoStoppedHandler.java index 4ef0c1ee593..d96d13b067b 100644 --- a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/GoStoppedHandler.java +++ b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/GoStoppedHandler.java @@ -1,6 +1,7 @@ package io.openems.edge.batteryinverter.refu88k.statemachine; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.batteryinverter.refu88k.RefuStore88k; import io.openems.edge.batteryinverter.refu88k.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -8,13 +9,14 @@ public class GoStoppedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { + RefuStore88k inverter = context.getParent(); - switch (context.component.getOperatingState()) { + switch (inverter.getOperatingState()) { case STARTING: case MPPT: case THROTTLED: case STARTED: - context.component.stopInverter(); + inverter.stopInverter(); return State.GO_STOPPED; case FAULT: case STANDBY: diff --git a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/RunningHandler.java b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/RunningHandler.java index 22a5811a0ca..500b59c6932 100644 --- a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/RunningHandler.java +++ b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/RunningHandler.java @@ -4,6 +4,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.batteryinverter.api.SymmetricBatteryInverter; +import io.openems.edge.batteryinverter.refu88k.RefuStore88k; import io.openems.edge.batteryinverter.refu88k.RefuStore88kChannelId; import io.openems.edge.batteryinverter.refu88k.enums.VArPctEna; import io.openems.edge.batteryinverter.refu88k.enums.WMaxLimEna; @@ -20,17 +21,19 @@ public class RunningHandler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.hasFaults()) { + RefuStore88k inverter = context.getParent(); + + if (inverter.hasFaults()) { return State.UNDEFINED; } - switch (context.component.getOperatingState()) { + switch (inverter.getOperatingState()) { case STARTED: case THROTTLED: case MPPT: // Mark as started - context.component._setStartStop(StartStop.START); + inverter._setStartStop(StartStop.START); // Apply Active and Reactive Power Set-Points this.applyPower(context); return State.RUNNING; @@ -56,9 +59,10 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { */ private void applyPower(Context context) throws OpenemsNamedException { + RefuStore88k inverter = context.getParent(); doGridConnectedHandling(context, context.setActivePower, context.setReactivePower); - IntegerReadChannel maxApparentPowerChannel = context.component + IntegerReadChannel maxApparentPowerChannel = inverter .channel(SymmetricBatteryInverter.ChannelId.MAX_APPARENT_POWER); int maxApparentPower = maxApparentPowerChannel.value().getOrError(); @@ -70,11 +74,11 @@ private void applyPower(Context context) throws OpenemsNamedException { // Calculate Reactive Power as a percentage of WMAX varSetPct = ((100 * context.setReactivePower) / maxApparentPower); - IntegerWriteChannel wMaxLimPctChannel = context.component.channel(RefuStore88kChannelId.W_MAX_LIM_PCT); - EnumWriteChannel wMaxLim_EnaChannel = context.component.channel(RefuStore88kChannelId.W_MAX_LIM_ENA); + IntegerWriteChannel wMaxLimPctChannel = inverter.channel(RefuStore88kChannelId.W_MAX_LIM_PCT); + EnumWriteChannel wMaxLim_EnaChannel = inverter.channel(RefuStore88kChannelId.W_MAX_LIM_ENA); - IntegerWriteChannel varMaxLimPctChannel = context.component.channel(RefuStore88kChannelId.VAR_W_MAX_PCT); - EnumWriteChannel varMaxLim_EnaChannel = context.component.channel(RefuStore88kChannelId.VAR_PCT_ENA); + IntegerWriteChannel varMaxLimPctChannel = inverter.channel(RefuStore88kChannelId.VAR_W_MAX_PCT); + EnumWriteChannel varMaxLim_EnaChannel = inverter.channel(RefuStore88kChannelId.VAR_PCT_ENA); wMaxLimPctChannel.setNextWriteValue(wSetPct); wMaxLim_EnaChannel.setNextWriteValue(WMaxLimEna.ENABLED); @@ -93,16 +97,18 @@ private void applyPower(Context context) throws OpenemsNamedException { private void doGridConnectedHandling(Context context, int activePower, int reactivePower) throws OpenemsNamedException { + RefuStore88k inverter = context.getParent(); + if (activePower == 0 && reactivePower == 0) { if (timeNoPower == null) { timeNoPower = LocalDateTime.now(); } if ((timeNoPower.plusSeconds(context.config.timeLimitNoPower())).isBefore(LocalDateTime.now())) { - context.component.enterStartedMode(); + inverter.enterStartedMode(); } } else { timeNoPower = null; - context.component.enterThrottledMpptMode(); + inverter.enterThrottledMpptMode(); } } diff --git a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/StoppedHandler.java b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/StoppedHandler.java index 11c0addfdd2..aaf2f026aae 100644 --- a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/StoppedHandler.java +++ b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/StoppedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.batteryinverter.refu88k.statemachine; +import io.openems.edge.batteryinverter.refu88k.RefuStore88k; import io.openems.edge.batteryinverter.refu88k.statemachine.StateMachine.State; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; @@ -8,16 +9,16 @@ public class StoppedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { + RefuStore88k inverter = context.getParent(); - switch (context.component.getOperatingState()) { - + switch (inverter.getOperatingState()) { case STANDBY: // Mark as stopped - context.component._setStartStop(StartStop.STOP); + inverter._setStartStop(StartStop.STOP); return State.STOPPED; case FAULT: // Mark as stopped - context.component._setStartStop(StartStop.STOP); + inverter._setStartStop(StartStop.STOP); return State.ERROR; case STARTING: case MPPT: diff --git a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/UndefinedHandler.java b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/UndefinedHandler.java index 26db57711b9..98d462f915d 100644 --- a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/UndefinedHandler.java +++ b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/statemachine/UndefinedHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.batteryinverter.refu88k.statemachine; +import io.openems.edge.batteryinverter.refu88k.RefuStore88k; import io.openems.edge.batteryinverter.refu88k.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -7,14 +8,16 @@ public class UndefinedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - switch (context.component.getStartStopTarget()) { + RefuStore88k inverter = context.getParent(); + + switch (inverter.getStartStopTarget()) { case UNDEFINED: // Stuck in UNDEFINED State return State.UNDEFINED; case START: // force START - if (context.component.hasFaults()) { + if (inverter.hasFaults()) { // Has Faults -> error handling return State.ERROR; } else { diff --git a/io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractContext.java b/io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractContext.java new file mode 100644 index 00000000000..558d7a37b81 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractContext.java @@ -0,0 +1,69 @@ +package io.openems.edge.common.statemachine; + +import org.slf4j.Logger; + +import io.openems.edge.common.component.OpenemsComponent; + +public class AbstractContext { + + private final PARENT parent; + + /** + * Constructs an {@link AbstractContext}. + * + * @param parent the parent {@link OpenemsComponent}. This is used to provide + * useful logging. + */ + public AbstractContext(PARENT parent) { + this.parent = parent; + } + + /** + * Gets the parent {@link OpenemsComponent}. + * + * @return the parent + */ + public PARENT getParent() { + return parent; + } + + /** + * Log a debug message including the Component ID. + * + * @param log the Logger instance + * @param message the message + */ + public void logDebug(Logger log, String message) { + OpenemsComponent.logDebug(this.parent, log, message); + } + + /** + * Log an info message including the Component ID. + * + * @param log the Logger instance + * @param message the message + */ + public void logInfo(Logger log, String message) { + OpenemsComponent.logInfo(this.parent, log, message); + } + + /** + * Log a warn message including the Component ID. + * + * @param log the Logger instance + * @param message the message + */ + public void logWarn(Logger log, String message) { + OpenemsComponent.logWarn(this.parent, log, message); + } + + /** + * Log an error message including the Component ID. + * + * @param log the Logger instance + * @param message the message + */ + public void logError(Logger log, String message) { + OpenemsComponent.logError(this.parent, log, message); + } +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractStateMachine.java b/io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractStateMachine.java index 1ffe9993e21..3a3938b3835 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractStateMachine.java +++ b/io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractStateMachine.java @@ -15,7 +15,7 @@ * @param the context type, i.e. a class wrapping a State-Machine * context */ -public abstract class AbstractStateMachine, CONTEXT> { +public abstract class AbstractStateMachine, CONTEXT extends AbstractContext> { private final Logger log = LoggerFactory.getLogger(AbstractStateMachine.class); diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/Context.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/Context.java index 8ee814f88a9..b27c6f3a2dc 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/Context.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/Context.java @@ -2,19 +2,19 @@ import io.openems.edge.battery.api.Battery; import io.openems.edge.batteryinverter.api.ManagedSymmetricBatteryInverter; +import io.openems.edge.common.statemachine.AbstractContext; import io.openems.edge.ess.generic.symmetric.Config; import io.openems.edge.ess.generic.symmetric.GenericManagedSymmetricEss; -public class Context { - protected final GenericManagedSymmetricEss component; +public class Context extends AbstractContext { + protected final Battery battery; protected final ManagedSymmetricBatteryInverter batteryInverter; protected final Config config; - public Context(GenericManagedSymmetricEss component, Battery battery, - ManagedSymmetricBatteryInverter batteryInverter, Config config) { - super(); - this.component = component; + public Context(GenericManagedSymmetricEss parent, Battery battery, ManagedSymmetricBatteryInverter batteryInverter, + Config config) { + super(parent); this.battery = battery; this.batteryInverter = batteryInverter; this.config = config; diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java index f762e7280d9..1cf648277a4 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java @@ -6,6 +6,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.ess.generic.symmetric.GenericManagedSymmetricEss; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; public class ErrorHandler extends StateHandler { @@ -23,8 +24,10 @@ protected void onEntry(Context context) throws OpenemsNamedException { @Override protected void onExit(Context context) throws OpenemsNamedException { - context.component._setMaxBatteryStartAttemptsFault(false); - context.component._setMaxBatteryInverterStopAttemptsFault(false); + GenericManagedSymmetricEss ess = context.getParent(); + + ess._setMaxBatteryStartAttemptsFault(false); + ess._setMaxBatteryInverterStopAttemptsFault(false); } @Override diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryHandler.java index ace508e61d6..e693b9670de 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryHandler.java @@ -17,11 +17,14 @@ public class StartBatteryHandler extends StateHandler { protected void onEntry(Context context) throws OpenemsNamedException { this.lastAttempt = Instant.MIN; this.attemptCounter = 0; - context.component._setMaxBatteryStartAttemptsFault(false); + GenericManagedSymmetricEss ess = context.getParent(); + ess._setMaxBatteryStartAttemptsFault(false); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { + GenericManagedSymmetricEss ess = context.getParent(); + if (context.battery.isStarted()) { // TODO should we check here the other parameters defined in Battery Nature. return State.START_BATTERY_INVERTER; @@ -34,7 +37,7 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > GenericManagedSymmetricEss.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxBatteryStartAttemptsFault(true); + ess._setMaxBatteryStartAttemptsFault(true); return State.UNDEFINED; } else { diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryInverterHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryInverterHandler.java index 0c4a4a5c0cb..b8b1ea2beeb 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryInverterHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryInverterHandler.java @@ -17,11 +17,14 @@ public class StartBatteryInverterHandler extends StateHandler { protected void onEntry(Context context) throws OpenemsNamedException { this.lastAttempt = Instant.MIN; this.attemptCounter = 0; - context.component._setMaxBatteryInverterStartAttemptsFault(false); + GenericManagedSymmetricEss ess = context.getParent(); + ess._setMaxBatteryInverterStartAttemptsFault(false); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { + GenericManagedSymmetricEss ess = context.getParent(); + if (context.batteryInverter.isStarted()) { return State.STARTED; } @@ -33,7 +36,7 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > GenericManagedSymmetricEss.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxBatteryInverterStartAttemptsFault(true); + ess._setMaxBatteryInverterStartAttemptsFault(true); return State.UNDEFINED; } else { diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartedHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartedHandler.java index d6928d9d321..9c25fa222cb 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartedHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartedHandler.java @@ -2,13 +2,16 @@ import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.ess.generic.symmetric.GenericManagedSymmetricEss; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; public class StartedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - if (context.component.hasFaults()) { + GenericManagedSymmetricEss ess = context.getParent(); + + if (ess.hasFaults()) { return State.UNDEFINED; } @@ -21,7 +24,7 @@ public State runAndGetNextState(Context context) { } // Mark as started - context.component._setStartStop(StartStop.START); + ess._setStartStop(StartStop.START); return State.STARTED; } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryHandler.java index 6932749a7e1..b1333dfd8f3 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryHandler.java @@ -17,11 +17,14 @@ public class StopBatteryHandler extends StateHandler { protected void onEntry(Context context) throws OpenemsNamedException { this.lastAttempt = Instant.MIN; this.attemptCounter = 0; - context.component._setMaxBatteryStopAttemptsFault(false); + GenericManagedSymmetricEss ess = context.getParent(); + ess._setMaxBatteryStopAttemptsFault(false); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { + GenericManagedSymmetricEss ess = context.getParent(); + if (context.battery.isStopped()) { return State.STOPPED; } @@ -33,7 +36,7 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > GenericManagedSymmetricEss.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxBatteryStopAttemptsFault(true); + ess._setMaxBatteryStopAttemptsFault(true); return State.UNDEFINED; } else { diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryInverterHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryInverterHandler.java index 6cde4b48fe3..ea8f392a0ff 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryInverterHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryInverterHandler.java @@ -17,11 +17,14 @@ public class StopBatteryInverterHandler extends StateHandler { protected void onEntry(Context context) throws OpenemsNamedException { this.lastAttempt = Instant.MIN; this.attemptCounter = 0; - context.component._setMaxBatteryInverterStopAttemptsFault(false); + GenericManagedSymmetricEss ess = context.getParent(); + ess._setMaxBatteryInverterStopAttemptsFault(false); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { + GenericManagedSymmetricEss ess = context.getParent(); + if (context.batteryInverter.isStopped()) { return State.STOP_BATTERY; } @@ -33,7 +36,7 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > GenericManagedSymmetricEss.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.component._setMaxBatteryInverterStopAttemptsFault(true); + ess._setMaxBatteryInverterStopAttemptsFault(true); return State.UNDEFINED; } else { diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StoppedHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StoppedHandler.java index bb09f3579fb..41d3178477a 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StoppedHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StoppedHandler.java @@ -2,13 +2,16 @@ import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.ess.generic.symmetric.GenericManagedSymmetricEss; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; public class StoppedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - if (context.component.hasFaults()) { + GenericManagedSymmetricEss ess = context.getParent(); + + if (ess.hasFaults()) { return State.UNDEFINED; } @@ -21,7 +24,7 @@ public State runAndGetNextState(Context context) { } // Mark as stopped - context.component._setStartStop(StartStop.STOP); + ess._setStartStop(StartStop.STOP); return State.STOPPED; } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/UndefinedHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/UndefinedHandler.java index b9eccc8fc85..6ed6f647c71 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/UndefinedHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/UndefinedHandler.java @@ -1,20 +1,22 @@ package io.openems.edge.ess.generic.symmetric.statemachine; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.ess.generic.symmetric.GenericManagedSymmetricEss; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; public class UndefinedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - switch (context.component.getStartStopTarget()) { + GenericManagedSymmetricEss ess = context.getParent(); + switch (ess.getStartStopTarget()) { case UNDEFINED: // Stuck in UNDEFINED State return State.UNDEFINED; case START: // force START - if (context.component.hasFaults()) { + if (ess.hasFaults()) { // TODO should we consider also Battery-Inverter and Battery Faults? // TODO should the Modbus-Device also be on error, when then Modbus-Bridge is on // error? diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode1Handler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode1Handler.java index 3fc77140bf3..af87f510e13 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode1Handler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode1Handler.java @@ -5,6 +5,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.SetupMode; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; @@ -14,9 +15,11 @@ public class ActivateDebugMode1Handler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.getSetupMode() != SetupMode.ON) { - this.log.info("Activate Readonly-Mode: Set Setup-Mode ON"); - context.component.setSetupMode(SetupMode.ON); + FeneconMiniEss ess = context.getParent(); + + if (ess.getSetupMode() != SetupMode.ON) { + context.logInfo(this.log, "Activate Readonly-Mode: Set Setup-Mode ON"); + ess.setSetupMode(SetupMode.ON); } return State.ACTIVATE_DEBUG_MODE_2; diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode2Handler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode2Handler.java index b569ba86874..7e0f79b8a26 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode2Handler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode2Handler.java @@ -5,6 +5,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.PcsMode; import io.openems.edge.fenecon.mini.ess.SetupMode; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; @@ -15,13 +16,15 @@ public class ActivateDebugMode2Handler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.getSetupMode() != SetupMode.ON) { - this.log.info("Wait for Setup-Mode ON"); + FeneconMiniEss ess = context.getParent(); + + if (ess.getSetupMode() != SetupMode.ON) { + context.logInfo(this.log, "Wait for Setup-Mode ON"); return State.ACTIVATE_DEBUG_MODE_2; } - this.log.info("Setup-Mode is ON -> Set PCS-Mode DEBUG"); - context.component.setPcsMode(PcsMode.DEBUG); + context.logInfo(this.log, "Setup-Mode is ON -> Set PCS-Mode DEBUG"); + ess.setPcsMode(PcsMode.DEBUG); return State.ACTIVATE_DEBUG_MODE_3; } diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode3Handler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode3Handler.java index f71d2e29695..2995e5eaa81 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode3Handler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode3Handler.java @@ -5,6 +5,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.PcsMode; import io.openems.edge.fenecon.mini.ess.SetupMode; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; @@ -15,13 +16,15 @@ public class ActivateDebugMode3Handler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.getPcsMode() != PcsMode.DEBUG) { - this.log.info("Wait for PCS-Mode DEBUG"); + FeneconMiniEss ess = context.getParent(); + + if (ess.getPcsMode() != PcsMode.DEBUG) { + context.logInfo(this.log, "Wait for PCS-Mode DEBUG"); return State.ACTIVATE_DEBUG_MODE_3; } - this.log.info("PCS-Mode is DEBUG -> Set Setup-Mode OFF"); - context.component.setSetupMode(SetupMode.OFF); + context.logInfo(this.log, "PCS-Mode is DEBUG -> Set Setup-Mode OFF"); + ess.setSetupMode(SetupMode.OFF); return State.ACTIVATE_DEBUG_MODE_4; } diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode4Handler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode4Handler.java index c2616dd471c..4f35c339e66 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode4Handler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateDebugMode4Handler.java @@ -5,6 +5,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.SetupMode; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; @@ -14,12 +15,14 @@ public class ActivateDebugMode4Handler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.getSetupMode() != SetupMode.OFF) { - this.log.info("Wait for Setup-Mode OFF"); + FeneconMiniEss ess = context.getParent(); + + if (ess.getSetupMode() != SetupMode.OFF) { + context.logInfo(this.log, "Wait for Setup-Mode OFF"); return State.ACTIVATE_DEBUG_MODE_4; } - this.log.info("Setup-Mode is OFF"); + context.logInfo(this.log, "Setup-Mode is OFF"); return State.GO_WRITE_MODE; } diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode1Handler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode1Handler.java index af92043a449..cd415525539 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode1Handler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode1Handler.java @@ -5,6 +5,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.SetupMode; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; @@ -14,9 +15,11 @@ public class ActivateEconomicMode1Handler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.getSetupMode() != SetupMode.ON) { - this.log.info("Activate Debug-Mode: Set Setup-Mode ON"); - context.component.setSetupMode(SetupMode.ON); + FeneconMiniEss ess = context.getParent(); + + if (ess.getSetupMode() != SetupMode.ON) { + context.logInfo(this.log, "Activate Debug-Mode: Set Setup-Mode ON"); + ess.setSetupMode(SetupMode.ON); } return State.ACTIVATE_ECONOMIC_MODE_2; diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode2Handler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode2Handler.java index 6a0ae4c6c63..8c7aff0e477 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode2Handler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode2Handler.java @@ -5,6 +5,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.PcsMode; import io.openems.edge.fenecon.mini.ess.SetupMode; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; @@ -15,14 +16,16 @@ public class ActivateEconomicMode2Handler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.getSetupMode() != SetupMode.ON) { - this.log.info("Wait for Setup-Mode ON"); + FeneconMiniEss ess = context.getParent(); + + if (ess.getSetupMode() != SetupMode.ON) { + context.logInfo(this.log, "Wait for Setup-Mode ON"); return State.ACTIVATE_ECONOMIC_MODE_2; } - this.log.info("Setup-Mode is ON -> Set PCS-Mode ECONOMIC"); - context.component.setPcsMode(PcsMode.ECONOMIC); - + context.logInfo(this.log, "Setup-Mode is ON -> Set PCS-Mode ECONOMIC"); + ess.setPcsMode(PcsMode.ECONOMIC); + return State.ACTIVATE_ECONOMIC_MODE_3; } diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode3Handler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode3Handler.java index 1f367febe71..1ecfbe43e5d 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode3Handler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode3Handler.java @@ -5,6 +5,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.PcsMode; import io.openems.edge.fenecon.mini.ess.SetupMode; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; @@ -15,13 +16,15 @@ public class ActivateEconomicMode3Handler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.getPcsMode() != PcsMode.ECONOMIC) { - this.log.info("Wait for PCS-Mode ECONOMIC"); + FeneconMiniEss ess = context.getParent(); + + if (ess.getPcsMode() != PcsMode.ECONOMIC) { + context.logInfo(this.log, "Wait for PCS-Mode ECONOMIC"); return State.ACTIVATE_ECONOMIC_MODE_3; } - this.log.info("PCS-Mode is ECONOMIC -> Set Setup-Mode OFF"); - context.component.setSetupMode(SetupMode.OFF); + context.logInfo(this.log, "PCS-Mode is ECONOMIC -> Set Setup-Mode OFF"); + ess.setSetupMode(SetupMode.OFF); return State.ACTIVATE_ECONOMIC_MODE_4; } diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode4Handler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode4Handler.java index 201c957a707..6fe885d5b64 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode4Handler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/ActivateEconomicMode4Handler.java @@ -5,6 +5,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.SetupMode; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; @@ -14,12 +15,14 @@ public class ActivateEconomicMode4Handler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.getSetupMode() != SetupMode.OFF) { - this.log.info("Wait for Setup-Mode OFF"); + FeneconMiniEss ess = context.getParent(); + + if (ess.getSetupMode() != SetupMode.OFF) { + context.logInfo(this.log, "Wait for Setup-Mode OFF"); return State.ACTIVATE_ECONOMIC_MODE_4; } - this.log.info("Setup-Mode is OFF"); + context.logInfo(this.log, "Setup-Mode is OFF"); return State.GO_READONLY_MODE; } diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/Context.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/Context.java index c9f9d6bdbcf..22ee676f6ed 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/Context.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/Context.java @@ -1,16 +1,17 @@ package io.openems.edge.fenecon.mini.ess.statemachine; +import io.openems.edge.common.statemachine.AbstractContext; import io.openems.edge.fenecon.mini.ess.Config; import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; -public class Context { - protected final FeneconMiniEss component; +public class Context extends AbstractContext { + protected final Config config; protected final int setActivePower; protected final int setReactivePower; - public Context(FeneconMiniEss component, Config config, int setActivePower, int setReactivePower) { - this.component = component; + public Context(FeneconMiniEss parent, Config config, int setActivePower, int setReactivePower) { + super(parent); this.config = config; this.setActivePower = setActivePower; this.setReactivePower = setReactivePower; diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoReadonlyModeHandler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoReadonlyModeHandler.java index 2238c2bd58b..86b6b12a8f7 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoReadonlyModeHandler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoReadonlyModeHandler.java @@ -2,6 +2,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.PcsMode; import io.openems.edge.fenecon.mini.ess.SetupMode; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; @@ -10,7 +11,9 @@ public class GoReadonlyModeHandler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.getPcsMode() == PcsMode.ECONOMIC && context.component.getSetupMode() == SetupMode.OFF) { + FeneconMiniEss ess = context.getParent(); + + if (ess.getPcsMode() == PcsMode.ECONOMIC && ess.getSetupMode() == SetupMode.OFF) { return State.READONLY_MODE; } diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoWriteModeHandler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoWriteModeHandler.java index f511cb83224..b6a65949b48 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoWriteModeHandler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoWriteModeHandler.java @@ -5,6 +5,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.PcsMode; import io.openems.edge.fenecon.mini.ess.SetupMode; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; @@ -15,16 +16,18 @@ public class GoWriteModeHandler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.getPcsMode() == PcsMode.UNDEFINED) { - this.log.info("Wait for PCS Mode to be defined"); + FeneconMiniEss ess = context.getParent(); + + if (ess.getPcsMode() == PcsMode.UNDEFINED) { + context.logInfo(this.log, "Wait for PCS Mode to be defined"); return State.GO_WRITE_MODE; } - if (context.component.getSetupMode() == SetupMode.UNDEFINED) { - this.log.info("Wait for Setup-Mode to be defined"); + if (ess.getSetupMode() == SetupMode.UNDEFINED) { + context.logInfo(this.log, "Wait for Setup-Mode to be defined"); return State.GO_WRITE_MODE; } - if (context.component.getPcsMode() == PcsMode.DEBUG && context.component.getSetupMode() == SetupMode.OFF) { + if (ess.getPcsMode() == PcsMode.DEBUG && ess.getSetupMode() == SetupMode.OFF) { return State.WRITE_MODE; } diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/UndefinedHandler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/UndefinedHandler.java index aaa7254057a..2e55a83de27 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/UndefinedHandler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/UndefinedHandler.java @@ -4,6 +4,7 @@ import org.slf4j.LoggerFactory; import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.PcsMode; import io.openems.edge.fenecon.mini.ess.SetupMode; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; @@ -11,18 +12,20 @@ public class UndefinedHandler extends StateHandler { private final Logger log = LoggerFactory.getLogger(UndefinedHandler.class); - + @Override public State runAndGetNextState(Context context) { - if (context.component.getPcsMode() == PcsMode.UNDEFINED) { - this.log.info("Wait for PCS Mode to be defined"); + FeneconMiniEss ess = context.getParent(); + + if (ess.getPcsMode() == PcsMode.UNDEFINED) { + context.logInfo(this.log, "Wait for PCS Mode to be defined"); return State.UNDEFINED; } - if (context.component.getSetupMode() == SetupMode.UNDEFINED) { - this.log.info("Wait for Setup-Mode to be defined"); + if (ess.getSetupMode() == SetupMode.UNDEFINED) { + context.logInfo(this.log, "Wait for Setup-Mode to be defined"); return State.UNDEFINED; } - + if (context.config.readonly()) { return State.GO_READONLY_MODE; } else { diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/WriteModeHandler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/WriteModeHandler.java index 589ff8ef9cf..bace6ed22d5 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/WriteModeHandler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/WriteModeHandler.java @@ -3,6 +3,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.statemachine.StateHandler; import io.openems.edge.fenecon.mini.ess.DebugRunState; +import io.openems.edge.fenecon.mini.ess.FeneconMiniEss; import io.openems.edge.fenecon.mini.ess.statemachine.StateMachine.State; public class WriteModeHandler extends StateHandler { @@ -22,12 +23,14 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { * @throws OpenemsNamedException on error */ private void applyPower(Context context) throws OpenemsNamedException { + FeneconMiniEss ess = context.getParent(); + // Set correct Debug Run State - DebugRunState runState = context.component.getDebugRunState(); + DebugRunState runState = ess.getDebugRunState(); if (context.setActivePower > 0 && runState != DebugRunState.DISCHARGE) { - context.component.setDebugRunState(DebugRunState.DISCHARGE); + ess.setDebugRunState(DebugRunState.DISCHARGE); } else if (context.setActivePower < 0 && runState != DebugRunState.CHARGE) { - context.component.setDebugRunState(DebugRunState.CHARGE); + ess.setDebugRunState(DebugRunState.CHARGE); } // Adjust Active Power @@ -37,19 +40,19 @@ private void applyPower(Context context) throws OpenemsNamedException { if (context.setActivePower >= 0) { // Set Discharge & no Charge - if (context.component.getGridMaxChargeCurrent().orElse(-1) != 0) { - context.component.setGridMaxChargeCurrent(0); + if (ess.getGridMaxChargeCurrent().orElse(-1) != 0) { + ess.setGridMaxChargeCurrent(0); } - if (context.component.getGridMaxDischargeCurrent().orElse(-1) != current) { - context.component.setGridMaxDischargeCurrent(current); + if (ess.getGridMaxDischargeCurrent().orElse(-1) != current) { + ess.setGridMaxDischargeCurrent(current); } } else { // Set Charge & no Discharge - if (context.component.getGridMaxDischargeCurrent().orElse(-1) != 0) { - context.component.setGridMaxDischargeCurrent(0); + if (ess.getGridMaxDischargeCurrent().orElse(-1) != 0) { + ess.setGridMaxDischargeCurrent(0); } - if (context.component.getGridMaxChargeCurrent().orElse(-1) != current) { - context.component.setGridMaxChargeCurrent(current); + if (ess.getGridMaxChargeCurrent().orElse(-1) != current) { + ess.setGridMaxChargeCurrent(current); } } } diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/Context.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/Context.java index dea9add5d9e..2be6e64d7f9 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/Context.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/Context.java @@ -1,20 +1,19 @@ package io.openems.edge.goodwe.ess.applypower; +import io.openems.edge.common.statemachine.AbstractContext; import io.openems.edge.goodwe.ess.GoodWeEssImpl; import io.openems.edge.goodwe.ess.enums.PowerModeEms; -public class Context { +public class Context extends AbstractContext { - protected final GoodWeEssImpl component; protected final int pvProduction; protected final int activePowerSetPoint; private PowerModeEms nextPowerMode; private int essPowerSet; - public Context(GoodWeEssImpl component, int pvProduction, int activePowerSetPoint) { - super(); - this.component = component; + public Context(GoodWeEssImpl parent, int pvProduction, int activePowerSetPoint) { + super(parent); this.pvProduction = pvProduction; this.activePowerSetPoint = activePowerSetPoint; } From 80b81c33c3aa8f79ea3bf4387cf6d715194760ef Mon Sep 17 00:00:00 2001 From: Wolfgang Gerbl Date: Mon, 21 Dec 2020 17:22:49 +0100 Subject: [PATCH 12/22] adapt values --- .../edge/battery/soltaro/SoltaroCellCharacteristic.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java index 07bc6031d80..91961c60393 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java @@ -4,22 +4,22 @@ public class SoltaroCellCharacteristic implements CellCharacteristic { @Override public int getFinalCellDischargeVoltage_mV() { - return 2_800; // 0x2086 Cell under voltage Alarm + return 2_900; // } @Override public int getForceChargeCellVoltage_mV() { - return 2_750; // 0x2047 Cell under voltage Protection recover + return 2_800; // 0x2046 Cell under voltage Protection } @Override public int getFinalCellChargeVoltage_mV() { - return 3_650; // 0x0080 Cell Over Voltage Alarm + return 3_650; // 0x0041 Cell Over Voltage Recover / 0x0080 Cell over Voltage Alarm } @Override public int getForceDischargeCellVoltage_mV() { - return 3_680; // 0x0041 Cell Over Voltage Recover + return 3_680; // } } From f38b0bf5629ae13ea89437bc243386e90a2cf471 Mon Sep 17 00:00:00 2001 From: Wolfgang Gerbl Date: Tue, 22 Dec 2020 15:45:08 +0100 Subject: [PATCH 13/22] adds test, fix that system charges until final discharge cell voltage is reached --- .../soltaro/SoltaroCellCharacteristic.java | 2 +- .../io/openems/edge/battery/soltaro/Util.java | 32 ++++---- .../edge/battery/soltaro/UtilTest.java | 81 +++++++++++++++++++ 3 files changed, 97 insertions(+), 18 deletions(-) diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java index 91961c60393..470e6dcac54 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java @@ -9,7 +9,7 @@ public int getFinalCellDischargeVoltage_mV() { @Override public int getForceChargeCellVoltage_mV() { - return 2_800; // 0x2046 Cell under voltage Protection + return 2_850; // 0x2046 Cell under voltage Protection + 50 mV (i.e. x2046 ==> 2800) } @Override diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java index 58363a37f30..b3128010880 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java @@ -16,34 +16,32 @@ public static void setMaxAllowedCurrents(CellCharacteristic cellCharacteristic, if (!areApiValuesPresent(battery)) { maxChargeCurrent = 0; maxDischargeCurrent = 0; - } else { - if (isChargingAlready(battery)) { if (isFurtherChargingNecessary(cellCharacteristic, battery)) { maxDischargeCurrent = calculateForceDischargeCurrent(battery); } + } else { + if (isVoltageBelowFinalDischargingVoltage(cellCharacteristic, battery)) { + if (isVoltageHigherThanForceChargeVoltage(cellCharacteristic, battery)) { + maxDischargeCurrent = 0; + } else { + maxDischargeCurrent = calculateForceDischargeCurrent(battery); + } + } } if (isDischargingAlready(battery)) { if (isFurtherDischargingNecessary(cellCharacteristic, battery)) { maxChargeCurrent = calculateForceChargeCurrent(battery); } - } - - if (isVoltageBelowFinalDischargingVoltage(cellCharacteristic, battery)) { - if (isVoltageHigherThanForceChargeVoltage(cellCharacteristic, battery)) { - maxDischargeCurrent = 0; - } else { - maxDischargeCurrent = calculateForceDischargeCurrent(battery); - } - } - - if (isVoltageAboveFinalChargingVoltage(cellCharacteristic, battery)) { - if (isVoltageLowerThanForceDischargeVoltage(cellCharacteristic, battery)) { - maxChargeCurrent = 0; - } else { - maxChargeCurrent = calculateForceChargeCurrent(battery); + } else { + if (isVoltageAboveFinalChargingVoltage(cellCharacteristic, battery)) { + if (isVoltageLowerThanForceDischargeVoltage(cellCharacteristic, battery)) { + maxChargeCurrent = 0; + } else { + maxChargeCurrent = calculateForceChargeCurrent(battery); + } } } } diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java index 9c19501f68f..889b93d9595 100644 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java +++ b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java @@ -18,6 +18,87 @@ public void setUp() throws Exception { cellCharacteristic = new DummyCellCharacteristic(); } + @Test + public void testBatteryIsChargedUntilFinalDischargeIsReached() { + // Battery has to be charged + int maxDischargeCurrentFromBMS = 0; + int maxChargeCurrentFromBMS = DummyBattery.DEFAULT_MAX_CHARGE_CURRENT; + battery.setMinimalCellVoltage(DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV); + + Util.setMaxAllowedCurrents(cellCharacteristic, maxChargeCurrentFromBMS, maxDischargeCurrentFromBMS, battery); + + battery.getChargeMaxCurrentChannel().nextProcessImage(); + battery.getForceDischargeActiveChannel().nextProcessImage(); + battery.getDischargeMaxCurrentChannel().nextProcessImage(); + battery.getForceChargeActiveChannel().nextProcessImage(); + + int expectedMaxChargeCurrent = maxChargeCurrentFromBMS; + int actualMaxChargeCurrent = battery.getChargeMaxCurrent().get(); + assertEquals(expectedMaxChargeCurrent, actualMaxChargeCurrent); + + int expectedMaxDischargeCurrent = - (int) Math.max(1, battery.getCapacity().get() * 0.02 / battery.getVoltage().get()); + int actualMaxDischargeCurrent = battery.getDischargeMaxCurrent().get(); + assertEquals(expectedMaxDischargeCurrent, actualMaxDischargeCurrent); + + boolean expectedChargeForce = true; + boolean actualChargeForce = battery.getForceChargeActive().get(); + assertEquals(expectedChargeForce, actualChargeForce); + + boolean expectedDischargeForce = false; + boolean actualdischargeForce = battery.getForceDischargeActive().get(); + assertEquals(expectedDischargeForce, actualdischargeForce); + + // Min Voltage has risen above force level, but is still under final discharge level + battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - 1); + Util.setMaxAllowedCurrents(cellCharacteristic, maxChargeCurrentFromBMS, maxDischargeCurrentFromBMS, battery); + + battery.getChargeMaxCurrentChannel().nextProcessImage(); + battery.getForceDischargeActiveChannel().nextProcessImage(); + battery.getDischargeMaxCurrentChannel().nextProcessImage(); + battery.getForceChargeActiveChannel().nextProcessImage(); + + expectedMaxChargeCurrent = maxChargeCurrentFromBMS; + actualMaxChargeCurrent = battery.getChargeMaxCurrent().get(); + assertEquals(expectedMaxChargeCurrent, actualMaxChargeCurrent); + + expectedMaxDischargeCurrent = - (int) Math.max(1, battery.getCapacity().get() * 0.02 / battery.getVoltage().get()); + actualMaxDischargeCurrent = battery.getDischargeMaxCurrent().get(); + assertEquals(expectedMaxDischargeCurrent, actualMaxDischargeCurrent); + + expectedChargeForce = true; + actualChargeForce = battery.getForceChargeActive().get(); + assertEquals(expectedChargeForce, actualChargeForce); + + expectedDischargeForce = false; + actualdischargeForce = battery.getForceDischargeActive().get(); + assertEquals(expectedDischargeForce, actualdischargeForce); + + // Min Voltage has risen above final discharge level + battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV + 1); + Util.setMaxAllowedCurrents(cellCharacteristic, maxChargeCurrentFromBMS, maxDischargeCurrentFromBMS, battery); + + battery.getChargeMaxCurrentChannel().nextProcessImage(); + battery.getForceDischargeActiveChannel().nextProcessImage(); + battery.getDischargeMaxCurrentChannel().nextProcessImage(); + battery.getForceChargeActiveChannel().nextProcessImage(); + + expectedMaxChargeCurrent = maxChargeCurrentFromBMS; + actualMaxChargeCurrent = battery.getChargeMaxCurrent().get(); + assertEquals(expectedMaxChargeCurrent, actualMaxChargeCurrent); + + expectedMaxDischargeCurrent = maxDischargeCurrentFromBMS; + actualMaxDischargeCurrent = battery.getDischargeMaxCurrent().get(); + assertEquals(expectedMaxDischargeCurrent, actualMaxDischargeCurrent); + + expectedChargeForce = false; + actualChargeForce = battery.getForceChargeActive().get(); + assertEquals(expectedChargeForce, actualChargeForce); + + expectedDischargeForce = false; + actualdischargeForce = battery.getForceDischargeActive().get(); + assertEquals(expectedDischargeForce, actualdischargeForce); + } + @Test public void testSetMaxAllowedCurrents() { // Nothing is necessary From 8eda1e7cfd2f8ce2723bcf66d34e83a023201a1e Mon Sep 17 00:00:00 2001 From: Wolfgang Gerbl Date: Tue, 22 Dec 2020 18:15:17 +0100 Subject: [PATCH 14/22] force charge stops at 10 mV to final discharge cell voltage --- .../src/io/openems/edge/battery/soltaro/Util.java | 3 ++- .../test/io/openems/edge/battery/soltaro/UtilTest.java | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java index b3128010880..8a38a03c120 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Util.java @@ -6,6 +6,7 @@ public class Util { public static final double CHARGE_DISCHARGE_FACTOR = 0.02; public static final int MINIMUM_CURRENT = 1; + public static final int TOLERANCE_MV = 10; public static void setMaxAllowedCurrents(CellCharacteristic cellCharacteristic, int maxChargeCurrentFromBMS, int maxDischargeCurrentFromBMS, Battery battery) { @@ -118,7 +119,7 @@ protected static boolean isFurtherChargingNecessary(CellCharacteristic cellChara return false; } return battery.getForceChargeActive().get() - && battery.getMinCellVoltage().get() < cellCharacteristic.getFinalCellDischargeVoltage_mV(); + && battery.getMinCellVoltage().get() < (cellCharacteristic.getFinalCellDischargeVoltage_mV() - TOLERANCE_MV ); } protected static boolean isChargingAlready(Battery battery) { diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java index 889b93d9595..ee5c6c12b21 100644 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java +++ b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/UtilTest.java @@ -48,8 +48,8 @@ public void testBatteryIsChargedUntilFinalDischargeIsReached() { boolean actualdischargeForce = battery.getForceDischargeActive().get(); assertEquals(expectedDischargeForce, actualdischargeForce); - // Min Voltage has risen above force level, but is still under final discharge level - battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - 1); + // Min Voltage has risen above force level, but is still under final discharge level minus tolerance + battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - Util.TOLERANCE_MV - 1); Util.setMaxAllowedCurrents(cellCharacteristic, maxChargeCurrentFromBMS, maxDischargeCurrentFromBMS, battery); battery.getChargeMaxCurrentChannel().nextProcessImage(); @@ -399,10 +399,10 @@ public void testIsFurtherChargingNecessary() { battery.setForceChargeActive(true); assertTrue(Util.isFurtherChargingNecessary(cellCharacteristic, battery)); - battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - 1); + battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - Util.TOLERANCE_MV - 1); assertTrue(Util.isFurtherChargingNecessary(cellCharacteristic, battery)); - battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV); + battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - Util.TOLERANCE_MV); assertFalse(Util.isFurtherChargingNecessary(cellCharacteristic, battery)); } From 0d04e5448f0d5d02ff382b7d28f8cc5e6d0a181b Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sun, 27 Dec 2020 11:34:53 +0100 Subject: [PATCH 15/22] Fix Fenecon Mini State-Machine --- .../fenecon/mini/ess/statemachine/GoReadonlyModeHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoReadonlyModeHandler.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoReadonlyModeHandler.java index c66b7d0780f..9d475d444fb 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoReadonlyModeHandler.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/statemachine/GoReadonlyModeHandler.java @@ -9,8 +9,8 @@ public class GoReadonlyModeHandler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - if (context.component.getSetupMode() == SetupMode.OFF) { - switch (context.component.getPcsMode()) { + if (context.getParent().getSetupMode() == SetupMode.OFF) { + switch (context.getParent().getPcsMode()) { case CONSUMERS_PEAK_PATTERN: case ECO: case ECONOMIC: From 9c9e3779914d77ca69747829ec2e333e8ecdaa8b Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sun, 27 Dec 2020 20:16:59 +0100 Subject: [PATCH 16/22] Soltaro Single B: Downgrade Errors - All Battery-Protocol Errors to Warnings to avoid GenericEss Stop - Disable ALARM_LEVEL_1_SOC_LOW Warning --- .../single/versionb/SingleRackVersionB.java | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionB.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionB.java index fa1dda525c1..bb4238ac6a3 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionB.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionB.java @@ -731,39 +731,39 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .text("Enable/Disable protect soc high")), // PROTECT_FLAG_REGISTER_2_SOC_LOW(Doc.of(OpenemsType.BOOLEAN) // .text("Enable/Disable protect soc low")), // - - //Faults and warnings - ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW(Doc.of(Level.FAULT) // + + // Faults and warnings + ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW(Doc.of(Level.WARNING) // .text("Cell Discharge Temperature Low Alarm Level 2")), // - ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH(Doc.of(Level.WARNING) // .text("Cell Discharge Temperature High Alarm Level 2")), // - ALARM_LEVEL_2_TOTAL_VOLTAGE_DIFFERENCE_HIGH(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_TOTAL_VOLTAGE_DIFFERENCE_HIGH(Doc.of(Level.WARNING) // .text("Total voltage difference too high Alarm Level 2")), // - ALARM_LEVEL_2_INSULATION_LOW(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_INSULATION_LOW(Doc.of(Level.WARNING) // .text("Insulation Low Alarm Level 2")), // - ALARM_LEVEL_2_CELL_VOLTAGE_DIFFERENCE_HIGH(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_CELL_VOLTAGE_DIFFERENCE_HIGH(Doc.of(Level.WARNING) // .text("Cell voltage difference is too high Alarm Level 2")), // - ALARM_LEVEL_2_POLES_TEMPERATURE_DIFFERENCE_HIGH(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_POLES_TEMPERATURE_DIFFERENCE_HIGH(Doc.of(Level.WARNING) // .text("Poles temperature difference is too high Alarm Level 2")), // - ALARM_LEVEL_2_TEMPERATURE_DIFFERENCE_HIGH(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_TEMPERATURE_DIFFERENCE_HIGH(Doc.of(Level.WARNING) // .text("Temperature difference is too high Alarm Level 2")), // - ALARM_LEVEL_2_SOC_LOW(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_SOC_LOW(Doc.of(Level.WARNING) // .text("SoC Low Alarm Level 2")), // - ALARM_LEVEL_2_CELL_CHA_TEMP_LOW(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_CELL_CHA_TEMP_LOW(Doc.of(Level.WARNING) // .text("Cell Charge Temperature Low Alarm Level 2")), // - ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH(Doc.of(Level.WARNING) // .text("Cell Charge Temperature High Alarm Level 2")), // - ALARM_LEVEL_2_DISCHA_CURRENT_HIGH(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_DISCHA_CURRENT_HIGH(Doc.of(Level.WARNING) // .text("Discharge Current High Alarm Level 2")), // - ALARM_LEVEL_2_TOTAL_VOLTAGE_LOW(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_TOTAL_VOLTAGE_LOW(Doc.of(Level.WARNING) // .text("Total Voltage Low Alarm Level 2")), // - ALARM_LEVEL_2_CELL_VOLTAGE_LOW(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_CELL_VOLTAGE_LOW(Doc.of(Level.WARNING) // .text("Cell Voltage Low Alarm Level 2")), // - ALARM_LEVEL_2_CHA_CURRENT_HIGH(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_CHA_CURRENT_HIGH(Doc.of(Level.WARNING) // .text("Charge Current High Alarm Level 2")), // - ALARM_LEVEL_2_TOTAL_VOLTAGE_HIGH(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_TOTAL_VOLTAGE_HIGH(Doc.of(Level.WARNING) // .text("Total Voltage High Alarm Level 2")), // - ALARM_LEVEL_2_CELL_VOLTAGE_HIGH(Doc.of(Level.FAULT) // + ALARM_LEVEL_2_CELL_VOLTAGE_HIGH(Doc.of(Level.WARNING) // .text("Cell Voltage High Alarm Level 2")), // ALARM_LEVEL_1_CELL_DISCHA_TEMP_LOW(Doc.of(Level.WARNING) // .text("Cell Discharge Temperature Low Alarm Level 1")), // @@ -779,7 +779,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .text("Pole temperature too high Alarm Level 1")), // ALARM_LEVEL_1_CELL_TEMP_DIFF_HIGH(Doc.of(Level.WARNING) // .text("Cell temperature Diff High Alarm Level 1")), // - ALARM_LEVEL_1_SOC_LOW(Doc.of(Level.WARNING) // + ALARM_LEVEL_1_SOC_LOW(Doc.of(OpenemsType.BOOLEAN) // .text("SOC Low Alarm Level 1")), // ALARM_LEVEL_1_CELL_CHA_TEMP_LOW(Doc.of(Level.WARNING) // .text("Cell Charge Temperature Low Alarm Level 1")), // @@ -838,35 +838,35 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .text("Slave 19 communication error")), // SLAVE_20_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Slave 20 communication error")), // - FAILURE_INITIALIZATION(Doc.of(Level.FAULT) // + FAILURE_INITIALIZATION(Doc.of(Level.WARNING) // .text("Initialization failure")), // - FAILURE_EEPROM(Doc.of(Level.FAULT) // + FAILURE_EEPROM(Doc.of(Level.WARNING) // .text("EEPROM fault")), // - FAILURE_INTRANET_COMMUNICATION(Doc.of(Level.FAULT) // + FAILURE_INTRANET_COMMUNICATION(Doc.of(Level.WARNING) // .text("Intranet communication fault")), // - FAILURE_TEMP_SAMPLING_LINE(Doc.of(Level.FAULT) // + FAILURE_TEMP_SAMPLING_LINE(Doc.of(Level.WARNING) // .text("Temperature sampling line fault")), // FAILURE_BALANCING_MODULE(Doc.of(Level.OK) // .text("Balancing module fault")), // - FAILURE_PCB(Doc.of(Level.FAULT) // + FAILURE_PCB(Doc.of(Level.WARNING) // .text("PCB error")), // - FAILURE_GR_T(Doc.of(Level.FAULT) // + FAILURE_GR_T(Doc.of(Level.WARNING) // .text("GR T error")), // - FAILURE_TEMP_SENSOR(Doc.of(Level.FAULT) // + FAILURE_TEMP_SENSOR(Doc.of(Level.WARNING) // .text("Temperature sensor fault")), // - FAILURE_TEMP_SAMPLING(Doc.of(Level.FAULT) // + FAILURE_TEMP_SAMPLING(Doc.of(Level.WARNING) // .text("Temperature sampling fault")), // - FAILURE_VOLTAGE_SAMPLING(Doc.of(Level.FAULT) // + FAILURE_VOLTAGE_SAMPLING(Doc.of(Level.WARNING) // .text("Voltage sampling fault")), // - FAILURE_LTC6803(Doc.of(Level.FAULT) // + FAILURE_LTC6803(Doc.of(Level.WARNING) // .text("LTC6803 fault")), // - FAILURE_CONNECTOR_WIRE(Doc.of(Level.FAULT) // + FAILURE_CONNECTOR_WIRE(Doc.of(Level.WARNING) // .text("connector wire fault")), // - FAILURE_SAMPLING_WIRE(Doc.of(Level.FAULT) // + FAILURE_SAMPLING_WIRE(Doc.of(Level.WARNING) // .text("sampling wire fault")), // - PRECHARGE_TAKING_TOO_LONG(Doc.of(Level.FAULT) // + PRECHARGE_TAKING_TOO_LONG(Doc.of(Level.WARNING) // .text("precharge time was too long")), - + // OpenEMS Faults RUN_FAILED(Doc.of(Level.FAULT) // .text("Running the Logic failed")), // @@ -874,7 +874,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .text("The maximum number of start attempts failed")), // MAX_STOP_ATTEMPTS(Doc.of(Level.FAULT) // .text("The maximum number of stop attempts failed")), // - + ; private final Doc doc; From c5ac1e882edc655481aa3026a4647b15dda25598 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sun, 27 Dec 2020 20:18:39 +0100 Subject: [PATCH 17/22] Improve ESS Sinexcel Battery-Handling - Apply startup ramp for Allowed Charge/Discharge Power - Fix handling of negative values for Current [A] limits; i.e. on force charge/discharge --- .../edge/ess/sinexcel/EssSinexcelImpl.java | 106 ++++++++++++------ 1 file changed, 71 insertions(+), 35 deletions(-) diff --git a/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcelImpl.java b/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcelImpl.java index 79698c94192..c9c7a9f7f2c 100644 --- a/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcelImpl.java +++ b/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcelImpl.java @@ -156,56 +156,92 @@ public EssSinexcelImpl() throws OpenemsNamedException { // this.numberOfSlaves = (int) bms.getComponentContext().getProperties().get("numberOfSlaves"); // } + private final static int MAX_CURRENT = 90; // [A] + + private float lastAllowedChargePower = 0; + private float lastAllowedDischargePower = 0; + /** * Sets the Battery Ranges. Executed on TOPIC_CYCLE_AFTER_PROCESS_IMAGE. * * @throws OpenemsNamedException */ private void setBatteryRanges() throws OpenemsNamedException { + final float efficiencyFactor = 0.95F; + final int disMaxA; + final int chaMaxA; + final int disMinV; + final int chaMaxV; + final int voltage; + + // Evaluate input data if (battery == null) { - return; - } - - int disMaxA = battery.getDischargeMaxCurrent().orElse(0); - int chaMaxA = battery.getChargeMaxCurrent().orElse(0); - int disMinV = battery.getDischargeMinVoltage().orElse(0); - int chaMaxV = battery.getChargeMaxVoltage().orElse(0); - - // Sinexcel range for Max charge/discharge current is 0A to 90A, - if (chaMaxA > 90) { - { - IntegerWriteChannel setChaMaxA = this.channel(EssSinexcel.ChannelId.CHARGE_MAX_A); - setChaMaxA.setNextWriteValue(900); - } + disMaxA = 0; + chaMaxA = 0; + disMinV = 0; + chaMaxV = 0; + voltage = 0; } else { - { - IntegerWriteChannel setChaMaxA = this.channel(EssSinexcel.ChannelId.CHARGE_MAX_A); - setChaMaxA.setNextWriteValue(chaMaxA * 10); - } + disMaxA = battery.getDischargeMaxCurrent().orElse(0); + chaMaxA = battery.getChargeMaxCurrent().orElse(0); + disMinV = battery.getDischargeMinVoltage().orElse(0); + chaMaxV = battery.getChargeMaxVoltage().orElse(0); + voltage = battery.getVoltage().orElse(0); } - if (disMaxA > 90) { - { - IntegerWriteChannel setDisMaxA = this.channel(EssSinexcel.ChannelId.DISCHARGE_MAX_A); - setDisMaxA.setNextWriteValue(900); - } - } else { - { - IntegerWriteChannel setDisMaxA = this.channel(EssSinexcel.ChannelId.DISCHARGE_MAX_A); - setDisMaxA.setNextWriteValue(disMaxA * 10); - } + // Set Inverter Registers + { + IntegerWriteChannel chargeMaxCurrentChannel = this.channel(EssSinexcel.ChannelId.CHARGE_MAX_A); + chargeMaxCurrentChannel.setNextWriteValue(// + /* enforce positive */ Math.max(0, // + /* apply max current */ Math.min(MAX_CURRENT, chaMaxA) // + ) * 10); } { - IntegerWriteChannel setDisMinV = this.channel(EssSinexcel.ChannelId.DISCHARGE_MIN_V); - setDisMinV.setNextWriteValue(disMinV * 10); + IntegerWriteChannel dischargeMaxCurrentChannel = this.channel(EssSinexcel.ChannelId.DISCHARGE_MAX_A); + dischargeMaxCurrentChannel.setNextWriteValue(// + /* enforce positive */ Math.max(0, // + /* apply max current */ Math.min(MAX_CURRENT, disMaxA) // + ) * 10); } { - IntegerWriteChannel setChaMaxV = this.channel(EssSinexcel.ChannelId.CHARGE_MAX_V); - setChaMaxV.setNextWriteValue(chaMaxV * 10); + IntegerWriteChannel dischargeMinVoltageChannel = this.channel(EssSinexcel.ChannelId.DISCHARGE_MIN_V); + dischargeMinVoltageChannel.setNextWriteValue(disMinV * 10); } - final double EFFICIENCY_FACTOR = 0.9; - this._setAllowedChargePower((int) (chaMaxA * chaMaxV * -1 * EFFICIENCY_FACTOR)); - this._setAllowedDischargePower((int) (disMaxA * disMinV * EFFICIENCY_FACTOR)); + { + IntegerWriteChannel chargeMaxVoltageChannel = this.channel(EssSinexcel.ChannelId.CHARGE_MAX_V); + chargeMaxVoltageChannel.setNextWriteValue(chaMaxV * 10); + } + + // Calculate AllowedCharge- and -DischargePower + float allowedChargePower; + float allowedDischargePower; + + // efficiency factor is not considered in chargeMaxCurrent (DC Power > AC Power) + allowedChargePower = chaMaxA * voltage * -1; + allowedDischargePower = disMaxA * voltage * efficiencyFactor; + + // Allow max increase of 1 % + if (allowedDischargePower > lastAllowedDischargePower + allowedDischargePower * 0.01F) { + allowedDischargePower = lastAllowedDischargePower + allowedDischargePower * 0.01F; + } + this.lastAllowedDischargePower = allowedDischargePower; + + if (allowedChargePower < lastAllowedChargePower + allowedChargePower * 0.01F) { + allowedChargePower = lastAllowedChargePower + allowedChargePower * 0.01F; + } + this.lastAllowedChargePower = allowedChargePower; + + // Make sure solution is feasible + if (allowedChargePower > allowedDischargePower) { // Force Discharge + allowedDischargePower = allowedChargePower; + } + if (allowedDischargePower < allowedChargePower) { // Force Charge + allowedChargePower = allowedDischargePower; + } + + this._setAllowedChargePower(Math.round(allowedChargePower)); + this._setAllowedDischargePower(Math.round(allowedDischargePower)); } /** From 3576a93d034b884a52783a6d59968869289b7c5e Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sun, 27 Dec 2020 20:19:01 +0100 Subject: [PATCH 18/22] Generic-ESS: change execution order to avoid race condition --- .../ess/generic/symmetric/ChannelManager.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java index 4a9e72c8582..a97b7e5164b 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/ChannelManager.java @@ -62,14 +62,6 @@ public void activate(Battery battery, ManagedSymmetricBatteryInverter batteryInv allowedDischargePower = 0; } - // Make sure solution is feasible - if (allowedChargePower > allowedDischargePower) { // Force Discharge - allowedDischargePower = allowedChargePower; - } - if (allowedDischargePower < allowedChargePower) { // Force Charge - allowedChargePower = allowedDischargePower; - } - // Allow max increase of 1 % if (allowedDischargePower > lastAllowedDischargePower + allowedDischargePower * 0.01F) { allowedDischargePower = lastAllowedDischargePower + allowedDischargePower * 0.01F; @@ -81,6 +73,14 @@ public void activate(Battery battery, ManagedSymmetricBatteryInverter batteryInv } ChannelManager.this.lastAllowedChargePower = allowedChargePower; + // Make sure solution is feasible + if (allowedChargePower > allowedDischargePower) { // Force Discharge + allowedDischargePower = allowedChargePower; + } + if (allowedDischargePower < allowedChargePower) { // Force Charge + allowedChargePower = allowedDischargePower; + } + this.parent._setAllowedChargePower(Math.round(allowedChargePower)); this.parent._setAllowedDischargePower(Math.round(allowedDischargePower)); }; From 220dbc9bae492ae026035a1c296514d3f6f93e09 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sun, 27 Dec 2020 20:26:48 +0100 Subject: [PATCH 19/22] Soltaro Single B: improve debuglog --- .../battery/soltaro/single/versionb/SingleRackVersionBImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java index 32bee65a6e4..e64b7806e38 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/SingleRackVersionBImpl.java @@ -247,7 +247,7 @@ public String debugLog() { return "SoC:" + this.getSoc() // + "|Discharge:" + this.getDischargeMinVoltage() + ";" + this.getDischargeMaxCurrent() // + "|Charge:" + this.getChargeMaxVoltage() + ";" + this.getChargeMaxCurrent() // - + "|State:" + this.stateMachine.getCurrentState(); + + "|State:" + this.stateMachine.getCurrentState().asCamelCase(); } /* From 5ee794abc9a14b692255b41b5f57464bb590017c Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sun, 27 Dec 2020 20:28:05 +0100 Subject: [PATCH 20/22] ESS SInexcel: identify state as "Automatic Standby-Mode" --- .../src/io/openems/edge/ess/sinexcel/EssSinexcel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcel.java b/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcel.java index fb07a302823..35047debbb8 100644 --- a/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcel.java +++ b/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcel.java @@ -193,8 +193,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .text("Grid shutdown")), // STATE_5(Doc.of(Level.WARNING) // .text("Cabinet open")), // - STATE_6(Doc.of(Level.WARNING) // - .text("Manual shutdown")), // + STATE_6(Doc.of(Level.INFO) // + .text("Automatic Standby-Mode")), // STATE_7(Doc.of(Level.WARNING) // .text("Over temperature")), // STATE_8(Doc.of(Level.WARNING) // From 7e3c8158df630214f311aa1ace9717de0efed3be Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sun, 27 Dec 2020 20:30:37 +0100 Subject: [PATCH 21/22] ESS Sinexcel: identify state as "Automatic Standby-Mode" --- .../src/io/openems/edge/ess/sinexcel/EssSinexcel.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcel.java b/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcel.java index 35047debbb8..57b18adea9f 100644 --- a/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcel.java +++ b/io.openems.edge.ess.sinexcel/src/io/openems/edge/ess/sinexcel/EssSinexcel.java @@ -193,6 +193,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .text("Grid shutdown")), // STATE_5(Doc.of(Level.WARNING) // .text("Cabinet open")), // + // Automatic Standby-Mode is activated after giving a active-power setpoint of + // zero for a while. STATE_6(Doc.of(Level.INFO) // .text("Automatic Standby-Mode")), // STATE_7(Doc.of(Level.WARNING) // From 087ca81250e36462e5c27b2c833f18e62baacc91 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 11 Jan 2021 16:18:11 +0100 Subject: [PATCH 22/22] Code cleanup --- .../battery/bydcommercial/statemachine/ErrorHandler.java | 7 +++++-- .../bydcommercial/statemachine/GoRunningHandler.java | 8 +++++--- .../bydcommercial/statemachine/GoStoppedHandler.java | 8 +++++--- .../bydcommercial/statemachine/RunningHandler.java | 9 ++++++--- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java index 13813fe5630..5ca1c5ff3ce 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/ErrorHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.bydcommercial.BatteryBoxC130; import io.openems.edge.battery.bydcommercial.enums.PowerCircuitControl; import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -22,8 +23,10 @@ protected void onEntry(Context context) throws OpenemsNamedException { @Override protected void onExit(Context context) throws OpenemsNamedException { - context.getParent()._setMaxStartAttempts(false); - context.getParent()._setMaxStopAttempts(false); + BatteryBoxC130 battery = context.getParent(); + + battery._setMaxStartAttempts(false); + battery._setMaxStopAttempts(false); } @Override diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoRunningHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoRunningHandler.java index 76158f4322e..336f9e80e8c 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoRunningHandler.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoRunningHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.bydcommercial.BatteryBoxC130; import io.openems.edge.battery.bydcommercial.enums.PowerCircuitControl; import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State; import io.openems.edge.battery.bydcommercial.utils.Constants; @@ -23,7 +24,8 @@ protected void onEntry(Context context) throws OpenemsNamedException { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - PowerCircuitControl preChargeControl = context.getParent().getPowerCircuitControl(); + BatteryBoxC130 battery = context.getParent(); + PowerCircuitControl preChargeControl = battery.getPowerCircuitControl(); if (preChargeControl == PowerCircuitControl.SWITCH_ON) { return State.RUNNING; @@ -36,12 +38,12 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > Constants.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.getParent()._setMaxStartAttempts(true); + battery._setMaxStartAttempts(true); return State.UNDEFINED; } else { // Trying to switch on - context.getParent().setPowerCircuitControl(PowerCircuitControl.PRE_CHARGING_1); + battery.setPowerCircuitControl(PowerCircuitControl.PRE_CHARGING_1); this.lastAttempt = Instant.now(); this.attemptCounter++; return State.GO_RUNNING; diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoStoppedHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoStoppedHandler.java index b860d7053d8..1a01fe2f8ac 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoStoppedHandler.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/GoStoppedHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.battery.bydcommercial.BatteryBoxC130; import io.openems.edge.battery.bydcommercial.enums.PowerCircuitControl; import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State; import io.openems.edge.battery.bydcommercial.utils.Constants; @@ -22,7 +23,8 @@ protected void onEntry(Context context) { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - PowerCircuitControl powerCircuitControl = context.getParent().getPowerCircuitControl(); + BatteryBoxC130 battery = context.getParent(); + PowerCircuitControl powerCircuitControl = battery.getPowerCircuitControl(); if (powerCircuitControl == PowerCircuitControl.SWITCH_OFF) { return State.STOPPED; @@ -35,12 +37,12 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { if (this.attemptCounter > Constants.RETRY_COMMAND_MAX_ATTEMPTS) { // Too many tries - context.getParent()._setMaxStopAttempts(true); + battery._setMaxStopAttempts(true); return State.UNDEFINED; } else { // Trying to switch off - context.getParent().setPowerCircuitControl(PowerCircuitControl.SWITCH_OFF); + battery.setPowerCircuitControl(PowerCircuitControl.SWITCH_OFF); this.lastAttempt = Instant.now(); this.attemptCounter++; return State.GO_STOPPED; diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/RunningHandler.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/RunningHandler.java index 45b8b2b12b5..5f0611fcb52 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/RunningHandler.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/statemachine/RunningHandler.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.bydcommercial.statemachine; +import io.openems.edge.battery.bydcommercial.BatteryBoxC130; import io.openems.edge.battery.bydcommercial.enums.PowerCircuitControl; import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State; import io.openems.edge.common.startstop.StartStop; @@ -9,16 +10,18 @@ public class RunningHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - if (context.getParent().hasFaults()) { + BatteryBoxC130 battery = context.getParent(); + + if (battery.hasFaults()) { return State.UNDEFINED; } - if (context.getParent().getPowerCircuitControl() != PowerCircuitControl.SWITCH_ON) { + if (battery.getPowerCircuitControl() != PowerCircuitControl.SWITCH_ON) { return State.UNDEFINED; } // Mark as started - context.getParent()._setStartStop(StartStop.START); + battery._setStartStop(StartStop.START); return State.RUNNING; }