Skip to content

Commit

Permalink
FEMS Backports 2024.3.0 (#2560)
Browse files Browse the repository at this point in the history
-  GoodWe Grid-Meter: add support for "Commercial Meter 
- Sum: improvements to max-ever-values
  - Calculate min/max ever ESS discharge power (will eventually replace MaxApparentPower in UI Live)
    - add EssMinDischargePower and EssMaxDischargePower channels to _sum
    - calculate _sum/EssDischargePower also from non-hybrid ESS
  - improve parsing of _sum config: parse String values to int
  - Prediction: fix possible NoSuchElementException if all predictions are empty
-  AppCenter: App for EZA-Regler 
- Implement generic LinuxFs GPIO (for Modberry) 
- CI: Update scripts
- AppCenter: Home 20 & 30 added modbus for external meters
- AppCenter: ToU only compatibility with Home 10, 20 or 30 _(this shows compatibility restrictions in AppCenter; for proprietary distributions of OpenEMS change this accordingly)_
- Implement system SOFT/HARD restart (Edge JsonRPC) 
  - Add JSON-RPC handler for system restart (`ExecuteSystemRestart`)
    - HARD: reboot system
    - SOFT: restart OpenEMS service
  - Extract handling of system commands to common `SystemRecord` record
- UI: change "Installateurszugang anlegen" to "Account anlegen" 
- UI: Refactoring of translations 
- AppCenter: fix AlpitronicEvcs wrong scheduler factory id
- GoodWe 20 & 30: handle Voltage & Current for DSP version
- UI: chartjs-migration
- UI: Fix Time-of-use bugs 
- AppCenter: refactor pvInverter apps to use "new" props
  - Refactored PV-Inverter Apps to use "new" Props
  - Added selection of Phase to SolarEdge App
  - Changed description text of tibber token
- RRD4j/Backend-Api: avoid exception during deactivate 
  - Fix bug in ControllerApiBackend or TimedataRrd4jImpl which required a restart.
  - Fixes #2545

---------

Co-authored-by: Michael Grill <[email protected]>
Co-authored-by: Sebastian Asen <[email protected]>
Co-authored-by: Lorant Meszlenyi <[email protected]>
Co-authored-by: Hueseyin Sahutoglu <[email protected]>
Co-authored-by: Stefan Feilmeier <[email protected]>
Co-authored-by: Kai Jeschek <[email protected]>
Co-authored-by: Lukas Rieger <[email protected]>
Co-authored-by: Sagar Venu <[email protected]>
  • Loading branch information
9 people authored Mar 3, 2024
1 parent eb5fdaf commit 5dcf38b
Show file tree
Hide file tree
Showing 192 changed files with 15,347 additions and 4,056 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public SystemUpdateParams getSystemUpdateParams() {
.put("App.PeakShaving.PeakShaving", "") //
.put("App.PeakShaving.PhaseAccuratePeakShaving", "") //
.put("App.Ess.FixActivePower", "") //
.put("App.Ess.PowerPlantController", "") //
.put("App.Ess.PrepareBatteryExtension", "") //
.build();

Expand Down
24 changes: 24 additions & 0 deletions io.openems.common/src/io/openems/common/utils/EnumUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,30 @@

public class EnumUtils {

/**
* Gets the Enum instance from the given value.
*
* <p>
* This is a null-safe wrapper around {@link Enum#valueOf(Class, String)}.
*
* @param <ENUM> the type
* @param enumType the class of the {@link Enum}
* @param name the name of the constant to return
* @return the enum constant of the specified enum class with the specified
* name; null if there is no matching Enum constant
*/
public static <ENUM extends Enum<ENUM>> ENUM toEnum(Class<ENUM> enumType, String name) {
if (name == null || name.isBlank()) {
return null;
}
try {
return Enum.valueOf(enumType, name.toUpperCase());
} catch (IllegalArgumentException e) {
// handled below
}
return null;
}

/**
* Converts the Enum {@link CaseFormat#UPPER_UNDERSCORE} name to
* {@link CaseFormat#UPPER_CAMEL}-case.
Expand Down
14 changes: 2 additions & 12 deletions io.openems.common/src/io/openems/common/utils/JsonUtils.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.openems.common.utils;

import static io.openems.common.utils.EnumUtils.toEnum;

import java.net.Inet4Address;
import java.time.ZoneId;
import java.time.ZonedDateTime;
Expand Down Expand Up @@ -2073,18 +2075,6 @@ private static String toString(JsonPrimitive jPrimitive) {
return null;
}

private static <E extends Enum<E>> E toEnum(Class<E> enumType, String name) {
if (name == null || name.isBlank()) {
return null;
}
try {
return Enum.valueOf(enumType, name.toUpperCase());
} catch (IllegalArgumentException e) {
// handled below
}
return null;
}

// CHECKSTYLE:OFF
private static UUID toUUID(String value) {
// CHECKSTYLE:ON
Expand Down
2 changes: 2 additions & 0 deletions io.openems.edge.application/EdgeApp.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
bnd.identity;id='io.openems.edge.fenecon.pro',\
bnd.identity;id='io.openems.edge.goodwe',\
bnd.identity;id='io.openems.edge.io.filipowski',\
bnd.identity;id='io.openems.edge.io.gpio',\
bnd.identity;id='io.openems.edge.io.kmtronic',\
bnd.identity;id='io.openems.edge.io.offgridswitch',\
bnd.identity;id='io.openems.edge.io.revpi',\
Expand Down Expand Up @@ -299,6 +300,7 @@
io.openems.edge.goodwe;version=snapshot,\
io.openems.edge.io.api;version=snapshot,\
io.openems.edge.io.filipowski;version=snapshot,\
io.openems.edge.io.gpio;version=snapshot,\
io.openems.edge.io.kmtronic;version=snapshot,\
io.openems.edge.io.offgridswitch;version=snapshot,\
io.openems.edge.io.revpi;version=snapshot,\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
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.component.annotations.ReferenceScope;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.osgi.service.event.propertytypes.EventTopics;
Expand Down Expand Up @@ -78,7 +77,8 @@ public class ControllerApiBackendImpl extends AbstractOpenemsComponent
@Reference
private OpenemsEdgeOem oem;

@Reference(scope = ReferenceScope.PROTOTYPE_REQUIRED)
@Reference
private ResendHistoricDataWorkerFactory resendHistoricDataWorkerFactory;
protected ResendHistoricDataWorker resendHistoricDataWorker;

@Reference
Expand Down Expand Up @@ -150,6 +150,7 @@ private void activate(ComponentContext context, Config config) {
this.websocket = new WebsocketClient(this, name, uri, httpHeaders, proxy);
this.websocket.start();

this.resendHistoricDataWorker = this.resendHistoricDataWorkerFactory.get();
this.resendHistoricDataWorker.setConfig(new ResendHistoricDataWorker.Config(//
this.getUnableToSendChannel().address(), //
this.getLastSuccessFulResendChannel().address(), //
Expand All @@ -164,6 +165,8 @@ private void activate(ComponentContext context, Config config) {
@Deactivate
protected void deactivate() {
super.deactivate();
this.resendHistoricDataWorkerFactory.unget(this.resendHistoricDataWorker);
this.resendHistoricDataWorker = null;
this.sendChannelValuesWorker.deactivate();
if (this.websocket != null) {
this.websocket.stop();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.openems.edge.controller.api.backend;

import org.osgi.service.component.ComponentServiceObjects;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

@Component(service = ResendHistoricDataWorkerFactory.class)
public class ResendHistoricDataWorkerFactory {

@Reference
private ComponentServiceObjects<ResendHistoricDataWorker> cso;

/**
* Returns a new {@link ResendHistoricDataWorker} service object.
*
* @return the created {@link ResendHistoricDataWorker} object
* @see #unget(ResendHistoricDataWorker)
*/
public ResendHistoricDataWorker get() {
return this.cso.getService();
}

/**
* Releases the {@link ResendHistoricDataWorker} service object.
*
* @param service a {@link ResendHistoricDataWorker} provided by this factory
* @see #get()
*/
public void unget(ResendHistoricDataWorker service) {
if (service == null) {
return;
}
this.cso.ungetService(service);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void test() throws Exception {
new ComponentTest(sut) //
.addReference("componentManager", new DummyComponentManager(clock)) //
.addReference("cycle", new DummyCycle(1000)) //
.addReference("resendHistoricDataWorker", new ResendHistoricDataWorker()) //
.addReference("resendHistoricDataWorkerFactory", new DummyResendHistoricDataWorkerFactory()) //
.addReference("oem", new DummyOpenemsEdgeOem()) //
.addComponent(new DummySum()) //
.activate(MyConfig.create() //
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.openems.edge.controller.api.backend;

import java.lang.reflect.InvocationTargetException;

import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentServiceObjects;

import io.openems.common.utils.ReflectionUtils;

public class DummyResendHistoricDataWorkerFactory extends ResendHistoricDataWorkerFactory {

public DummyResendHistoricDataWorkerFactory()
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
super();
ReflectionUtils.setAttribute(ResendHistoricDataWorkerFactory.class, this, "cso",
new DummyResendHistoricDataWorkerCso());
}

private static class DummyResendHistoricDataWorkerCso implements ComponentServiceObjects<ResendHistoricDataWorker> {

@Override
public ResendHistoricDataWorker getService() {
return new ResendHistoricDataWorker();
}

@Override
public void ungetService(ResendHistoricDataWorker service) {
// empty for tests
}

@Override
public ServiceReference<ResendHistoricDataWorker> getServiceReference() {
// empty for tests
return null;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ protected ThrowingTriFunction<ConfigurationTarget, Map<Property, JsonElement>, L
new EdgeConfig.Component(controllerId, this.getName(l), "Controller.Api.ModbusTcp.ReadOnly",
JsonUtils.buildJsonObject() //
.add("component.ids", componentIds) //
.addProperty("port", 502) //
.build()));

return AppConfiguration.create() //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter;
import io.openems.edge.core.appmanager.dependency.DependencyDeclaration;
import io.openems.edge.core.appmanager.dependency.Tasks;
import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent;
import io.openems.edge.core.appmanager.formly.JsonFormlyUtil;

/**
Expand Down Expand Up @@ -164,15 +165,9 @@ protected ThrowingTriFunction<ConfigurationTarget, Map<Property, JsonElement>, L
new EdgeConfig.Component(controllerId, this.getName(l), "Controller.Api.ModbusTcp.ReadWrite",
JsonUtils.buildJsonObject() //
.addProperty("apiTimeout", apiTimeout) //
.add("component.ids", controllerIds).build()) //
);

final var schedulerIds = Lists.newArrayList(//
"ctrlEmergencyCapacityReserve0", //
controllerId, //
"ctrlGridOptimizedCharge0", //
"ctrlEssSurplusFeedToGrid0", //
"ctrlBalancing0" //
.add("component.ids", controllerIds) //
.addProperty("port", 502) //
.build()) //
);

final var dependencies = Lists.newArrayList(//
Expand All @@ -193,7 +188,9 @@ protected ThrowingTriFunction<ConfigurationTarget, Map<Property, JsonElement>, L

return AppConfiguration.create() //
.addTask(Tasks.component(components)) //
.addTask(Tasks.scheduler(schedulerIds)) //
.addTask(Tasks.schedulerByCentralOrder(//
new SchedulerComponent(controllerId, "Controller.Api.ModbusTcp.ReadWrite",
this.getAppId()))) //
.addDependencies(dependencies) //
.build();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import io.openems.edge.core.appmanager.TranslationUtil;
import io.openems.edge.core.appmanager.dependency.DependencyDeclaration;
import io.openems.edge.core.appmanager.dependency.Tasks;
import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent;
import io.openems.edge.core.appmanager.formly.JsonFormlyUtil;

/**
Expand Down Expand Up @@ -128,14 +129,6 @@ protected ThrowingTriFunction<ConfigurationTarget, EnumMap<Property, JsonElement
.build()) //
);

final var schedulerIds = Lists.newArrayList(//
"ctrlEmergencyCapacityReserve0", //
controllerId, //
"ctrlGridOptimizedCharge0", //
"ctrlEssSurplusFeedToGrid0", //
"ctrlBalancing0" //
);

var dependencies = Lists.newArrayList(//
new DependencyDeclaration("READ_ONLY", //
DependencyDeclaration.CreatePolicy.NEVER, //
Expand All @@ -154,7 +147,8 @@ protected ThrowingTriFunction<ConfigurationTarget, EnumMap<Property, JsonElement

return AppConfiguration.create() //
.addTask(Tasks.component(components)) //
.addTask(Tasks.scheduler(schedulerIds)) //
.addTask(Tasks.schedulerByCentralOrder(//
new SchedulerComponent(controllerId, "Controller.Api.Rest.ReadWrite", this.getAppId()))) //
.addDependencies(dependencies) //
.build();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,13 @@ AppDef<APP, Nameable, BundleProvider> pickModbusId(//
.setTranslatedDescription("communication.modbusId.description");
final var oldDefaultValue = def.getDefaultValue();
def.setDefaultValue((app, property, l, parameter) -> {
if (PropsUtil.isHomeInstalled(app.getAppManagerUtil())) {
// TODO should be configured in oem bundle
if (PropsUtil.isHome10Installed(app.getAppManagerUtil())) {
return new JsonPrimitive("modbus1");
}
if (PropsUtil.isHome20Or30Installed(app.getAppManagerUtil())) {
return new JsonPrimitive("modbus2");
}

return oldDefaultValue.get(app, property, l, parameter);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.openems.edge.app.common.props;

import io.openems.edge.app.integratedsystem.FeneconHome;
import io.openems.edge.app.integratedsystem.FeneconHome20;
import io.openems.edge.app.integratedsystem.FeneconHome30;
import io.openems.edge.core.appmanager.AppManagerUtil;

public final class PropsUtil {
Expand All @@ -9,7 +11,8 @@ private PropsUtil() {
}

/**
* Checks if a {@link FeneconHome} is installed.
* Checks if a {@link FeneconHome}, {@link FeneconHome20} or
* {@link FeneconHome30} is installed.
*
* @param util the {@link AppManagerUtil} to get the installed instances
* @return true if a {@link FeneconHome} is installed otherwise false
Expand All @@ -22,4 +25,29 @@ public static boolean isHomeInstalled(AppManagerUtil util) {
).isEmpty();
}

/**
* Checks if a {@link FeneconHome} is installed.
*
* @param util the {@link AppManagerUtil} to get the installed instances
* @return true if a {@link FeneconHome} is installed otherwise false
*/
public static boolean isHome10Installed(AppManagerUtil util) {
return !util.getInstantiatedAppsOf(//
"App.FENECON.Home" //
).isEmpty();
}

/**
* Checks if a {@link FeneconHome20} or {@link FeneconHome30} is installed.
*
* @param util the {@link AppManagerUtil} to get the installed instances
* @return true if a {@link FeneconHome} is installed otherwise false
*/
public static boolean isHome20Or30Installed(AppManagerUtil util) {
return !util.getInstantiatedAppsOf(//
"App.FENECON.Home.20", //
"App.FENECON.Home.30" //
).isEmpty();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import io.openems.edge.core.appmanager.Type.Parameter;
import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter;
import io.openems.edge.core.appmanager.dependency.Tasks;
import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent;

/**
* Describes a fix active power app.
Expand Down Expand Up @@ -144,16 +145,11 @@ protected ThrowingTriFunction<ConfigurationTarget, Map<Property, JsonElement>, L
.build()) //
);

// TODO improve scheduler configuration
final var schedulerIds = Lists.newArrayList(//
ctrlFixActivePowerId, //
"ctrlPrepareBatteryExtension0", //
"ctrlEmergencyCapacityReserve0", //
"ctrlGridOptimizedCharge0" //
);
return AppConfiguration.create() //
.addTask(Tasks.component(components)) //
.addTask(Tasks.scheduler(schedulerIds)) //
.addTask(Tasks.schedulerByCentralOrder(//
new SchedulerComponent(ctrlFixActivePowerId, "Controller.Ess.FixActivePower",
this.getAppId()))) //
.build();
};
}
Expand Down
Loading

0 comments on commit 5dcf38b

Please sign in to comment.